In Ruby, the typical way to define a class is using the class
keyword:
class Foo # ... end
The class keyword, however, is effectively just syntax sugar for the Class constructor:
Foo = Class.new # ... end
Using Class.new
is occasionally preferable, e.g. when you want an anonymous class which isn’t assigned to a constant:
@myclass = Class.new # ... end
I like to use this technique for certain metaprogramming tasks, and when testing/spec-ing modules:
describe MyModule before :each do @test_class = Class.new do include MyModule end end # ... end
There are a few subtle semantic differences between the class
keyword and Class.new
. Because the Class constructor uses a block to define the contents of the class, it can reference the surrounding lexical scope:
>> method_name = "foo" => "foo" >> class KeywordClass >> define_method(method_name) do ?> puts "hello" >> end >> end NameError: undefined local variable or method `method_name' for KeywordClass:Class from (irb):3 >> DynamicClass = Class.new do ?> define_method(method_name) do ?> puts "hello" >> end >> end => DynamicClass >> DynamicClass.new.foo hello => nil
I’d known about this difference for a long time. The other day I came across another difference between these two methods of class definition which was new to me, and can lead to potentially surprising behavior. It concerns the order of execution and the .inherited() callback.
When a parent class defines a class method called inherited
:
class A def self.inherited(other) puts "in A.inherited" end end
And then that class is subclassed:
class B < A puts "in class B body" end
The order of execution is 1) run the A.inherited
callback; then 2) execute the class definition body. You can see this if you run the above two blocks; the output will be:
in A.inherited in class B body
If, however, we try to inherit from A dynamically, using the Class constructor:
C = Class.new(A) do puts "in class C body" end
The output is reversed:
in class C body in A.inherited
I’m not sure if either of these behaviors is right or wrong, per se; but it can catch you by surprise if you are expecting dynamic class definition to have the same order of operations as the keyword form. In particular, it can lead to some confusing side effects when using certain libraries that extend the behavior of Ruby’s classes. For instance, I discovered this difference while working on some code that used the class-inheritable attributes feature of ActiveSupport:
myclass = Class.new do class_inheritable_accessor :bar self.bar = 42 end
>> myclass.bar => nil >> # hey! where'd the value of bar go?!
As it turns out, class_inheritable_accessor
and its friends work by defining Object.inherited
to initialize some variables that ActiveSupport uses for bookkeeping. In the dynamic form of the class definition, the class body would assign values to the inheritable attributes – and then Object.inherited
would be called back, re-initializing the variables and wiping out my assigned values. The solution was to separate the class creation and definition into two steps:
myclass = Class.new myclass.instance_eval do class_inheritable_accessor :bar self.bar = 42 end
So there you go, another, lesser-known semantic distinction between “static” and “dynamic” class definition in Ruby.
Wow, I wrote a long comment… about as long as the original post.
Avdi,
Thanks for sharing. I ran into this todo when refactoring some examples. It seems so odd that the order in which .inherited is called changes depending on how you construct the class.
Avdi,
Thanks for sharing. I ran into this todo when refactoring some examples. It seems so odd that the order in which .inherited is called changes depending on how you construct the class.
Avdi, it looks like this behaviour was changed in 1.9. The output is no longer reversed when you do Class.new(A) { … }.
Yay!