Specifying local and external block parameters (that old chestnut)
Author |
Message |
Gavin Sinclai #1 / 49
|
 Specifying local and external block parameters (that old chestnut)
I've {*filter*}ised discussion from the "Bugs" thread. I hope it is a service to the community to reopen this. The poll on RubyGarden votes "make 'em all local", closely followed by "leave it unchanged". Yet the "problem" keeps coming up, and the most sensible solution (in my mind) is not represented in the poll. I think it makes sense to explicitly mark *external* variables, as block-local variables (parameters, in fact) would be the norm. Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable, then one could write collection.each do |a,:b,c| ... end or collection.each do |a,b,c| external b ... end I'm not sure which of the above I prefer. One should optimise for the common case. I'd like to put a question to the audience :) Does anyone actually have a need to use non-local block parameters? Ever? Apologies if this can of worms is better left buried. Cheers, Gavin -- Gavin Sinclair Software Engineer Sydney, Australia Soyabean Software Pty Ltd
|
Tue, 22 Mar 2005 09:58:07 GMT |
|
 |
Alan Che #2 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> I've {*filter*}ised discussion from the "Bugs" thread. I hope it is a service to > the community to reopen this. The poll on RubyGarden votes "make 'em all > local", closely followed by "leave it unchanged". Yet the "problem" keeps > coming up, and the most sensible solution (in my mind) is not represented in > the poll. > I think it makes sense to explicitly mark *external* variables, as block-local > variables (parameters, in fact) would be the norm. > Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable, > then one could write > collection.each do |a,:b,c| > ... > end > or > collection.each do |a,b,c| > external b > ... > end > I'm not sure which of the above I prefer. One should optimise for the common > case. > I'd like to put a question to the audience :) Does anyone actually have a need > to use non-local block parameters? Ever?
I've asked this before but can't recall any answers. How would one do the following without non-local block params: a = [1.1, 3.14, 2.7, 5.15] sum = 0.0 a.each { |elem| sum += a } Personally, I like accessing external scope by default. C behaves similiarly: #include <stdio.h> int main() { int a = 42; int b = 55; printf("a: %d b: %d\n", a, b ); { int a = 33; /* define a as local scope to this block*/ printf("a: %d b: %d\n", a, b ); } Quote: }
Gives you a: 42 b: 55 a: 33 b: 55 -- Alan Chen Digikata LLC http://www.*-*-*.com/
|
Tue, 22 Mar 2005 10:19:17 GMT |
|
 |
Yukihiro Matsumo #3 / 49
|
 Specifying local and external block parameters (that old chestnut)
Hi, In message "Specifying local and external block parameters (that old chestnut)"
|I've {*filter*}ised discussion from the "Bugs" thread. I hope it is a service to |the community to reopen this. The poll on RubyGarden votes "make 'em all |local", closely followed by "leave it unchanged". Yet the "problem" keeps |coming up, and the most sensible solution (in my mind) is not represented in |the poll. The "solution" changes time to time in my mind. Currently I'm thinking of the following: * variables assigned by ":=" should be local to the block (or possibly local to the nearest compound statements). * if ":=" assignee is already defined in outer scope, it should be warned (no -w needed, probably), and outer variable is shadowed hereafter. * all local variables in block parameters (e.g. var in |var|) should be treated as if they are assigned by ":=". other types of variables in block parameter should be warned. * scope of local variables assigned by "=" will be a nearest "body" (method body, class body etc.) consistently. This does not change the appearance of Ruby code much, unlke <var> solution. It is incompatible to the current syntax, for example, a = 5 [1,2,3].each{|a| break if a % 2 == 0} p a prints "2" now. It will print "5" (with shadowing warning) if we adopt the changes above. Since it is not compatible, it will not be available in the near future. Perhaps you have to wait until Rite. matz.
|
Tue, 22 Mar 2005 10:37:21 GMT |
|
 |
