Ruby1.9 block scope

Mike G. 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
Beating the Averages

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 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.

Suraj K. wrote:

package. It should not emit new variables into its surroundings!
Otherwise, it would be something like an “opener” instead of a
“closure”.

If you’re thinking in terms of lambdas and anonymous functions then I
can see how you would think that. But I think of blocks more in terms of
control structures. Variables defined inside a “if” or “while” statement
continue existing outside of the if/while, and so should variables
defined inside a block.

I don’t deny that that lambdas are useful, but I do think we have a
conflict here: blocks are used both as control structures and as
lambdas, and those two would benefit from having different scoping
rules.

Yes. You are right. In that case might be good to not perform a
regular expression match on every element.
res = a.reverse.find { |e| e =~ /foo/ }

2008/10/1 Mike G. [email protected]:

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 :slight_smile: But how does this change
the asymptotic complexity? This is what I wrote about.

Regards,
Pit