Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: On what defining a class evaluates to

Tags:

ruby

In Ruby, why does defining a class evaluate to nil? Same goes for defining a method: why does it evaluate to nil? Wouldn't it be useful if defining a class would evaluate as the class?

like image 331
wilhelmtell Avatar asked Dec 18 '22 00:12

wilhelmtell


1 Answers

In Ruby, why does defining a class evaluate to nil?

It doesn't.

First off, in Ruby you don't define a class, you execute a class body. Secondly, executing a class body does not evaluate to nil as you claim, it evaluates to the value of the last expression inside the class body. This is perfectly consistent with executing a module body and executing a method body.

See, for example:

class Foo
  'Hello'
end
# => 'Hello'

Same goes for defining a method: why does it evaluate to nil?

Actually, it doesn't either. Defining a method evaluates to an implementation-defined value. The reason why it evaluates to an implementation-defined value is that so far the Ruby community hasn't reached a consensus on what it should return.

Some argue that it should evaluate to the CompiledMethod object corresponding to that method. That's what Rubinius does. However, there is a problem with this: not all Ruby implementations compile their methods. And not all of them that do compile them, compile them at definition time. JRuby, for example, only compiles them when they are executed, more precisely after they have been executed 20 times. Sometimes it doesn't compile them at all, for example in environments where compilation is forbidden such as Google App Engine. Also, not all Ruby implementations do have a Ruby representation for their compiled methods. And even if they did, their compiled methods are vastly different: Rubinius's compiled methods are Rubinius bytecode, YARV's compiled methods are YARV bytecode, JRuby's compiled methods are JVM bytecode, IronRuby's compiled methods are DLR trees. And of course the most widely used implementation, MRI, doesn't even have a compiler.

Others say, it should evaluate to the UnboundMethod object corresponding to that method. Here, the problem is that there is no single UnboundMethod object corresponding to a method. There's infinitely many of them. Ruby methods aren't objects. They can be converted to objects, but they aren't objects themselves. And when they are converted to objects, they generate a new object every time. So, the UnboundMethod object that would be returned is really not directly related to the method that was defined. Also, what would you want to do with an unbound method? The only case where I use an unbound method is to wrap an already existing method that I cannot modify; but if I have access to the definition anyway, then I don't need to wrap it.

A third group says that defining a method should evaluate to its name. This seems to be a somewhat arbitrary choice. In fact, I have not seen any compelling reason for why this should be the case. Literally the only argument is that this would allow you to make Ruby look more like Java:

# here's how you make a single method private today
def foo(bar) end
private :foo

# instead you could do this:
private def foo(bar) end

So, basically, the reason why method definitions return an implementation-defined value (which on most implementations is just nil) is that nobody has come up with a better suggestion.

Interestingly, Module#define_method does return something useful. If you use a method to define a method, it returns the old method. If you use a proc to define a method it returns a variation of that proc. If you use a block to define a method, it returns a proc corresponding to that block. In other words, it returns an executable object that corresponds to the method body:

class Foo
  $bar  = ->{}
  $baz  = define_method :baz, $bar

  $qux  = instance_method :baz
  $quux = define_method :quux, $qux

  define_method :corge do;end
end
# => #<Proc:0x1cda900@(irb):8 (lambda)>

$bar.eql?   $baz  # => true
$bar.equal? $baz  # => false
$qux.equal? $quux # => true

Wouldn't it be useful if defining a class would evaluate as the class?

Why? The way it is now, class bodies can return anything you want, including the class. With your suggestion, it could return only the class, so it would be strictly less powerful.

Also, the only case were I ever needed a class body to return the class itself, was for getting a reference to the singleton class of an object, like this:

foo = Object.new
foo_singleton_class = class << foo; self end

Or the more well-known pattern:

class Object; def singleton_class; class << self; self end end end

But now that Object#singleton_class is part of the core library, that is no longer necessary.

like image 65
Jörg W Mittag Avatar answered Dec 19 '22 12:12

Jörg W Mittag