Hal E. Fulto #4 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote: ----- Original Message -----
Sent: Thursday, October 03, 2002 8:58 PM Subject: Specifying local and external block parameters (that old chestnut) > I think it makes sense to explicitly mark *external* variables, as block-local > variables (parameters, in fact) would be the norm. > Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable, > then one could write > collection.each do |a,:b,c| > ... > end > or > collection.each do |a,b,c| > external b > ... > end > I'm not sure which of the above I prefer. One should optimise for the common > case.
One problem is that it's not just a simple variable. It can be anything that responds to assignment. For example, an accessor: 0.upto(99) {|frame.scroll| sleep 0.1} Quote: > I'd like to put a question to the audience :) Does anyone actually have a need > to use non-local block parameters? Ever?
The above is an example. Also what if I want the last value(s) of a loop? x,i = nil myobj.each_with_index do |x,i| # process... break if some_condition # more processing... end last_obj = x last_index = i Yes, I *could* save them off in different variables right before I did the break: y,j = nil myobj.each do |x,i| #... if some_condition y,j = x,i break end #... end last_obj, last_index = y,j Two more variables and much ugliness. No, thanks. Hal
|
Tue, 22 Mar 2005 10:38:46 GMT |
|
 |
Gavin Sinclai #5 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> Sent: Thursday, October 03, 2002 8:58 PM > Subject: Specifying local and external block parameters (that old chestnut) > > I think it makes sense to explicitly mark *external* variables, as > block-local > > variables (parameters, in fact) would be the norm. > > Thus, if 'a' and 'c' are regular parameters and 'b' is an external > variable, > > then one could write > > collection.each do |a,:b,c| > > ... > > end > > or > > collection.each do |a,b,c| > > external b > > ... > > end > > I'm not sure which of the above I prefer. One should optimise for the > common > > case. > One problem is that it's not just a simple variable. It > can be anything that responds to assignment. For example, > an accessor: > 0.upto(99) {|frame.scroll| sleep 0.1}
So could 0.upto(99) {|:frame.scroll| sleep 0.1} work? Look quite good, I think, since we are used to :: as a scoping operator. Quote: > > I'd like to put a question to the audience :) Does anyone actually have a > need > > to use non-local block parameters? Ever? > The above is an example.
Quite a nice example too, IMO. Quote: > Also what if I want the last value(s) of a loop? > x,i = nil > myobj.each_with_index do |x,i| > # process... > break if some_condition > # more processing... > end > last_obj = x > last_index = i > Yes, I *could* save them off in different variables > right before I did the break: > [...] > Two more variables and much ugliness. No, thanks. > Hal
I really dislike relying on finishing values like that, because: - you have to declare variables beforehand - code is harder to understand or be confident that it's right Much better, IMO, is x, i = get_values(myobj) def get_values(obj) obj.each_with_index do |x, i| # process return x, i if some_condition # more processing end end Gavin
|
Tue, 22 Mar 2005 13:10:48 GMT |
|
 |
Yukihiro Matsumo #6 / 49
|
 Specifying local and external block parameters (that old chestnut)
Hi, In message "Re: Specifying local and external block parameters (that old chestnut)"
| 0.upto(99) {|frame.scroll| sleep 0.1} | x,i = nil | myobj.each_with_index do |x,i| | # process... | break if some_condition | # more processing... | end | | last_obj = x | last_index = i Yes, they are problems. With the "solution" described in [ruby-talk:52440], you have to rewrite them as following respectively. Quote: > 0.upto(99) {|x| frame.scroll = x; sleep 0.1} > myobj.each_with_index do |x,i| > # process... > if some_condition > last_obj = x > last_index = i > break > end > # more processing... > end
matz.
|
Tue, 22 Mar 2005 13:39:44 GMT |
|
 |
