Rite, Block locals and Autovivification

Perl has what may be an evil solution block locals.

Certainly maximal surprise but Does What I Mean…

What does the bit of Perl
$a{foo}++
do?

Well, you clearly are referring to a hash, so it makes one.

Since foo doesn’t have a sigil, it takes it as a string…
$a{‘foo’}++

Since the element doesn’t exists yet, and we’re adding one to it, it
"autovivifies" or “magically grants life” to it. Namely 0. Perl chose 0
since that is “What I Mean” when I add one to and uninitialised something.

Now to Ruby…

def each_anime(io)
io.each do |line|
next unless line =~ /evangelion|omg|spirited/
l = line.length # l is just local to block
map[$1] = line # Autovivifies map as Hash
count += 1 # Auto vivifies as 0 on first pass, an gives it scope
# beyond block.
weight *= 0.2 # Autovivifies as 1

yield line

end

l is out of scope here

[count,weight,map] # Visible at function scope as autovivified.
end

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

A Million Monkeys can inflict worse things than just Shakespeare on
your system.

Just my personal feeling… but I’d hope to avoid stuff like this in
ruby.
It is fun, powerful and absolutely intrinsic and hard to understand.
[1]

I’m not saying this is really bad, just I’d prefer this does’nt
appear.
I strongly believe ‘explicit is better than implicit’.
plus, a single line:
map, count,weight={},0,1
would make this work. Not so much a big cost for me :slight_smile:

[1]
If you’re going to say ‘no, let me explain, this is really clean and
intuitive’ please consider that i really think this is hard to grasp
:slight_smile:

···

il Tue, 2 Dec 2003 06:35:18 +0900, John Carter john.carter@tait.co.nz ha scritto::

Perl has what may be an evil solution block locals.

Certainly maximal surprise but Does What I Mean…

Hi –

···

On Tue, 2 Dec 2003, John Carter wrote:

Perl has what may be an evil solution block locals.

Certainly maximal surprise but Does What I Mean…

[…]

I’m sorry but I don’t think I understand your post. Are you asking
about how 2.0 is going to handle scope? I couldn’t quite follow.

David


David A. Black
dblack@wobblini.net

Now I reread my post I see I didn’t make myself explicit. Sorry.

There has been debate on how to resolve the ugly problem of local’s in
Ruby in V2.0.

The suggestion I’m making is add autovivification, with the rule that
if a block local needs autovivifying you probably mean it to have
larger than block scope. (Since there is an implicit “local_var =
SomeClass.new” before the block)

This makes for very terse code.

def histogram( enum)

<— Implicit hash = Hash.new(0) here

enum.each{|e| hash[e]+=1} # Hash autovivifies.

Since hash autovivified we expect it to be available

outside the block scope.

hash.keys.sort{|a,b| hash[a]<=>hash[b]}.each do |k|
puts “#{k}\t#{hash[k]}”
end
end

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

A Million Monkeys can inflict worse things than just Shakespeare on
your system.

···

On Tue, 2 Dec 2003, David A. Black wrote:

Hi –

On Tue, 2 Dec 2003, John Carter wrote:

Perl has what may be an evil solution block locals.

Certainly maximal surprise but Does What I Mean…

[…]

I’m sorry but I don’t think I understand your post. Are you asking
about how 2.0 is going to handle scope? I couldn’t quite follow.

Hi,

def histogram( enum)

<— Implicit hash = Hash.new(0) here

enum.each{|e| hash[e]+=1} # Hash autovivifies.

eh? But… somevar[e] … Why would Ruby assume I wanted a Hash
object? That could be an Array, or a String, or…

Do you mean the autovivification would happen only if the variable
was actually named ‘hash’ ?

Or am I not understanding your example?

Since hash autovivified we expect it to be available

outside the block scope.

hash.keys.sort{|a,b| hash[a]<=>hash[b]}.each do |k|
puts “#{k}\t#{hash[k]}”
end
end

Regards,

Bill

···

From: “John Carter” john.carter@tait.co.nz

John Carter wrote:

def histogram( enum)

<— Implicit hash = Hash.new(0) here

enum.each{|e| hash[e]+=1} # Hash autovivifies.

Since hash autovivified we expect it to be available

outside the block scope.

hash.keys.sort{|a,b| hash[a]<=>hash[b]}.each do |k|
puts “#{k}\t#{hash[k]}”
end
end

How do you know that hash needs to be a hash? Depending on what enum is,
it could be an array or something else even.

As I understand it, variables first assigned to in a block in 2.0 are
equivalent to
variables in 1.8 with an implicit var = nil before the block, so they’re
visible
outside the block. Autovivifying to something other than nil seems more
dangerous
than it would be worth to me.

  • Dan

Autovivification in Perl is simplified by the fact that in the case
of “$a{$b}” Perl knows from the ‘{’ that a hash is involved.

In Ruby, it is not so easy, but clearly “a[b]” doesn’t make sense if
a.kind_of? Array and !b.kind_of?( FixNum), so “Do What I Mean” says you
should autovivify a Hash if appropriate.

Likewise whether in Perl “$a{$b}++” or ruby “a[b]+=1” the element at a[b]
should be autovivified as 0.

In the case of
a[b]*=c
the only thing that makes sense is if a[b] autovivified as 1

···

On Wed, 3 Dec 2003, Bill Kelly wrote:

Hi,

From: “John Carter” john.carter@tait.co.nz

def histogram( enum)

<— Implicit hash = Hash.new(0) here

enum.each{|e| hash[e]+=1} # Hash autovivifies.

eh? But… somevar[e] … Why would Ruby assume I wanted a Hash
object? That could be an Array, or a String, or…

Do you mean the autovivification would happen only if the variable
was actually named ‘hash’ ?

Or am I not understanding your example?

Since hash autovivified we expect it to be available

outside the block scope.

hash.keys.sort{|a,b| hash[a]<=>hash[b]}.each do |k|
puts “#{k}\t#{hash[k]}”
end
end

Regards,

Bill

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

A Million Monkeys can inflict worse things than just Shakespeare on
your system.

John Carter wrote:

In Ruby, it is not so easy, but clearly “a[b]” doesn’t make sense if
a.kind_of? Array and !b.kind_of?( FixNum), so “Do What I Mean” says you
should autovivify a Hash if appropriate.

But you don’t know what enum is until the method is called, so is your
autovivification code really
going to look like:

if enum[0].kind_of? FixNum
hash = Array.new(0)
else
hash = Hash.new(0)
end

? But you really need to test all the elements on enum, because it
doesn’t have to have all the same
type of elements. Also, Hashes can take FixNums as indicies, so who’s
to say I didn’t actually want
a hash, especially since you were sorting using keys and values later,
so if someone mistakenly passed
in an Enumerable containing only FixNums, your code would break.

Likewise whether in Perl “$a{$b}++” or ruby “a[b]+=1” the element at a[b]
should be autovivified as 0.

In the case of
a[b]*=c
the only thing that makes sense is if a[b] autovivified as 1

Why does only 1 make sense? It would also be fine to say that

a[b] *= c
p a[b] # => 0

is the proper interpretation, in that all FixNums autovivify to have an
initial value of 0, rather than
having a value after assignment of whatever was used.

Really, all these autovivification decisions are arbitrary, and having
variables autovivify depending
on how they’re used would likely require a lot of extra analysis. Isn’t
it more consistant to make
things autovivify always as nil, in cases where that’s required (like
“bar = bar; p bar”, apparently)?

  • Dan