Forum: Ruby-core [ruby-trunk - Bug #6151][Open] BasicObject instance_eval of lambda causes errors

Posted by Thomas Sawyer (7rans)
on 2012-03-15 22:09
(Received via mailing list)
Issue #6151 has been reported by Thomas Sawyer.

----------------------------------------
Bug #6151: BasicObject instance_eval of lambda causes errors
https://bugs.ruby-lang.org/issues/6151

Author: Thomas Sawyer
Status: Open
Priority: Normal
Assignee:
Category: core
Target version:
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
  from (irb):44:in `block in irb_binding'
  from (irb):16:in `instance_eval'
  from (irb):16:in `initialize'
  from (irb):46:in `new'
  from (irb):46
  from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use `Proc.new` instead of `lambda` it works. But since I am using 
`#instance_eval` to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to `name 
'Tommy'`.
=end
Posted by Thomas Sawyer (7rans)
on 2012-03-15 22:13
(Received via mailing list)
Issue #6151 has been updated by Thomas Sawyer.


That's fun, go to report a bug in Ruby and hit a bug in Ruby's Bug 
tracker.

Try again, this time with no RD crap.

Given:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

      data = {}
      blk = lambda do
        name 'tommy'
      end

      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)

But it works if we use:

      blk = Proc.new do
        name 'tommy'
      end

Since BlockParser is using instance_eval, I don't see why this should be 
an error. Indeed, how can I depend on it if my API simply accepts a 
block --I don't know if it's a Proc or a lambda.


----------------------------------------
Bug #6151: BasicObject instance_eval of lambda causes errors
https://bugs.ruby-lang.org/issues/6151#change-24618

Author: Thomas Sawyer
Status: Open
Priority: Normal
Assignee:
Category: core
Target version:
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
  from (irb):44:in `block in irb_binding'
  from (irb):16:in `instance_eval'
  from (irb):16:in `initialize'
  from (irb):46:in `new'
  from (irb):46
  from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use `Proc.new` instead of `lambda` it works. But since I am using 
`#instance_eval` to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to `name 
'Tommy'`.
=end
Posted by Nobuyoshi Nakada (nobu)
on 2012-03-15 22:59
(Received via mailing list)
Issue #6151 has been updated by Nobuyoshi Nakada.

Description updated


----------------------------------------
Bug #6151: BasicObject instance_eval of lambda causes errors
https://bugs.ruby-lang.org/issues/6151#change-24619

Author: Thomas Sawyer
Status: Open
Priority: Normal
Assignee:
Category: core
Target version:
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by Nobuyoshi Nakada (nobu)
on 2012-03-16 04:00
(Received via mailing list)
Issue #6151 has been updated by Nobuyoshi Nakada.

Subject changed from BasicObject instance_eval of lambda causes errors 
to ArgumentError of lambda shows wrong location
Target version set to 2.0.0

You need to indent with spaces, before tabs.
----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-24622

Author: Thomas Sawyer
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by Nobuyoshi Nakada (nobu)
on 2012-03-16 04:30
(Received via mailing list)
Issue #6151 has been updated by Nobuyoshi Nakada.

Status changed from Open to Closed
% Done changed from 0 to 100

fixed in r35051-r35053.
----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-24626

Author: Thomas Sawyer
Status: Closed
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by John Firebaugh (Guest)
on 2012-03-16 04:42
(Received via mailing list)
Issue #6151 has been updated by John Firebaugh.


The reason it raises an error is that instance_eval yields one argument 
(the receiver), and lambdas are strict about arity -- see #2476.
----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-24627

Author: Thomas Sawyer
Status: Closed
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by Thomas Sawyer (7rans)
on 2012-03-16 19:17
(Received via mailing list)
Issue #6151 has been updated by Thomas Sawyer.


Just to be clear, where both issues fixed? i.e. the fact that an error 
was raised in this case at all, as well as the location of lambda 
errors?

----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-24657

Author: Thomas Sawyer
Status: Closed
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by John Firebaugh (Guest)
on 2012-03-16 19:19
(Received via mailing list)
Issue #6151 has been updated by John Firebaugh.


Just the location was fixed. The error is "by design" -- as you 
discovered, you will need to use Proc.new (or lambda {|*| ... }).
----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-24658

Author: Thomas Sawyer
Status: Closed
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by Thomas Sawyer (7rans)
on 2012-03-16 20:24
(Received via mailing list)
Issue #6151 has been updated by Thomas Sawyer.


How can that be by design? What kind of design criteria says that 
"instance_eval should blow up if a lambda is passed to it"?

So you are saying that instance_eval passes the receiver into the Proc 
as an argument? Why would it do this when the Block has zero arity? Why 
not just check the arity of the block and pass it if it can take an 
argument otherwise not?

This snafu is really ashame for me too, b/c I finally had a good reason 
to use Ruby 1.9's `->` operator!

----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-24660

Author: Thomas Sawyer
Status: Closed
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Posted by TylerRick (Tyler Rick) (Guest)
on 2013-03-05 18:50
(Received via mailing list)
Issue #6151 has been updated by TylerRick (Tyler Rick).


I agree, @trans, this is a very surprising behavior. I was expecting 
instance_eval to call the block I passed to it without any args. Since 
self is already implicitly available from the block, I just don't 
understand why instance_eval would yield self as an argument.

Fortunately, I think instance_exec 
<http://ruby-doc.org/core-2.0/BasicObject.html#meth... 
does what we are wanting so I'm using it instead.

We should update the documentation. 
http://ruby-doc.org/core-2.0/BasicObject.html#meth... 
does not mention that it yields self as the first argument.
----------------------------------------
Bug #6151: ArgumentError of lambda shows wrong location
https://bugs.ruby-lang.org/issues/6151#change-37314

Author: trans (Thomas Sawyer)
Status: Closed
Priority: Normal
Assignee:
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]


=begin

Perhaps there is a reason, but it sure seems like a bug to me. Given 
this simple class:

      #
      class BlockParser < BasicObject
        def initialize(data={}, &block)
          @data = data
          instance_eval(&block)
        end

        def method_missing(name, *args, &block)
          if block
            @data[name] = {}
            BlockParser.new(@data[name], &block)
          else
            case args.size
            when 0
              @data[name]
            when 1
              @data[name] = args.first
            else
              @data[name] = args
            end
          end
        end
      end

Then we can do:

      data = {}
      BlockParser.new(data) do
        name 'Tommy'
      end
      data #=> {:name=>'Tommy'}

But,

      data = {}
      blk  = lambda do
        name 'Tommy'
      end
      BlockParser.new(data, &blk)
      ArgumentError: wrong number of arguments (1 for 0)
        from (irb):44:in `block in irb_binding'
        from (irb):16:in `instance_eval'
        from (irb):16:in `initialize'
        from (irb):46:in `new'
        from (irb):46
        from /home/trans/.rbfu/rubies/1.9.3-p0/bin/irb:12:in `<main>'

If I use (({Proc.new})) instead of (({lambda})) it works. But since I am 
using (({#instance_eval})) to evaluate the Proc, that shouldn't matter.

Note the reported line number of the error corresponds to (({name 
'Tommy'})).
=end
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.