Mauricio Fernánde #7 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> I've asked this before but can't recall any answers. How would one > do the following without non-local block params: > a = [1.1, 3.14, 2.7, 5.15] > sum = 0.0 > a.each { |elem| sum += a }
Shouldn't it be a.each { |elem| sum += elem } Anyway you aren't using (nor need) non-local block params at all! You're simply accessing variables from an external scope, which is OK (how would we get closures otherwise?) and isn't the issue we're to talk about. The thing is after a.each { |elem| sum += elem } elem will be 5.15 iff elem was already in the external scope, otherwise it isn't defined. Compare: a = [1,2,3,4,5] a = [1,2,3,4,5] sum = 0 sum = 0 l = 0 a.each { |l| sum += l } a.each { |l| sum += 1 } # here l == 5 # l is undefined here! With local block parameters, you'd get a = [1,2,3,4,5] sum = 0 l = "sdfsdfs" a.each { |:l| sum += 1 } # I claim this syntax as mine :-) # l is unchanged here! l == "sdfsdfs" Quote: > Personally, I like accessing external scope by default. C behaves similiarly: > #include <stdio.h> > int main() > { > int a = 42; > int b = 55; > printf("a: %d b: %d\n", a, b ); > { > int a = 33; /* define a as local scope to this block*/ > printf("a: %d b: %d\n", a, b ); > } > } > Gives you > a: 42 b: 55 > a: 33 b: 55
In C you can shadow external vars because you must declare them anyway. In Ruby an assignment to a var creates a new one iff there isn't already one with that name. -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Absolutely nothing should be concluded from these figures except that no conclusion can be drawn from them. -- Joseph L. Brothers, Linux/PowerPC Project)
|
Tue, 22 Mar 2005 14:46:26 GMT |
|
 |
Mauricio Fernánde #8 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> I've {*filter*}ised discussion from the "Bugs" thread. I hope it is a service to > the community to reopen this. The poll on RubyGarden votes "make 'em all > local", closely followed by "leave it unchanged". Yet the "problem" keeps > coming up, and the most sensible solution (in my mind) is not represented in > the poll. > I think it makes sense to explicitly mark *external* variables, as block-local > variables (parameters, in fact) would be the norm. > Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable, > then one could write > collection.each do |a,:b,c| > ... > end
I hereby claim authorship of any syntax derived from the use of the ':' prefix to indicate the scope of block parameters, based on [ruby-talk:52401]. All rights reserved. :-) Quote: > or > collection.each do |a,b,c| > external b > ... > end > I'm not sure which of the above I prefer. One should optimise for the common > case.
I'd head towards ':'. Reason: less typing.
just makes sense for me. Local params would surely be more common, but marking them with ':' instead of the external ones has the additional advantage of not breaking any code out there. The transition could be made very easy if the current scoping rules are mixed with ':' for a while. So in blabla.aaaa do |a,:b| end a is local if there's no variable named 'a' previously defined, otherwise external b is local even if there's already 'b' in the external scope bottom line: nothing breaks, ':' forces local Ruby can issue a warning iff there was no 'a' variable before, as this code would break once the old scoping rules are thrown away and only the presence or absence of ':' is significant. Quote: > I'd like to put a question to the audience :) Does anyone actually > have a need to use non-local block parameters? Ever?
They are indeed needed sometimes. -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Debian is like Suse with yast turned off, just better. :) -- Goswin Brederlow
|
Tue, 22 Mar 2005 15:20:45 GMT |
|
 |
Kent Dah #9 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> I hereby claim authorship of any syntax derived from the use of > the ':' prefix to indicate the scope of block parameters, based on > [ruby-talk:52401]. All rights reserved.
Request denied. Previous work proves to be quite similar. Plagarist! [ruby-talk:5555] Quote: > :-)
Please refrain from using : in smilies, as authorship has been contested and await legal decision on the matter. ;-P Quote: > I'd head towards ':'. Reason: less typing.
> just makes sense for me.
I like it too, but aparently Matz doesn't. [ruby-talk:42295] -- (\[ Kent Dahl ]/)_ _~_ __[ http://www.stud.ntnu.no/~kentda/ ]___/~ ))\_student_/(( \__d L b__/ NTNU - graduate engineering - 5. year ) ( \__\_?|?_/__/ ) _)Industrial economics and technological management( \____/_?_\____/ (____engineering.discipline_=_Computer::Technology___)
|
Tue, 22 Mar 2005 15:40:05 GMT |
|
 |
