Ruby-dev summary 17252-17356

a = 1
i = 2
(1..10).each do |i;a|
  a = i*i
end

p a   #=> 1
p i   #=> 10

and I assume

a = 1
i = 2
(1..10).each do <i;a>
  a = i*i
end

p a   #=> 1
p i   #=> 2

and
5.times do |;a| a=gets; print a end
or
5.times do <;a> a=gets; print a end
?

Both are very ugly :wink:

I think parameter passing and locality (?) of variables should be handled
orthogonally. Maybe adding a new keyword.

I can think (uh… these are very ugly too):

  • extending the block syntax to optionally predeclare local variables:

(1…10).each usinglocals :a, :i do |i| a=i*i end

  • adding a keyword to declare a local variable:

(1…10).each do |my i| my a; a=i*i end

  • the same, but postdeclaring (?) the parameters as local:

(1…10).each do |i| my i, a; a=i*i; end

I’d prefer a little more verbosity than more special symbols and dangling
semicolons and commas…

Dave Thomas Dave@PragmaticProgrammer.com wrote in message > > In that case, what does the semicolon mean?

It separates parameters from variables which are local to the block.

a = 1
i = 2
(1..10).each do |i|
  a = i*i
end

p a   #=> 100
p i   #=> 10

a = 1
i = 2
(1..10).each do |i;a|
  a = i*i
end

p a   #=> 1
p i   #=> 10

and I assume

a = 1
i = 2
(1..10).each do <i;a>
  a = i*i
end

p a   #=> 1
p i   #=> 2

How about:

a = 1
i = 2

(1…10).each with{a} do |i|
a = i*i
end

p a #=> 100
p i #=> 2

a = 1
i = 2

(1…10).each with{a,i} do |i|
a = i*i
end

p a #=> 100
p i #=> 10

a = 1
i = 2

(1…10).each do |i|
a = i*i
end

p a #=> 1
p i #=> 2

a = 1
i = 2

(1…10).each do with{i} |i|
a = i*i
end

p a #=> 1
p i #=> 10

That is: Modifications to a block variable are visible outside of the
block only if explicitly specified using a ‘with’ cause.

To put it another way, variables are passed into the block “by value”.
Only if specified using a ‘with’ clause are they passed in “by
reference”.
If a variable is passed in “by value” then any changes made to that
variable are restricted to the block; thus we get shadowing for free.

Damon

How about a third section, using the same delimiter:

(1…10).each do |a|b|
# b is local
end

It maintains backwards compatibility, too, because the locals section is
optional.

Only weird case is when you have exclusively locals:
5.times do ||b|
# …
end

but that isn’t so bad, really…

···

On Wed, Jun 12, 2002 at 07:18:22AM +0900, Hal E. Fulton wrote:

I still wish we could use something other than <> for the
new notation. At the least I’d prefer something that didn’t
balance left-right (as || doesn’t). But we run out of
punctuation, don’t we? On American non-APL keyboards,
anyway.


Evan Martin
martine@cs.washington.edu
http://neugierig.org

Hi,

Well, Matz is much smarter than I am… but this
makes me wince.

I don’t think I’m smarter than you. That’s simply my fault that I
cannot explain clear enough mostly due to the language barrier.
I wish I were born in English speaking country. I’ll try to explain
anyway.

Originally, the “|…|” used to be a simple iteration variable
specifier. But when Proc (and closure) was introduced to Ruby (back
in Ruby 0.60 in 1994), I needed block local variables, so I made the
current local variable scoping rule, which is “when a new local
variable appears first in a block, it is valid only in the block”.

And I was wrong. This rule is the single biggest design flaw in
Ruby. You have to care about local variable name conflict, and you
will have totally different result (without error) if they conflict.

So, we are talking about a part of many-year-long effort of fixing
this flaw.

We have following constraints:

  • the fix should not cause fatal compatibility problem. It may not
    cause any problem, or at least may not cause any problem which
    cannot be fixed by the filter program.

  • the fix need not to cover arbitrary combination of local/non-local
    variables in block parameter, so that you don’t need the one like

    a,{b},c| # where a goes block-local

    as someone proposed before. We have two major usage of block
    parameters, a) iterator variables b) closure arguments. The
    current block parameters are suitable (and designed for) a. I
    guess we need a new notation designed for b too.

  • preferably, the above bad scoping rule should be removed from the
    language in the future, so that I guess we need a new notation to
    declare in-block variables.

  • Ruby does not like explicit variable declaration (except method
    arguments, of course), so that a new in-block variable declaration
    is better not be explicit, if possible.

