[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: ruby1.9 block scope

Yukihiro Matsumoto

9/30/2008 5:43:00 PM

Hi,

In message "Re: ruby1.9 block scope"
on Wed, 1 Oct 2008 02:06:38 +0900, Mike Gold <mike.gold.4433@gmail.com> writes:

|I hope I'm not belaboring the point, but --

<snip>

Yes, but

* Class.new and define_method is a rather rare examples, of which
non-block counterpart introduce new scopes.
* In 1.9, you can have explicit block local variables if you expect
any confusion.

matz.

9 Answers

Mike Gold

9/30/2008 6:40:00 PM

0

Yukihiro Matsumoto wrote:
>
> Yes, but
>
> * Class.new and define_method is a rather rare examples, of which
> non-block counterpart introduce new scopes.

But it's not a rare example for me. It's a great solution to an
otherwise tangled problem. When I have more time I can post some code
if my example is not convincing.

The whole point is that I don't want to introduce a new scope. As I
briefly mentioned, I am writing adapters which put a "new face" on the
current binding so that other levels can understand it.

By contrast, it would be convoluted to create all new scopes each with
instance variables pointing back to the places I just came from. The
code would be Java-like: reams of scaffolding which serve no end except
to compensate for a missing language feature.

> * In 1.9, you can have explicit block local variables if you expect
> any confusion.

I would use the block local syntax every time, because I would always
expect confusion. The ruby "good feeling" would be gone, for me.
Effectively it would be Lisp "let" constructs, which is fine I guess,
but it's Lisp.

I have always thought of ruby as a (non-defmacro) Lisp "optimized" to
make programmers more happy. In this case I feel the proposed
"optimization" goes too far, producing unexpected behavior like in the
example I gave. But I realize POLS refers to your surprise, not my
surprise.
--
Posted via http://www.ruby-....

Daniel DeLorme

10/1/2008 4:52:00 AM

0

Mike Gold wrote:
> Yukihiro Matsumoto wrote:
>> Yes, but
>>
>> * Class.new and define_method is a rather rare examples, of which
>> non-block counterpart introduce new scopes.
>
> But it's not a rare example for me. It's a great solution to an
> otherwise tangled problem. When I have more time I can post some code
> if my example is not convincing.

Yes, I would love to see some non-contrived example code. I don't use
define_method very often and I have hardly ever used Class.new,
certainly not with several levels of nested blocks. The common case for
which I *would* like to use this suggested featured is something like this:

1 collection.each do |element|
2 changed = true if element.change
3 end
4 do_something if changed

Are you really saying that upon reading line 4 you have to backtrack to
line 2 in order to understand this code?

Far from a monster of O(n^2) complexity, this is the kind of code that
most programmers would expect to work. Except it doesn't, and if I have
to hazard a guess I would say that 90% of ruby newbies have run into
that gotcha.

Of course we all learn to work around it and even exploit it, but it
doesn't mean it was right to begin with. While "intuitive" and "POLS"
are loaded terms, if 90% of newbies bump into a gotcha, IMHO it's the
sign of a design flaw, and matz was right to notice it.

--
Daniel

Brian Candler

10/1/2008 8:33:00 AM

0

Daniel DeLorme wrote:
> 1 collection.each do |element|
> 2 changed = true if element.change
> 3 end
> 4 do_something if changed
>
> Are you really saying that upon reading line 4 you have to backtrack to
> line 2 in order to understand this code?

I think the point is more this:

class Foo
attr_reader :changed

def update
collection.each do |element|
element << "\n" if changed # <<<<
end
...
...
...
collection.each do |element|
changed = true if element.change
end
end
end

At the marked line, you can't tell whether 'changed' is a local variable
or a method call on this object until you have read forward to the end
of the method. For me, this is horrid.

Perhaps more importantly though, as far as I can see it makes irb pretty
useless, since it can't predict the future. What's supposed to happen
when you type this, one line at a time?

def tmp; "hello"; end
m = lambda { |x| tmp + x }
m[" world"]
tmp = "goodbye"
m[" world"]

This particular example may be somewhat contrived, but if code behaves
differently in irb than when read from a source file, that would be
horrid (and difficult to explain) too.

Regards,

Brian.
--
Posted via http://www.ruby-....

Mike Gold

10/1/2008 6:44:00 PM

0

Daniel DeLorme wrote:
> Mike Gold wrote:
>> Yukihiro Matsumoto wrote:
>>> Yes, but
>>>
>>> * Class.new and define_method is a rather rare examples, of which
>>> non-block counterpart introduce new scopes.
>>
>> But it's not a rare example for me. It's a great solution to an
>> otherwise tangled problem. When I have more time I can post some code
>> if my example is not convincing.
>
> Yes, I would love to see some non-contrived example code. I don't use
> define_method very often and I have hardly ever used Class.new,
> certainly not with several levels of nested blocks. The common case for
> which I *would* like to use this suggested featured is something like
> this:

Because you've hardly ever used Class.new, and therefore are probably
not familiar with run-time generated classes which present a given
binding as different views to external onlookers, then you won't
appreciate what I have to say. To you everything is blub, and you
wonder why non-blub things are necessary. It's a paradox, that you need
to understand before you can understand. See
http://www.paulgraham.co...

The strategy I've described comes from Lisp. And it's awesome.

In fact I think my example does suffice. You just need to imagine it
being using on a slightly larger scale. As I said previously in this
thread, "it would be convoluted to create all new scopes each with
instance variables pointing back to the places I just came from. The
code would be Java-like: reams of scaffolding which serve no end except
to compensate for a missing language feature." Do you have a response
to that? Please don't repeat your argument yet again; instead, try to
understand what I've said.

> 1 collection.each do |element|
> 2 changed = true if element.change
> 3 end
> 4 do_something if changed
>
> Are you really saying that upon reading line 4 you have to backtrack to
> line 2 in order to understand this code?

Yes, I backtracked just now, before I read your last sentence above. I
checked to be sure that 'changed' means a local variable. I have to do
this with every variable in arbitrarily long scopes. You are thinking
in terms of small examples, but I am thinking about large ones.

> Far from a monster of O(n^2) complexity,

It is O(n^2) complex because it requires a backtrack for each case. I
like to be certain what code does. I will always backtrack in order to
be certain.

> this is the kind of code that
> most programmers would expect to work. Except it doesn't, and if I have
> to hazard a guess I would say that 90% of ruby newbies have run into
> that gotcha.

You did not address my counterpoint to your argument here. You just
repeated your argument.

--
Posted via http://www.ruby-....

Pit Capitain

10/1/2008 7:40:00 PM

0

2008/10/1 Mike Gold <mike.gold.4433@gmail.com>:
> Daniel DeLorme wrote:
>> Yes, I would love to see some non-contrived example code. I don't use
>> define_method very often and I have hardly ever used Class.new,
>> certainly not with several levels of nested blocks. The common case for
>> which I *would* like to use this suggested featured is something like
>> this:
>
> Because you've hardly ever used Class.new, and therefore are probably
> not familiar with run-time generated classes which present a given
> binding as different views to external onlookers, then you won't
> appreciate what I have to say.

So Mike, please show us a real non-contrived example to enlighten us.
I've often used Class.new but still don't see your problem.

> In fact I think my example does suffice.

No it doesn't. In your example there's no obvious need to use
Class.new and define_method.

>> Far from a monster of O(n^2) complexity,
>
> It is O(n^2) complex because it requires a backtrack for each case. I
> like to be certain what code does. I will always backtrack in order to
> be certain.

You have to do that in current Ruby, too, because you have to check
for local variables that have been assigned to before the code blocks.
Expanding the checks to the end of the scope doesn't change the O
complexity.

Regards,
Pit

Mike Gold

10/1/2008 8:55:00 PM

0

Pit Capitain wrote:
> So Mike, please show us a real non-contrived example to enlighten us.
> I've often used Class.new but still don't see your problem.

Do you understand my previous paragraph:

By contrast, it would be convoluted to create all new scopes each with
instance variables pointing back to the places I just came from. The
code would be Java-like: reams of scaffolding which serve no end except
to compensate for a missing language feature.

I ask because I've seen no indication that others have gotten it besides
matz. A larger example would be just what I've written already, only
larger. But if we aren't first on the same page with respect to the
above, the larger example will not help either. There is nothing I'm
holding back. If it's not obvious then ask a question.

I would suggest to actively seek what is meant by the above, rather than
to passively demand code which will infuse you with enlightenment. It
won't.

Rather, treat it as a homework problem: construct a case where a set of
dynamically generated _unique_ classes bound to the current context
results in better code compared to a set of named classes defined in a
different scopes containing instance variables to that current context.
Go.

I don't mean to lecture, but after the necessary tools have been laid on
the table, I do resent students who demand to be shown. It is only the
curious who really learn. Questions are welcome. Demands are not.

> You have to do that in current Ruby, too, because you have to check
> for local variables that have been assigned to before the code blocks.

But you don't have to check for locals that have been assigned after.
See my example.
--
Posted via http://www.ruby-....

Daniel DeLorme

10/2/2008 5:17:00 AM

0

Mike Gold wrote:
> Because you've hardly ever used Class.new, and therefore are probably
> not familiar with run-time generated classes which present a given
> binding as different views to external onlookers, then you won't
> appreciate what I have to say. To you everything is blub, and you
> wonder why non-blub things are necessary. It's a paradox, that you need
> to understand before you can understand. See
> http://www.paulgraham.co...
>
> The strategy I've described comes from Lisp. And it's awesome.

Just because I've hardly ever *had* to use Class.new doesn't mean that I
don't understand how it works or that I'm some kind of idiot. It's true
that I don't appreciate what you have to say. And I imagine 99.9% of
ruby coders won't either. The problem you describe is, by your own
admission, rooted in using ruby as an alternative lisp. It's great that
ruby is so flexible that you can do that, but ultimately ruby is ruby,
not lisp. I wouldn't hold back the language just so that it can stay
more like another language.

> In fact I think my example does suffice. You just need to imagine it
> being using on a slightly larger scale. As I said previously in this
> thread, "it would be convoluted to create all new scopes each with
> instance variables pointing back to the places I just came from. The
> code would be Java-like: reams of scaffolding which serve no end except
> to compensate for a missing language feature." Do you have a response
> to that? Please don't repeat your argument yet again; instead, try to
> understand what I've said.

I apologize for repeating myself. In my defense, your argument is
gibberish to me so there's not much I can reply to. If you're talking
about added complexity in the interpreter, I fail to see how that should
affect the language's design. And if you're talking about added
complexity in the ruby code, I fail to see how the proposal has anything
to do with instance variables or would require additional "scaffolding".
At most you'd need to avoid re-using variable names in a given scope,
and that good programming practice anyway.

> Yes, I backtracked just now, before I read your last sentence above. I
> checked to be sure that 'changed' means a local variable. I have to do
> this with every variable in arbitrarily long scopes. You are thinking
> in terms of small examples, but I am thinking about large ones.
> It is O(n^2) complex because it requires a backtrack for each case. I
> like to be certain what code does. I will always backtrack in order to
> be certain.

Ok, I now see that it is indeed O(n^2) complex. But you *already* have
to do that for large scopes; you have to consider every variable that
previously appeared in the scope, and that's O(n^2). The new rule would
make it 2*O(n^2) [which, in math speak, is still O(n^2)]. But this is
only a problem if n is very large; if you really have a scope that long
then I dare say that you already have a problem and some refactoring is
in order. Whatever happened to "no more than 10-20 lines per method" ?

--
Daniel

Daniel DeLorme

10/2/2008 5:47:00 AM

0

Daniel DeLorme wrote:
> Ok, I now see that it is indeed O(n^2) complex. But you *already* have
> to do that for large scopes; you have to consider every variable that
> previously appeared in the scope, and that's O(n^2). The new rule would
> make it 2*O(n^2) [which, in math speak, is still O(n^2)]. But this is
> only a problem if n is very large; if you really have a scope that long
> then I dare say that you already have a problem and some refactoring is
> in order. Whatever happened to "no more than 10-20 lines per method" ?

Sorry, I didn't think this through enough.

The new rule would not change the current rule that variables defined at
L are not considered as variables at all at lines L-n. So under the new
rule, code would have mathematically the *same* complexity but
practically it might be more tricky:

define_method :foo do
#say, 20 lines of code
end
foobar

under new rules, you'd have to backtrack until the top of the scope to
see if "foobar" is a variable or not.

under old rules, you'd have to backtrack until the top of the scope to
see if "foobar" is a variable or not, while taking into account that
variables defined in a sub-scope are self-contained, which means that
you can skip large sections of indented code.

I hope I got it right this time.

--
Daniel

Pit Capitain

10/2/2008 6:16:00 AM

0

2008/10/1 Mike Gold <mike.gold.4433@gmail.com>:
> Rather, treat it as a homework problem: construct a case where a set of
> dynamically generated _unique_ classes bound to the current context
> results in better code compared to a set of named classes defined in a
> different scopes containing instance variables to that current context.

Why should I do that? You said that changing Ruby to automatically
expand the scope of local variables would make some code harder to
visually inspect and showed an example using Class.new and
define_method. But your example could be changed easily to use normal
class and method definitions without altering its behaviour.

My question is why you need the current context. This is the very part
which you don't explain in your example. I'm not asking "how" but
"why". By writing code I can only learn about the "how" part. I'm
always interested to learn something new, but if you don't want to
answer the question, that's fine for me, too.

>> You have to do that in current Ruby, too, because you have to check
>> for local variables that have been assigned to before the code blocks.
>
> But you don't have to check for locals that have been assigned after.

Oh really? I think I didn't get this, yet :-) But how does this change
the asymptotic complexity? This is what I wrote about.

Regards,
Pit