Gavin Sinclai #10 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote: > > Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable, > > then one could write > > collection.each do |a,:b,c| > > ... > > end > I hereby claim authorship of any syntax derived from the use of > the ':' prefix to indicate the scope of block parameters, based on > [ruby-talk:52401]. All rights reserved. > :-)
Fair enough. Your royalty cheque is in the mail. Quote: > > or > > collection.each do |a,b,c| > > external b > > ... > > end > > I'm not sure which of the above I prefer. One should optimise for the common > > case. > I'd head towards ':'. Reason: less typing.
> just makes sense for me.
Exactly. Quote: > Local params would surely be more common, but marking them with ':' > instead of the external ones has the additional advantage of not > breaking any code out there.
I disagree. Marking the external ones rather than internal ones is SO much more sensible. Seeing a.each do |:x| everywhere is too ugly. Changes have been made that break code before. How much code would it really break anyway? Quote: > The transition could be made very easy if > the current scoping rules are mixed with ':' for a while. > So in > blabla.aaaa do |a,:b| > end > a is local if there's no variable named 'a' previously defined, > otherwise external
This sort of confusion is exactly what we want to get away from. Quote: > b is local even if there's already 'b' in the external scope > bottom line: nothing breaks, ':' forces local > Ruby can issue a warning iff there was no 'a' variable before, as this > code would break once the old scoping rules are thrown away and only the > presence or absence of ':' is significant.
Gavin
|
Tue, 22 Mar 2005 15:44:17 GMT |
|
 |
Mauricio Fernánde #11 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> The "solution" changes time to time in my mind. Currently I'm > thinking of the following: > * variables assigned by ":=" should be local to the block (or > possibly local to the nearest compound statements). > * if ":=" assignee is already defined in outer scope, it should be > warned (no -w needed, probably), and outer variable is shadowed > hereafter.
Then there must be a way to turn these warnings off, because shadowing outer scope variables would be quite common IMHO. Quote: > * all local variables in block parameters (e.g. var in |var|) should > be treated as if they are assigned by ":=". other types of > variables in block parameter should be warned.
What about Hal's 0.upto(99) {|frame.scroll| sleep 0.1} example? Accessors would have to be treated differently (introduces a "special case" in the language). Quote: > * scope of local variables assigned by "=" will be a nearest "body" > (method body, class body etc.) consistently. > This does not change the appearance of Ruby code much, unlke <var>
It'd make me think of Pascal :-S Just the thought of such a '{*filter*}-and-discipline" language could sicken more than one Rubyist :) The "utterly dynamic" vs. "so static it's useless" contrast would be too much. := does change the appearance more than the admittedly more restricted ':' prefix solution. Quote: > solution. It is incompatible to the current syntax, for example, > a = 5 > [1,2,3].each{|a| break if a % 2 == 0} > p a > prints "2" now. It will print "5" (with shadowing warning) if we > adopt the changes above. Since it is not compatible, it will not be > available in the near future. Perhaps you have to wait until Rite.
As you say, it also breaks code, which "':' to indicate local" doesn't. -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Just go ahead and write your own multitasking multiuser os! Worked for me all the times. -- Linus Torvalds
|
Tue, 22 Mar 2005 15:59:24 GMT |
|
 |
Mauricio Fernánde #12 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> ----- Original Message -----
> > Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable, > > then one could write > > collection.each do |a,:b,c| > > ... > > end
See my note on this syntax in my original reply to Gavin :-) Quote: > One problem is that it's not just a simple variable. It > can be anything that responds to assignment. For example, > an accessor: > 0.upto(99) {|frame.scroll| sleep 0.1}
This works unchanged if you accept ':' as a local scope indicator, only to be used on variables (not on accesor methods, as it'd be meaningless), so Ruby would {*filter*}on 0.upto(99) {|:frame.scroll| sleep 0.1} as anyway what you really want is 0.upto(99) {|frame.scroll| sleep 0.1} Quote: > > I'd like to put a question to the audience :) Does anyone actually have a > need > > to use non-local block parameters? Ever? > The above is an example. > Also what if I want the last value(s) of a loop? > x,i = nil > myobj.each_with_index do |x,i| > # process... > break if some_condition > # more processing... > end > last_obj = x > last_index = i > Yes, I *could* save them off in different variables > right before I did the break: > y,j = nil > myobj.each do |x,i| > #... > if some_condition > y,j = x,i > break > end > #... > end > last_obj, last_index = y,j > Two more variables and much ugliness. No, thanks.
One more reason to use ':' to indicate local, so the former code runs unchanged. -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Not only Guinness - Linux is good for you, too. -- Banzai on IRC
|
Tue, 22 Mar 2005 15:59:40 GMT |
|
 |