I’ve got a bunch of proposals from worldwide (and from myself). Some
seemed good, Some bad, and some even ugly. Thank you everyone who
joined the discussion anyway. After a long discussion and pondering,
there is the first design choice:

(a-1) do nothing, it’s already a part of the language even though it’s
bad. Stay as it is.

   Pros: least effort.
   Cons: least effectiveness.

(a-2) do something, let’s make Ruby close to the perfect language.

Assuming we choose the latter, I chose several candidates for the fix.
From the constraints, we need two new notations to fix the problem,
one for block parameters and one for in-block variables.

For block parameters (in order of my preference):

(b-1) “<…>” that takes local variables only; they are in-block
local. In addition, it follows basic rules of argument
passing, even optinal argumen may be allowed.

   Pros: it solves several pitfalls of Ruby at once, for example,
         "lambda{|a| p a}.call(1,2,3)" prints "[1,2,3]", because
         it behaves like assignment "a = 1,2,3".  on the other
         hand, "lambda{<a> p a}.call(1,2,3)" will cause an error
         "wrong number of arguments (3 for 1)".
   Cons: it makes Ruby syntax bigger.
         it appears awkward for some eyes.

(b-2) “|…|” should take local variables only, and make them
in-block variables.

   Pros: it makes Ruby syntax simpler.
   Cons: no backward compatibility.

For in-block variables:

(c-1) local variables assigned by “:=” are in-block variables,
otherwise they are method local variables. If you assigns to
an existing local variable, the variable is shadowed, and you
will probably be warned.

(c-2) variables listed after “;” in the block parameters are in-block
variables. If you list an existing local variable, the
variable is shadowed, and you will probably be warned.

   Cons: this is explicit declaration.

(c-3) introduce a method named “let” and use the solution for (b) to
solve the in-block variables problem. For example (in the case
we choose (b-1)):

     lambda{<x,y>   # x,y are local to this closure.
       ...
       let{<a,b,c>
         ....       # a,b,c are local here.
       }
       ...
     }

   Pros: least syntax enhancement.
   Cons: Cons: this is explicit declaration.
         And even uglier (to my eyes).

Man, it took me hours to write this mail. Why you guys don’t read Japanese?

Complaint #1: This introduces an ordering constraint on
the items. If the “natural” order is a,b,c but we need
b to be local, we will write something like |a,c;b|

It won’t happen, since they are different things. “a” and “c” are
block parameters, “b” is an in-block variable.

Complaint #2: The <x;y> case is exceptionally annoying
to me if I understand it correctly. Doesn’t it send two
contradictory messages (to the reader) about x? The fact
that it appears on the lefthand side of the semicolon
says it’s nonlocal; but the fact it’s in brackets says
it’s local.

No. The fact that it appears on the lefthand side of the semicolon
says it’s a block parameter; and the fact it’s in brackets says it’s
in-block local. Get it?

						matz.
···

In message “Re: ruby-dev summary 17252-17356” on 02/06/12, “Hal E. Fulton” hal9000@hypermetrics.com writes:

Hi,

and
5.times do |;a| a=gets; print a end
or
5.times do <;a> a=gets; print a end
?

How about

5.times do a:=gets; print a end

?

Or even

5.times do let{<a=gets>print a} end

?

						matz.
···

In message “Re: ruby-dev summary 17252-17356” on 02/06/12, Carlos angus@quovadis.com.ar writes:

Hey, I like it.

The brace version isn’t quite as pretty, but it’s still fine with me:

(1..10).each { with{i} |i|
a = i*i
}

How about we extend it to block variables as well:

(1..10).each { with{i,a,b} |i|
a = i*i
b = 10
}

“i” and “a” now reference outer variables, b is local.

Of course, we could always use a clause to force locality instead:

(1..10).each { local{b} |i|
a = i*i
b = 10
}

I do like the idea of having block params and variables be localized/de-
localized in the same fashion.

Jim

···

On Thu, 13 Jun 2002 02:02:24 +0900 “Damon” adamon@mailandnews.com wrote:

That is: Modifications to a block variable are visible outside of the
block only if explicitly specified using a ‘with’ cause.

To put it another way, variables are passed into the block “by value”.
Only if specified using a ‘with’ clause are they passed in “by
reference”.
If a variable is passed in “by value” then any changes made to that
variable are restricted to the block; thus we get shadowing for free.

