(3) some other syntax will be introduced for cases where...
God help us all. I thought Ruby was a simple language.
If a variable is only used in the scope of a block, then let the darn compiler
figure that out.
-Patrick
(3) some other syntax will be introduced for cases where...
God help us all. I thought Ruby was a simple language.
If a variable is only used in the scope of a block, then let the darn compiler
figure that out.
-Patrick
That modification is not meant to spoon-feed the compiler (which does
BTW not exist) but rather to simplify the scoping rules. The AST
walker always knows the truth about the program; the programmer might
not. The proposed change makes it easier to realize what’s going on.
On Thu, Feb 13, 2003 at 08:35:34AM +0900, patrickdlogan@attbi.com wrote:
(3) some other syntax will be introduced for cases where…
God help us all. I thought Ruby was a simple language.
If a variable is only used in the scope of a block, then let the darn compiler
figure that out.
–
_ _
__ __ | | ___ _ __ ___ __ _ _ __
'_ \ /| __/ __| '_
_ \ / ` | ’ \
) | (| | |__ \ | | | | | (| | | | |
.__/ _,|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com
#if _FP_W_TYPE_SIZE < 64
#error “Only stud muffins allowed, schmuck.”
#endif
– linux/arch/sparc64/quad.c
That's exactly it.
I think it's a barrier to newcomers that "a=0" has various different
behaviours depending on where you put it and whether or not you had a
previous assignment to "a" elsewhere in your method. I understand it now,
but it took a while.
Furthermore, your code may sometimes *rely* on variables being block-local,
but you have no way to signal your intention other than the *absence* of an
assignment outside of the block... documentation by omission I end up
using bizarre names like "thread_i" to indicate this.
Essentially, we have four different behaviours now, all of which are useful,
but all of which are implied:
(1) 'a' (assigned variable) is bound to the method's local variables
def method
a = 0
[1,2,3].each {|p|
a = p <<<
}
puts a
end
(2) 'a' is local to the block
def method
[1,2,3].each {|p|
a = p <<<
}
end
(3) 'p' (block parameter) is bound to the method's local variables
def method
p = nil
[1,2,3].each {|p| <<<
a = p
}
puts p
end
(4) 'p' is local to the block
def method
[1,2,3].each {|p| <<<
a = p
}
end
And actually cases (1) and (3) have variants where they bind to the
variables of an enclosing block, as opposed to the method itself:
(1a) 'a' is bound to an enclosing block
def method
[1,2,3].each {|p|
a = nil <<< a is local to outer block
[4,5,6].each {|q|
a = q <<< this is the same 'a' in outer block
}
puts a
}
end
(3a) 'q' is bound to an enclosing block
def method
[1,2,3].each {|p|
q = nil
[4,5,6].each {|q| <<< bound to 'q' in outer block
a = q
}
puts q
}
end
These last two really do seem to be different, because a method is not the
same as a Proc object, and so a method local variable is not the same as a
block local variable.
I think all the above cases will appear in real programs, except IMO cases
(3) and (3a) are ugly hacks which nobody should be allowed to use That
is, parameters to a block should be like the formal parameters to a method,
which are always local. That is acknowledged by Matz in the proposed New
Rules.
But apart from that, we still have to signal to the interpreter whether we
want 'a' or 'p' to be local or bound to enclosing scope, and whatever you do
that's going to involve syntax rules. Let me try to summarise:
Current rules
On Thu, Feb 13, 2003 at 05:44:36PM +0900, Mauricio Fern?ndez wrote:
On Thu, Feb 13, 2003 at 08:35:34AM +0900, patrickdlogan@attbi.com wrote:
> > (3) some other syntax will be introduced for cases where...
>
> God help us all. I thought Ruby was a simple language.
>
> If a variable is only used in the scope of a block, then let the darn compiler
> figure that out.That modification is not meant to spoon-feed the compiler (which does
BTW not exist) but rather to _simplify_ the scoping rules. The AST
walker always knows the truth about the program; the programmer might
not. The proposed change makes it easier to realize what's going on.
=============
'a' bound previous assignment to 'a'
'a' local no previous assignment to 'a' before block
'|p|' bound previous assignment to 'p'
'|p|' local no previous assignment to 'p' before block
'a' bound the default*
'a' local not available, use |a| in a fake block, e.g. local {|a| ...}
'|p|' bound not available, use '|q| p=q'
'|p|' local the default
*if block is nested within another block, not clear whether 'a' binds to the
entire method or to the enclosing block; this may still depend on where 'a'
was previously assigned to.
Any other set of rules is going to have to have syntax for each of these
cases, and you just choose your sugar to taste. Many have been suggested.
e.g.
'a' bound a=0
'a' local my a=0 or %a=0
'|p|' bound |p|
'|p|' local |my p| or |%p|
'a' bound our a=0 or { |p| <a> ... }
'a' local a=0
'|p|' bound |our p|
'|p|' local |p|
Matz doesn't want any explicit declarations, so basically the new rules
forbid two behaviours completely ('a' local and '|p|' bound), with
workarounds if you need those behaviours.
'|p|' bound is not very useful anyway, so your fundamental problem boils
down to how to choose between the two behaviours for local variables:
max = 0
obj.each {|i|
max = i if i > max # max must be BOUND or this doesn't work
}
puts max
Thread.new {
tmp = Obj.new # tmp must be LOCAL or this doesn't work
tmp.doit
}
Regards,
Brian.
P.S. All this ignores the fact that "puts a" might be a method call or a
local variable depending on whether "a" has been assigned to previously. I
don't mind explaining that to nubies... it's having further levels of
complexity over assignments which is likely to put people off!
Essentially, we have four different behaviours now
No, there are only 2 cases. No need to give complex explanation for
something which is simple.
What you call a “block parameter” don’t exist, this is is just an
assigned variable : understand this and you’ll understand the rules used
by ruby actually.
Guy Decoux
Any other set of rules is going to have to have syntax for each of these
cases, and you just choose your sugar to taste. Many have been suggested.
e.g.
thank you for the excellent overview
Matz doesn’t want any explicit declarations, so basically the new rules
forbid two behaviours completely (‘a’ local and ‘|p|’ bound), with
workarounds if you need those behaviours.‘|p|’ bound is not very useful anyway, so your fundamental problem boils
down to how to choose between the two behaviours for local variables:max = 0
obj.each {|i|
max = i if i > max # max must be BOUND or this doesn’t work
}
puts maxThread.new {
tmp = Obj.new # tmp must be LOCAL or this doesn’t work
tmp.doit
}
since there seems to be two general cases that are competing for high-ground,
so to speak, i wonder if it would not be more prudent to distinguish the two
with seperate block deliminators? rough examples:
obj.each do |i|
max = i if i > max # max must be BOUND or this doesn’t work
end
puts max
using do…end, max is bound to outer scope. (IMHO block parameters, e.g. |i|,
should ALWAYS be local)
Thread.new {
tmp = Obj.new # tmp must be LOCAL or this doesn’t work
tmp.doit
}
using {…} tmp is local.
currently do…end and {…} are the same except for a minor precendence issue
that honestly i’ve never had need to understand. (perhaps someone could
explain that?)
anyway you get the idea, whether the distinction lies between do…end versus
{…} or another syntax.
On Thursday 13 February 2003 04:54 am, Brian Candler wrote:
–
tom sawyer, aka transami
transami@transami.net
Of course you are right, but:
(1) a=0 and {|a| ... }
are two different syntaxes. It just so happens that they have the
same behaviour. I found this REALLY surprising, as |a| looks like a
formal parameter. It was the last piece of the jigsaw to fit for me.
(2) Under the new rules, they will most definitely be different.
That's why I think it is worth explicitly enumerating all four cases.
Regards,
Brian.
On Thu, Feb 13, 2003 at 09:01:52PM +0900, ts wrote:
> Essentially, we have four different behaviours now
No, there are only 2 cases. No need to give complex explanation for
something which is simple.What you call a "block parameter" don't exist, this is is *just* an
assigned variable : understand this and you'll understand the rules used
by ruby actually.
using do..end, max is bound to outer scope. (IMHO block parameters, e.g. |i|,
should ALWAYS be local)
...
using {...} tmp is local.
Hmm, nice idea: make it settable per-block rather than per-variable.
How about we stick all these ideas on wiki somewhere? At least then when
this thread comes up again we can direct people there!
Cheers,
Brian.
On Thu, Feb 13, 2003 at 10:02:45PM +0900, Tom Sawyer wrote:
Hi,
In message “Re: Lexical scope and closures” on 03/02/13, Tom Sawyer transami@transami.net writes:
since there seems to be two general cases that are competing for high-ground,
so to speak, i wonder if it would not be more prudent to distinguish the two
with seperate block deliminators?
I don’t think it’s good idea, because it kinda hard to remember which
is which. Besides, block delimiters already have precedence
difference, I believe adding two independent roles to a single syntax
construct is bad.
matz.
(2) Under the new rules, they will most definitely be different.
Only matz know the new rules.
Guy Decoux
using do…end, max is bound to outer scope. (IMHO block parameters, e.g. |i|,
should ALWAYS be local)
…
using {…} tmp is local.Hmm, nice idea: make it settable per-block rather than per-variable.
Was suggested before but IIRC matz didn’t comment on it.
How about we stick all these ideas on wiki somewhere? At least then when
this thread comes up again we can direct people there!
We really need that since this thread never seems to die.
On Thu, Feb 13, 2003 at 10:10:01PM +0900, Brian Candler wrote:
On Thu, Feb 13, 2003 at 10:02:45PM +0900, Tom Sawyer wrote:
–
_ _
__ __ | | ___ _ __ ___ __ _ _ __
'_ \ /| __/ __| '_
_ \ / ` | ’ \
) | (| | |__ \ | | | | | (| | | | |
.__/ _,|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com
Computers are like air conditioners. Both stop working, if you open windows.
– Adam Heath
i understand, but perhaps too bad, as i think it might be the easiest way to
satisfy both camps.
aside, i am curious about the precedence though, as i have never had the need
to pay attention to it. is it a common need? is there no other simple way to
designate the precedence one might need in such a situtation?
on the other hand we could appraoch it with a simple variation:
arr.each do local |x| r = x + 1; puts r end
or, perhaps better,
arr.each local do |x| r = x + 1; puts r end
in either case r would be local to the block.
On Thursday 13 February 2003 06:44 pm, Yukihiro Matsumoto wrote:
Hi,
In message “Re: Lexical scope and closures” > > on 03/02/13, Tom Sawyer transami@transami.net writes:
since there seems to be two general cases that are competing for
high-ground, so to speak, i wonder if it would not be more prudent to
distinguish the two with seperate block deliminators?I don’t think it’s good idea, because it kinda hard to remember which
is which. Besides, block delimiters already have precedence
difference, I believe adding two independent roles to a single syntax
construct is bad.matz.
–
tom sawyer, aka transami
transami@transami.net
He was involved in the recent discussion about what his ideas were for the
new rules. I am happy to be corrected if I have not summarised correctly.
Regards,
Brian.
On Thu, Feb 13, 2003 at 09:23:27PM +0900, ts wrote:
> (2) Under the new rules, they will most definitely be different.
Only matz know the new rules.
I see there is an unlinked topic:
* LocalVariablesAndBlocks?
at http://www.rubygarden.org/ruby?RubyDiscussions
Did you just create it? If not, I'll put something there later today.
Regards,
Brian.
On Thu, Feb 13, 2003 at 10:58:11PM +0900, Mauricio Fern?ndez wrote:
> How about we stick all these ideas on wiki somewhere? At least then when
> this thread comes up again we can direct people there!We really need that since this thread never seems to die.
Thanks for putting this together. Anybody else who's interested, please see
I have added my post from ruby-talk:64670 (since you so graciously suggested
I do so off-list and a couple of subpages:
/CurrentBehaviour
/ProposedBehaviour
Cheers,
Brian.
On Thu, Feb 13, 2003 at 10:58:11PM +0900, Mauricio Fern?ndez wrote:
> How about we stick all these ideas on wiki somewhere? At least then when
> this thread comes up again we can direct people there!We really need that since this thread never seems to die.
Hi,
In message “Re: Lexical scope and closures” on 03/02/14, Tom Sawyer transami@transami.net writes:
i understand, but perhaps too bad, as i think it might be the easiest way to
satisfy both camps.
Which camps? At least this one does not satisfy the “compatibility
camp”, which must be the biggest. Could you describe other camps
satisfied by this proposal?
matz.
camps:
1) make’em all local
2) leave it unchanged
which represent 74.66% or all votes on ruby garden poll.
you are right about compatibility. and i wasn’t so much suggesting that this
be the very syntax to use, i.e. do…end vs. {…} it was only a Rough
demonstration.
more suitable would be the changes as you have already suggested plus the
addition of local keyword. ( i.e. arr.each local do … end )
On Thursday 13 February 2003 07:42 pm, Yukihiro Matsumoto wrote:
Hi,
In message “Re: Lexical scope and closures” > > on 03/02/14, Tom Sawyer transami@transami.net writes:
i understand, but perhaps too bad, as i think it might be the easiest way
to satisfy both camps.Which camps? At least this one does not satisfy the “compatibility
camp”, which must be the biggest. Could you describe other camps
satisfied by this proposal?
–
tom sawyer, aka transami
transami@transami.net
Hi,
more suitable would be the changes as you have already suggested plus the
addition of local keyword. ( i.e. arr.each local do … end )
I’d choose something between
arr.each {|i|
local{|a,b|
c = …
…
}
}
and
arr.each {|i|
let a = …
let b = …
c = …
…
}
in either case, a, b are local, c is method-wise variable.
matz.
In message “Re: Lexical scope and closures” on 03/02/14, Tom Sawyer transami@transami.net writes:
arr.each {|i|
local{|a,b|
c = …
…
}
}
mmm…seems overly syntatical, might as well do:
arr.each {|i;a,b|
c = …
}
though for some reason i don’t like this either. feels like a aand b should be
catching something, not just becoming local.
arr.each {|i|
let a = …
let b = …
c = …
…
}
clean, though this is a declarative, which i thought you were trying to avoid.
but maybe this is best. yet i think this would add complication: what would
‘let’ mean outside of block? wouldn’t one be inclined to have it go further:
class A
def inititalize
c = “instead of @c”
let a = “instead of just a”
end
end
which might be all well and good, but i think it’s a little too late for this.
so unless you really wanted to do this despite code breakage, ‘let’ and ‘:=’
should probably be avoided --the inclination toward the above would be too
strong.
yet, something drives me to want procs and blocks to be like methods --that
everything is local and you have to pass variables in and out, but this
doesn’t coincide well with current ruby, and perhaps defeats the purpose of
closures.
hmmm… might as well throw this out:
arr.each do(a,b) |i|
c = “is local”
a = “not local”
b = “not local”
d = “is local”
return d # but this gives d to outer scope
end
another idea to add to the pool. give it plenty of time, the best solution
will clearly arise at some point. who knows, perhaps you got it right the
first time: the way it is
On Thursday 13 February 2003 08:03 pm, Yukihiro Matsumoto wrote:
–
tom sawyer, aka transami
transami@transami.net
“Yukihiro Matsumoto” matz@ruby-lang.org schrieb im Newsbeitrag
news:1045190480.331543.2340.nullmailer@picachu.netlab.jp…
Hi,
more suitable would be the changes as you have already suggested plus
the
addition of local keyword. ( i.e. arr.each local do … end )I’d choose something between
arr.each {|i|
local{|a,b|
c = …
…
}
}and
arr.each {|i|
let a = …
let b = …
c = …
…
}in either case, a, b are local, c is method-wise variable.
I vote for the second variant, possibly replacing ‘let’ with ‘local’. The
drawback of the first variant is IMHO that it is too easily recognized as
an ordinary block.
Kind regards
robert
In message “Re: Lexical scope and closures” > on 03/02/14, Tom Sawyer transami@transami.net writes:
Hi,
more suitable would be the changes as you have already suggested plus the
addition of local keyword. ( i.e. arr.each local do … end )I’d choose something between
arr.each {|i|
local{|a,b|
c = …
…
}
}
personal feeling: too many indentation levels.
and
arr.each {|i|
let a = …
let b = …
c = …
…
}in either case, a, b are local, c is method-wise variable.
Would you reconsider dropping ‘:=’ ?
arr.each { |i|
a := …
b := …
c = …
…
}
involves fewer keystrokes. Moreover (I don’t know if it was your
original idea or not, but just to be sure)
a = 1
arr.each { |i|
a := …
…
a = … # uses local a, not external, ie. := works like let
}
On Fri, Feb 14, 2003 at 12:03:59PM +0900, Yukihiro Matsumoto wrote:
In message “Re: Lexical scope and closures” > on 03/02/14, Tom Sawyer transami@transami.net writes:
–
_ _
__ __ | | ___ _ __ ___ __ _ _ __
'_ \ /| __/ __| '_
_ \ / ` | ’ \
) | (| | |__ \ | | | | | (| | | | |
.__/ _,|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com
Yes I have a Machintosh, please don’t scream at me.
– Larry Blumette on linux-kernel