Mauricio Fernánde #13 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote:
> > I hereby claim authorship of any syntax derived from the use of > > the ':' prefix to indicate the scope of block parameters, based on > > [ruby-talk:52401]. All rights reserved. > Request denied. Previous work proves to be quite similar. Plagarist! > [ruby-talk:5555] > > :-)
I'm just receiving my first royalty checks. Try to take them from me 8-) BTW, you'll have a hard time crawling through Spain's judicial system before you can get a single penny back. Quote: > Please refrain from using : in smilies, as authorship has been contested > and await legal decision on the matter. > ;-P
No problem. Clemens Hintze granted me long ago an exclusive, unlimited, world-wide, royalty-free license to use ':'. Talk with your lawyer, for I suspect *you* will soon receive a cease and desist letter. }:-> Anyway, I hereby claim authorship of the use of any single-character prefix or suffix, for which no prior art exists, to indicate scoping in Ruby. Quote: > > I'd head towards ':'. Reason: less typing.
> > just makes sense for me. > I like it too, but aparently Matz doesn't. [ruby-talk:42295]
I've just read it but I cannot understand why :-? -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Less is more or less more -- Y_Plentyn on #LinuxGER
|
Tue, 22 Mar 2005 16:17:25 GMT |
|
 |
Yukihiro Matsumo #14 / 49
|
 Specifying local and external block parameters (that old chestnut)
Hi, In message "Re: Specifying local and external block parameters (that old chestnut)"
|> * if ":=" assignee is already defined in outer scope, it should be |> warned (no -w needed, probably), and outer variable is shadowed |> hereafter. | |Then there must be a way to turn these warnings off, because shadowing |outer scope variables would be quite common IMHO. I'm afraid I won't give you a way to turn it off. It is "quite common" in other languages, but it does not mean Ruby must follow. I believe local variable shadowing is a bad thing. |> * all local variables in block parameters (e.g. var in |var|) should |> be treated as if they are assigned by ":=". other types of |> variables in block parameter should be warned. | |What about Hal's | 0.upto(99) {|frame.scroll| sleep 0.1} |example? | |Accessors would have to be treated differently (introduces a "special |case" in the language). If you read the rule again, you will find the answer. Accessors are not local variables, so that they will not be treated by ":=" anyway. Instead, since they are "other types of variables", you will be warned. |Just the thought of such a '{*filter*}-and-discipline" language could |sicken more than one Rubyist :) The "utterly dynamic" vs. "so static |it's useless" contrast would be too much. | |:= does change the appearance more than the admittedly more restricted |':' prefix solution. I'm not sure if I get your point. It will surely change the appearance. But it changes less than the "<var> solution". |As you say, it also breaks code, which "':' to indicate local" doesn't. Yes. But I feel "':' to indicate local" is ugly. Many (or most) people want their block parameters "local to the block". But "':' to indicate local" requires additional mark for common case. "':' to indicate *external*" is better in this sense, but this also breaks existing code. matz.
|
Tue, 22 Mar 2005 16:19:50 GMT |
|
 |
Gavin Sinclai #15 / 49
|
 Specifying local and external block parameters (that old chestnut)
Quote: > Apologies if this can of worms is better left buried. > Cheers, > Gavin
Following up my own post, I now see that it has been discussed extensively in the past, nothing has happened, Matz has some plans, and we won't see any change until Rite. I have no problem with any of that, so I'll let this sleeping dog lie. Gavin
|
Tue, 22 Mar 2005 16:27:10 GMT |
|
|
|