Forum: Ruby-core Constant lookup in class eval (appeal)

428167a3ec72235ba971162924492609?d=identicon&s=25 Yehuda Katz (wycats)
on 2009-07-18 05:22
(Received via mailing list)
Matz,
One of the biggest breaking changes in Ruby 1.9 is the change in
constant
lookup inside a proc that is *_eval'ed.

For instance,

*1.8*
*
*
class Foo
  class Bar
  end
  def evaluate(&blk) instance_eval(&blk) end
end

Foo.new.evaluate { Bar }
NameError: uninitialized constant Bar

*1.9*

class Foo
  class Bar
  end

  def evaluate(&blk) instance_eval(&blk) end
end

Foo.new.evaluate { Bar }
=> Foo::Bar


The 1.9 behavior is understandable if everything is in one file.
However, in
the normal case, instance_eval is used to implement DSLs. For instance,
rspec has the following semantics:

module RubyFun
  class Foo
  end

  describe ("Foo") do
    it("exists") do
      lambda { Foo }.should_not raise_error
    end
  end
dnc

This test passes in 1.8 but not in 1.9 because of the change in
behavior. It
also clearly articulates the *reason* for the 1.8 behavior: it is more
the
expected behavior. One of the things that's great about Ruby is that it
focuses on programmer understanding, even if that is sometimes slow.
This is
a case where the programmer expects to see a constant but it is being
looked
up somewhere the programmer knows nothing about. I think it is clear
that
the old behavior is better, even if it is harder to implement.
Additionally,
both JRuby and Rubinius were able to implement the old behavior in a
compiled system, so it should be possible.

Thanks for your time.
F1d37642fdaa1662ff46e4c65731e9ab?d=identicon&s=25 Charles Nutter (headius)
on 2009-07-18 07:39
(Received via mailing list)
On Fri, Jul 17, 2009 at 10:19 PM, Yehuda Katz<wycats@gmail.com> wrote:
> This test passes in 1.8 but not in 1.9 because of the change in behavior. It
> also clearly articulates the reason for the 1.8 behavior: it is more the
> expected behavior. One of the things that's great about Ruby is that it
> focuses on programmer understanding, even if that is sometimes slow. This is
> a case where the programmer expects to see a constant but it is being looked
> up somewhere the programmer knows nothing about. I think it is clear that
> the old behavior is better, even if it is harder to implement. Additionally,
> both JRuby and Rubinius were able to implement the old behavior in a
> compiled system, so it should be possible.

As I understand it, this change was actually made *on purpose*. A key
example of when this is useful is for programmatic class definitions:

class Foo
  Bar = 1
end

xyz = Class.new(Foo) do
  puts Bar
end

Under Ruby 1.8.x, this raises an error because Bar can't be found.
Under 1.9, because constant lookups within a block get re-scoped to
their actual execution context (a subclass of Foo), it prints out '1'.

This is actually very useful, since constants now actually follow the
runtime scoping of their execution context rather than only following
their lexical scoping. But I also agree that it's a fairly major
breaking change, since it can drastically change existing code that
expected the old behavior:

I don't have a good solution for you. This is one of those language
changes that makes existing libraries really hard to support across
Ruby versions. Of course I and others have argued for a way to isolate
version-specific releases in RubyGems, but that has regularly been
shot down. So as it stands today, you can't release a separate 1.9
version of a RubyGem, even though changes like this may make it very
difficult to support a single gem portably.

- Charlie
428167a3ec72235ba971162924492609?d=identicon&s=25 Yehuda Katz (wycats)
on 2009-07-18 08:03
(Received via mailing list)
Charlie,
I actually spoke with Matz and Koichi at lunch today and Matz said he
agrees
that we should eventually roll back the change (he's not sure when
though).

The problem with this change is that it helps people who are intimately
familiar with Ruby at the expense of the lay Ruby programmer. It's
pretty
easy to work around the problem you showed when writing frameworks, but
very
confusing for users who intuitively expect blocks to have lexically
scoped
lookup.

-- Yehuda

On Sat, Jul 18, 2009 at 2:38 PM, Charles Oliver Nutter
This topic is locked and can not be replied to.