Questionable behavior


#1

I’m getting some very strange behavior from a conditional statement –
I can;t imagine how it is happeneing and I wondering if I stumbled upon
some sort of bug in Ruby. Although I have no idea how it could even
occuer, perhaps someone else can see it. Here’s the code:

p pkg
p pkg.gem
p pkg.gem
if pkg.gem
p “HERE”
pkg = pkg.merge( pkg.gem )
end
p pkg

This prints

#<OpenObject…>
nil
nil
nil

Notice it does not print “HERE” yet by that last print pkg has somehow
become nil! Note that I repeated ‘p pkg.gem’ to show that it has
nothing to do with calling this statment. Now if I remark out the pkg
assignment:

p pkg
p pkg.gem
p pkg.gem
if pkg.gem
p “HERE”
#pkg = pkg.merge( pkg.gem )
end
p pkg

I get

#<OpenObject…>
nil
nil
#<OpenObject…>

As it should be. How is this possible?

FYI
Ubuntu Linux
ruby 1.8.4 (2005-12-24) [i486-linux]

Thanks,
T.


#2

On May 26, 2006, at 9:54 AM, removed_email_address@domain.invalid wrote:

  p "HERE"

  #pkg = pkg.__merge__( pkg.gem )

As it should be. How is this possible?
I’d be happy to test it here and see if I can replicate it. But I
don’t know what an OpenObject is.
-Mat


#3

Hi,

On Fri, 26 May 2006 15:54:21 +0200, removed_email_address@domain.invalid wrote:

I’m getting some very strange behavior from a conditional statement –
I can;t imagine how it is happeneing and I wondering if I stumbled upon
some sort of bug in Ruby. Although I have no idea how it could even
occuer, perhaps someone else can see it. Here’s the code:

No, that is no bug, it’ a feature :wink:

here pkg is a method call

p pkg
p pkg.gem
p pkg.gem
if pkg.gem
p “HERE”
after this line pkg is a local variable (because you assign to it)
pkg = pkg.merge( pkg.gem )
end
unintialized local variables default to nil, so it prints nil
p pkg

This prints

#<OpenObject…>
nil
nil
nil

If you want the method call you can use pkg().

Here is another example:

$ cat lvar_tst.rb
def a
“method”
end

def test
p a
p a()
if false
a = 23
end
p a
p a()
end

test
$ ruby lvar_tst.rb
“method”
“method”
nil
“method”

This is just the way Ruby (it’s parser) handles local variables, but I
think matz said that this will be made more “consistent” in future
versions (i.e. if something is a lvar at some point in a scope it will
be
an lvar everywhere in this scope and you might get a warning for your
above code, like “use of lvar before initialization”)

Hope that helps,
Dominik


#4

It would be tricky to run the test in that the code is pretty deep
inside my application. If your willing though I would be happy to send
you the whole package to try. FYI, it’s the Reap project.

OpenObject is similar to OpenStruct and can be found in Ruby F.s.

Thanks,
T.


#5

Dominik B. wrote:

I’m getting some very strange behavior from a conditional statement –
I can;t imagine how it is happeneing and I wondering if I stumbled upon
some sort of bug in Ruby. Although I have no idea how it could even
occuer, perhaps someone else can see it. Here’s the code:

No, that is no bug, it’ a feature :wink:

Oh, I love those kind of “features”… NOT!

This is just the way Ruby (it’s parser) handles local variables, but I
think matz said that this will be made more “consistent” in future
versions (i.e. if something is a lvar at some point in a scope it will be
an lvar everywhere in this scope and you might get a warning for your
above code, like “use of lvar before initialization”)

Why does it do this and why is that a good solution? How unintuitive
can it possibly be? Why doesn’t it just convert the refernce to a lvar
when it evaluates? Why does the parser have to look ahead and
pre-judge the reference. You got code evaluating in a false condition
–so anti-dynamic!

Sigh. Okay so referncing it as a local var --EVEN IN UNEVALUATED CODE
changes a refernce to a local variable. Great! I was trying to take
advantage of the isomorphism of local vars and metods --which I thought
WAS a feature. So much for that.

Thanks Dominik,
T.


#6

Ah, despite my rant, there is an easy solution. And it makes it very
clear the oddness of the way Ruby parser work here:

  if pkg.gem
    pkg = pkg.__merge__( pkg.gem )
  else
    pkg = pkg
  end

It won’t work without the ‘pkg = pkg’.

T.


#7

Sounds like it’s pretty wrapped up. Interesting fix. And something
to keep in mind for later. Hopefully later version of ruby will
print warnings on this sort of thing.
-Mat