Wed, 12 Jun 2002 10:43:09 +0900, Yukihiro Matsumoto matz@ruby-lang.org pisze:

Assuming we choose the latter, I chose several candidates for
the fix. From the constraints, we need two new notations to fix
the problem, one for block parameters and one for in-block variables.

This is what I will use in some language for anonymous function
parameters:
for x, y do … end
and for creation of a new variable:
var x = initial_value

Maybe some variation of this syntax would fit Ruby.

Man, it took me hours to write this mail. Why you guys don’t read Japanese?

Why don’t you read Polish? :slight_smile:

···


__("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
__/
^^
QRCZAK

Hi,

···

At Wed, 12 Jun 2002 08:06:35 +0900, Evan Martin wrote:

How about a third section, using the same delimiter:

(1…10).each do |a|b|

b is local

end

It maintains backwards compatibility, too, because the locals section is
optional.

It’s parsed as |a| followed by a method/variable `b’ and a
bitwise-or operator now.


Nobu Nakada

In article 1023845919.929356.32025.nullmailer@picachu.netlab.jp,
matz@ruby-lang.org (Yukihiro Matsumoto) writes:

(b-1) “<…>” that takes local variables only; they are in-block
local. In addition, it follows basic rules of argument
passing, even optinal argumen may be allowed.

Is a block parameter allowed as {<&c> …} ?

···


Tanaka Akira

17252-17356)

Man, it took me hours to write this mail.

Thanks very much for writing this, Matz. I am understanding
it better now.

I have printed out this message so I can study it and think
about it more. I think perhaps I will frame it and put it
on the wall by my bed.

Why you guys don’t read Japanese?

Heh heh… when you reduce it to an alphabet of 26 characters,
I will be more inclined to learn it.

When the Pickaxe Book was not yet available, I bought your
book in Japanese, so I could read the code. I accidentally
learned one Japanese symbol, the one for “statement” or
“expression.” I called it the “Blair Witch” character. (You
probably don’t know about that dumb American movie, though.)

Thanks again.

Hal Fulton

···

----- Original Message -----
From: “Yukihiro Matsumoto” matz@ruby-lang.org
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Tuesday, June 11, 2002 8:43 PM
Subject: a new block parameter/variable notation (Re: ruby-dev summary

Not wanting to flog a dead horse, but I just wonder what the final word
on the :a notation was?
Make Your Own Quiz, List or Poll | RubyTalk (and 5568 and 5592)

Personally I thought it was perfect at the time, and after starting to
use arrays of Symbols for various magic tricks, the appeal hasn’t
diminished:

  • small syntax change
  • no problem mixing and matching local versus non-local variables on the
    block side.

Maybe I have misunderstood some of the other approaches, but I get the
sinking feeling that the order that the iterator methods yield the
arguments have bearing on what I can do on the block side. I see that
this problem is really defined away by the constraint, but I fear that
this decision can preempt some useful, future usages. (Though I can’t
think of any good examples now…)

Yukihiro Matsumoto wrote:

Man, it took me hours to write this mail. Why you guys don’t read Japanese?

Working a little bit on that, but at this rate Ruby 3.8 is most likely
to be out before I can make heads or tails of it. :slight_smile:

···


([ Kent Dahl ]/)_ ~ [ http://www.stud.ntnu.no/~kentda/ ]/~
))_student
/(( _d L b_/ NTNU - graduate engineering - 4. year )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

Perhaps:
5.times do new a = gets, print a end

I guess it could break some code though:
do
obj = new a = gets; print obj # self.new() today
end

Jean-Hugues

···

At 10:43 12/06/2002 +0900, matz wrote:

Hi,

In message “Re: ruby-dev summary 17252-17356” > on 02/06/12, Carlos angus@quovadis.com.ar writes:

and
5.times do |;a| a=gets; print a end
or
5.times do <;a> a=gets; print a end
?

How about

    5.times do a:=gets; print a end

?

Or even

    5.times do let{<a=gets>print a} end

?

                                                    matz.

Web: http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17

Or, how about:

5.times do(a) a=gets; print a end

To me, that’s the least surprise. It makes “a” look like a
defined parameter of the do “method” so to speak.

It breaks down with the {} shorthand:

5.times { (a) a=gets; print a }

– Dossy

···

On 2002.06.12, Yukihiro Matsumoto matz@ruby-lang.org wrote:

Hi,

In message “Re: ruby-dev summary 17252-17356” > on 02/06/12, Carlos angus@quovadis.com.ar writes:

and
5.times do |;a| a=gets; print a end
or
5.times do <;a> a=gets; print a end
?

How about

5.times do a:=gets; print a end
?

Or even

5.times do let{<a=gets>print a} end
?


Dossy Shiobara mail: dossy@panoptic.com
Panoptic Computer Network web: http://www.panoptic.com/
“He realized the fastest way to change is to laugh at your own
folly – then you can let go and quickly move on.” (p. 70)

“Yukihiro Matsumoto” matz@ruby-lang.org wrote in

(b-1) “<…>” that takes local variables only; they are in-block
local. In addition, it follows basic rules of argument
passing, even optinal argumen may be allowed.

I am not sure - if I am reading this correctly but it used to be
possible to create Procs with default arguments via Method
objects, now (mswin today’s cvs) this segfaults.

···

class A
def body(x=1); p x end
end

A.new.method(:body).to_proc.call()

/Christoph

Yukihiro Matsumoto wrote:

And I was wrong. This rule is the single biggest design flaw in
Ruby.

Perhaps Rite / Ruby 2+ is a chance to fix this and similiar issues?

I think sometimes, non-backwards-compatible changes are OK, if done in a
transparent way.
People can continue to use Ruby 2- programs with 2- interpreter
versions, and update to 2+ versions as soon as the need arises, by
making some changes to the existing programs.

Tobi

···


http://www.pinkjuice.com/

and
5.times do |;a| a=gets; print a end
or
5.times do <;a> a=gets; print a end
?

How about

5.times do a:=gets; print a end
?

The ‘:=’ is nice, but it will become more complicated if later you decide to
add variable initialization (you can not initialize a block variable with
‘:=’ (as I understand(?) it) because it is assigned in every iteration).

Or even

5.times do let{<a=gets>print a} end
?

And here I can not initialize ‘a’ only one time for the 5 iterations.

I’m pointing specifically at a problem that other posted before: when you
need to initialize the local variable with an external object, only once:

now:

p = list
5.times do p p; p=p.next end
list = nil # elements from 6th forward won’t be destroyed until I do:
p = nil

with <> (if we can initialize):

5.times do <;p=list> p p; p.next end
list = nil # ok, nothing points to the 6th element

And with my proposals I will not make examples because I know you don’t like
them :wink:

“James F.Hranicky” jfh@cise.ufl.edu wrote

That is: Modifications to a block variable are visible outside of the
block only if explicitly specified using a ‘with’ clause.

To put it another way, variables are passed into the block “by value”.
Only if specified using a ‘with’ clause are they passed in “by
reference”.
If a variable is passed in “by value” then any changes made to that
variable are restricted to the block; thus we get shadowing for free.

Hey, I like it.

The brace version isn’t quite as pretty, but it’s still fine with me:

(1..10).each { with{i} |i|

a = i*i
}

I’d actually meant for the ‘with’ clause to appear outside of the
block. Perhaps that might make the brace version a little prettier?

a = 1
i = 2

(1…10).each with{i} { |i|
a = i*i
}

p a # → 1
p i # → 10

How about we extend it to block variables as well:

(1..10).each { with{i,a,b} |i|

a = i*i
b = 10
}

“i” and “a” now reference outer variables, b is local.

I had also intended for block variables not specified in the ‘with’
clause to always be local. Thus in the above example, ‘b’ would not
be local to the block:

a = 1
i = 2
b = 3 # b defined outside of the block prior to executing the block

(1…10).each with{i,a,b} { |i|
a = i*i
b = 10
}

p a # → 100
p i # → 10
p b # → 10

a = 1
i = 2
# b not defined outside of the block

(1…10).each with{i,a,b} { |i|
a = i*i
b = 10
}

This should raise an error, because b is expected to be defined when

the ‘with’ clause is run.

To make ‘b’ local to the block, simply leave it out of the ‘with’
clause.
Thus:

a = 1
i = 2
b = 3 # b defined outside of the block prior to executing the block

(1…10).each with{i,a} { |i|
a = i*i
b = 10
}

p a # → 100
p i # → 10
p b # → 3

or:

a = 1
i = 2
# b not defined outside of the block

(1…10).each with{i,a} { |i|
a = i*i
b = 10 # b defined only inside block, making it block local
}

p a # → 100
p i # → 10
p b # error: undefined variable ‘b’

Of course, we could always use a clause to force locality instead:

(1..10).each { local{b} |i|

a = i*i
b = 10
}

I do like the idea of having block params and variables be localized/de-
localized in the same fashion.

Unfortunately, this looks a little too much like a variable
declaration for my taste. The default behavior is to have all
variables in a block local to the block, unless specified with a
‘with’ clause. The ‘with’ clause can be likened to an “accessor” for
variables that are private to the block. If the variable is not
specified in the ‘with’ clause then it should remain private to the
block, or local to the block.

By adopting this rule, we can do away with variable declarations
altogether, using lexical scoping rules to determine a variable’s
visiblity and ‘with’ clauses to determine if changes made to a
variable inside a block are propagated outside of the block.

To summarize:

  1. Variables in the outer body are “passed by reference” if specified
    in a ‘with’ clause, passed “by value” otherwise. Thus changes to
    the variable are propagated back to the outer body if the variable
    is specified in the ‘with’ clause.

  2. A variable is local to the block, if it is defined in the block
    and does not appear in the ‘with’ clause of the block.

  3. Changes to a variable defined in the outer body are local to the
    block if the variable does not appear in the ‘with’ clause of the
    block.

I suppose one can invert the functionality and have instead a
‘without’
clause, which would mean the same thing as a ‘local’ clause. Ie, now
we have variables passed in by reference, unless they are specified in
the ‘without’ clause, in which case they would be passed in by value.

a = 1
i = 2

(1…10).each without{i} { |i|
a = i*i
}

p a # → 100
p i # → 2

a = 1
i = 2

or equivalently,

a = 1
i = 2

(1…10).each local{i} { |i|
a = i*i
}

p a # → 100
p i # → 2

So in the absence of a ‘without’ or ‘local’ clause, we get pass by
reference

a = 1
i = 2

(1…10).each { |i|
a = i*i
}

p a # → 100
p i # → 10

which conforms to current behavior.

However, I think it’s better to use ‘with’ clauses rather than
‘without’ clauses, as it is safer to default to pass-by-value rather
than pass-by-reference.

Damon

···

“Damon” adamon@mailandnews.com wrote:

matz@ruby-lang.org (Yukihiro Matsumoto) wrote in message news:1023845919.929356.32025.nullmailer@picachu.netlab.jp

(c-1) local variables assigned by “:=” are in-block variables,
otherwise they are method local variables. If you assigns to
an existing local variable, the variable is shadowed, and you
will probably be warned.

Matz, what about making this distinction more general than just
block-local vs. method local? That is, always be able to use := to
create a new binding rather than modifying an existing one. So, if
you had

def foo
x := 1
y := 2
myproc = lambda{p x, y}
x := 10
y = 20
myproc.call
end

#=> 1
#=> 20

Bindings would be scoped to thier closest enclosing method or block;
using = when no binding already existed for the variable would be the
same as using :=.

My main motivation for wanting this is to ease state management when
using continuations for backtracking - creating new bindings is
obviously safer here than mutating existing ones.

Too lispy?

Alternatively, I wouldn’t mind seeing an ML-style

let x = 1 in

end

But the := thing is probably more Ruby like.

Avi

Hello,

about scope design,

Perhaps:
xx do local xxx end
xx do xxx end

after “local” a new scope rule starts applying.

For block parameters:
xx.each do local |x| xxx end

For block variables:
x,y,z = 1,2,3
(Proc.new do
x = 0 # outer x
p x # 0
local # new scope rule starts here
x,y = 2,3 # outer x, local y
p x,y,z # 2,3,nil versus 2,3,3 without “local”
).call
p x,y,z # 2,2,3 versus 2,3,3 without “local”

Also (orthogonal): global
xx do xxx global; xxx end
Ideally: unbound
xxx do global; local; xxx end
eqv xxx do unbound; xxx end

Also: local but with initial values
do local a,b,c |x| xxx end
where a,b,c are initialized with whatever value they
had before.

Also: local but initialized at block creation time:
do unbound a,b |z| xxx end
a,b will be local but initialized with whatever value
they had when the block was created.

Yours,

Jean-Hugues

I vote for these two at least.

Yukihiro Matsumoto wrote:

···

(a-2) do something, let’s make Ruby close to the perfect language.

(b-2) “|…|” should take local variables only, and make them
in-block variables.

   Pros: it makes Ruby syntax simpler.
   Cons: no backward compatibility.