I am trying to understand concepts of including or inheriting a module inside a class. Whenever I read i get new ways to include or inherit a module inside a class. So just want to know how many ways are there. Here are the examples I am sharing:
Example 1
module TimeExtensions
refine Fixnum do
def minutes; self * 60; end
end
end
class MyApp
using TimeExtensions
def initialize
p 2.minutes
end
end
Example 2
VAL = 'Global'
module Foo
VAL = 'Foo Local'
class Bar
def value1
VAL
end
end
end
class Foo::Bar
def value2
VAL
end
end
Example 3
module Foo
def foo
puts 'heyyyyoooo!'
end
end
class Bar
include Foo
end
Out of the three, only the last one includes a module into the class. That is, it adds the methods from the module to the class.
The first one is called refinement. If instead of refining Fixnum you just added a #minutes method to it, Fixnum will have that method for everyone that uses it, as long as your code is loaded. This might cause conflicts with other implementations of the same method (for example active record's #minutes) and leads to obscure, hard to debug issues. Instead, you can refine the Fixnum class and it will have that method only in the scope where you added the refinement with using.
It has some issues and it's not very widely used. But for the purposes of this question, the differences between including a module and using a refinement are:
including will add methods to the class where you do the inclusion, while refinements make other classes behave differently in the context where they are used
including is semantical (all objects will have the new included methods), while refinements are lexical (after you close the class, if you reopen it again, you won't see the refined methods)
The second one is scoping the class inside the module. This doesn't add methods anywhere. It is just due to the way constants are searched that if the constant (in this case VAL) isn't found in the current class, it is searched further up the tree. It's not that simple actually, if you want more details, you can read here.
Related
I'm having lots of fun with ActiveModel's serialization, specifically the tangled web of as_json and serializable_hash.
My app has a large collection of models that share behavior by including a module, we'll call it SharedBehavior.
My team has decided we have a default format we want all these classes to follow when being cast to JSON (for rendering in a Rails app), but some of them should behave a little differently. Due to odd behavior in these two methods from the ActiveModel library, adding whitelisted or blacklisted attributes in the models themselves gets overridden by the method definition in this module, and then passed on to the super declarations in ActiveModel.
For this reason, I'd like this module to only apply its definition of these methods to models if they are not explicitly overridden in those models (in essence, take the module out of the ancestor chain for a few method calls), but I still need the shared behavior from this module.
I tried solving this by conditionally, dynamically applying the method on module inclusion in IRB:
class A
def foo
puts 'in A'
end
end
module D
def self.included(base)
unless base.instance_methods(false).include?(:foo)
define_method(:foo) do
puts 'in D'
super()
end
end
end
end
class B < A
include D
end
class C < A
include D
def foo
puts 'in C'
super
end
end
With this declaration, I expected the output of C.new.foo to be
in C
in A
but it was instead
in C
in D
in A
My only other thought is to move this logic out into another module and include that module in every class (there are about 54 of them) that does not explicitly override this method, but there are a couple downsides to that:
It introduces a bit of implicit coupling in the project that a new model include this module iff it does not want to override this method implementation
The current implementation of these serialization methods in the module have to do with behavior and attributes established by that module, so I feel like it would be unintuitive to have a second module that knows about and depends on those implementation details of SharedBehavior, though the second module would have almost nothing to do with the first.
Can anyone else think of another solution, or maybe spot an oversight of mine in the code example above that would allow me to make a call in the included hook? (I also tried switching the order in which the C class defined the foo method and included the D module, but saw exactly the same behavior).
There are two tricky bugs here.
Ruby evaluates classes, so the order of expressions matters. You include D before defining foo in C, so when the included hook is called, foo won't be defined in base. You need to include D at the end of the class.
You're defining foo in D. So after including D in B, D#foo is defined, meaning it's still included in C even if you fix the previous bug. You need base to be the receiver of define_method.
But there's an interesting twist: fixing the second bug makes the first bug irrelevant. By defining foo in base directly, it will be overwritten by any later definitions. It would be like doing
class C < A
def foo
puts 'in D'
super()
end
# overwrites previous definition!
def foo
puts 'in C'
super
end
end
So to summarize, you just need
# in D.included
base.class_eval do
define_method(:foo) do
puts 'in D'
super()
end
end
The methods in Math can be invoked like a class method:
Math.cos(0)
but also can be include-d like instance method:
include Math
cos(0)
In contrast, the following modules can be invoked in one way but not the other:
module Foo
def bar
end
end
Foo.bar() # NoMethodError for this call
include Foo
bar() # but this call is fine
Singleton method:
module Foo
def self.bar
end
end
Foo.bar() # this call is fine
include Foo
bar() # but not this one
Any idea how to write a module like Math?
There're a few ways to get singleton methods, so I'm going to go over those first. We'll get to the part that lets the include Math work in a minute. So, first, if you're in a module or class body, you can define a singleton method as a method of self, like so:
module Foo
# Define bar as a method on self (the Foo module), thereby making
# it a singleton method.
def self.bar
"baz"
end
end
Alternatively, you can define them as methods on a module or class's singleton class:
module Foo
# Opens the singleton class of self (the Foo module). This makes
# bar a singleton method (see Module#define_singleton_method for
# some more on that).
class <<self
def bar
"baz"
end
end
end
include Math, Having Your Methods, and Eating Them Too
Thirdly, if you want methods as both instance and singleton methods, you can use extend. This allows you to include the module somewhere and call its methods without qualification or at least with differing qualification, depending on where you include the module (sort of -- that's beyond the scope of this, though). You can also extend self or extend using another module (containing instance methods) to add them as singleton methods when in a module or class body. This might sound more complicated than it probably looks:
module Foo
def bar
"baz"
end
# Extending self will add the instance methods of self as
# methods on the object self -- which happens to be a module,
# so you basically get class methods from the instance methods.
extend self
end
This last case allows you to also include the module in another module or class and gain bar as an instance method as well, so what you do depends on what you need. In general, I prefer the first route if I'm just defining a singleton method and it's all I'll need. The second option is more or less equivalent, but also allows you to use alias_method and so on. Qualified access is next to godliness, as far as I'm concerned.
The third option, however, — using extend self — is good for doing what you're asking about with include Math, where you want to be able to both call a function as a singleton method (Math.cos(0)) and include the module to access and call the methods without qualifying them with the module name (cos(0)). If you want that, you can do one of the following:
Define the method twice, both as a singleton method and as an instance method. This is not preferrable.
Define them in another module and both include and extend using that module. This is handy if you want to use the module in multiple places.
extend self. Extending using self is probably the best choice here, since it's simple, reduces duplicate code, and it's sufficient for the purpose of the question.
So there you go, instance methods and singleton methods living side-by-side in harmony, just like Holan and Hamlet.
That's what Module#module_function is for.
RSpec adds a "describe" method do the top-level namespace. However, instead of simply defining the method outside of any classes/modules, they do this:
# code from rspec-core/lib/rspec/core/dsl.rb
module RSpec
module Core
# Adds the `describe` method to the top-level namespace.
module DSL
def describe(*args, &example_group_block)
RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
end
end
end
end
extend RSpec::Core::DSL
Module.send(:include, RSpec::Core::DSL)
What is the benefit of using this technique as opposed to simply defining describe outside any modules and classes? (From what I can tell, the DSL module isn't used anywhere else in rspec-core.)
I made this change a few months ago so that describe is no longer added to every object in the system. If you defined it at the top level:
def describe(*args)
end
...then every object in the system would have a private describe method. RSpec does not own every object in the system and should not be adding describe willy-nilly to every object. We only want the describe method available in two scopes:
describe MyClass do
end
(at the top-level, off of the main object)
module MyModule
describe MyClass do
end
end
(off of any module, so you nest your describes in a module scope)
Putting it in a module makes it easy to extend onto the main object (to add it to only that object, and not every object) and include it in Module (to add it to all modules).
Actually, if that's all there is in the code, I don't really believe it to be much better — if at all. A common argument is that you can easily check that RSpec is responsible for addinng this method in the global namespace by checking the method owner. Somehow it never felt this was needed, as the location of the method already stores that information.
Defining the method outside of any scope would have be equivalent to defining a private instance method in Object:
class Object
private
def double(arg)
arg * 2
end
end
double(3) # OK
3.double(3) # Error: double is private
self.double(3) # Error: double is private
I think privateness is a useful aspect, because it prevents from making certain method calls that have no meaning, that the code shown in the question lacks.
There's an advantge to defining the method in a module, though, but the RSpec code doesn't seem to make use of it: using module_function, not only do you preserve privateness of the instance method, but you also get a public class method. This means that if you have an instance method of the same name, you will still be able to refer to the one defined by the module, by using the class method version.
A common example of module_function is the Kernel module, which contains most function-like core methods like puts (another one is Math). If you're in a class that redefines puts, you can still use Kernel#puts explicitly if you need:
class LikeAnIO
def puts(string)
#output << string
end
def do_work
puts "foo" # inserts "foo" in #output
Kernel.puts "foo" # inserts "foo" in $stdout
end
end
Let's say I have a bunch of related functions that have no persistent state, say various operations in a string differencing package. I can either define them in a class or module (using self) and they can be accessed the exact same way:
class Diff
def self.diff ...
def self.patch ...
end
or
module Diff
def self.diff ...
def self.patch ...
end
I can then do Diff.patch(...). Which is 'better' (or 'correct')?
The main reason I need to group them up is namespace issues, common function names are all used elsewhere.
Edit: Changed example from matrix to diff. Matrix is a terrible example as it does have state and everyone started explaining why it's better to write them as methods rather than answer the actual question. :(
In your two examples, you are not actually defining methods in a Class or a Module; you are defining singleton methods on an object which happens to be a Class or a Module, but could be just about any object. Here's an example with a String:
Diff = "Use me to access really cool methods"
def Diff.patch
# ...
end
You can do any of these and that will work, but the best way to group related methods is in a Module as normal instance methods (i.e. without self.):
module Diff
extend self # This makes the instance methods available to the Diff module itself
def diff ... # no self.
def patch ...
end
Now you can:
use this functionality from within any Class (with include Diff) or from any object (with extend Diff)
an example of this use is the extend self line which makes it possible to call Diff.patch.
even use these methods in the global namespace
For example, in irb:
class Foo
include Diff
end
Foo.new.patch # => calls the patch method
Diff.patch # => also calls Diff.patch
include Diff # => now you can call methods directly:
patch # => also calls the patch method
Note: the extend self will "modify" the Diff module object itself but it won't have any effect on inclusions of the module. Same thing happens for a def self.foo, the foo won't be available to any class including it. In short, only instance methods of Diff are imported with an include (or an extend), not the singleton methods. Only subclassing a class will provide inheritance of both instance and singleton methods.
When you actually want the inclusion of a module to provide both instance methods and singleton methods, it's not completely easy. You have to use the self.included hook:
module Foo
def some_instance_method; end
module ClassMethods
def some_singleton_method; end
end
def self.included(base)
base.send :extend, ClassMethods
end
def self.will_not_be_included_in_any_way; end
end
class Bar
include Foo
end
# Bar has now instance methods:
Bar.new.some_instance_method # => nil
# and singleton methods:
Bar.some_singleton_method # => nil
The main difference between modules and classes is that you can not instantiate a module; you can't do obj = MyModule.new. The assumption of your question is that you don't want to instantiate anything, so I recommend just using a module.
Still you should reconsider your approach: rather than using arrays of arrays or whatever you are doing to represent a Matrix, it would be more elegant to make your own class to represent a matrix, or find a good class that someone else has already written.
Ruby Modules are used to specify behaviour, pieces of related functionality.
Ruby Classes are used to specify both state and behaviour, a singular entity.
There is a maxim in software design that says that code is a liability, so use the less code possible. In the case of Ruby, the difference in code lines is cero. So you can use either way (if you don't need to save state)
If you want to be a purist, then use a Module, since you won't be using the State functionality. But I wouldn't say that using a class is wrong.
As a trivia info: In Ruby a Class is a kind of Module.
http://www.ruby-doc.org/core-1.9.3/Class.html
The following also works
Matrix = Object.new
def Matrix.add ...
def Matrix.equals ...
That's because so-called "class methods" are just methods added to a single object, and it doesn't really matter what that object class is.
As a matter of form, the Module is more correct. You can still create instances of the class, even if it has only class methods. You can think of a module here as a static class of C# or Java. Classes also always have the instance related methods (new, allocate, etc.). Use the Module. Class methods usually have something to do with objects (creating them, manipulating them).
In Ruby, since you can include multiple mixins but only extend one class, it seems like mixins would be preferred over inheritance.
My question: if you're writing code which must be extended/included to be useful, why would you ever make it a class? Or put another way, why wouldn't you always make it a module?
I can only think of one reason why you'd want a class, and that is if you need to instantiate the class. In the case of ActiveRecord::Base, however, you never instantiate it directly. So shouldn't it have been a module instead?
I just read about this topic in The Well-Grounded Rubyist (great book, by the way). The author does a better job of explaining than I would so I'll quote him:
No single rule or formula always results in the right design. But it’s useful to keep a
couple of considerations in mind when you’re making class-versus-module decisions:
Modules don’t have instances. It follows that entities or things are generally best
modeled in classes, and characteristics or properties of entities or things are
best encapsulated in modules. Correspondingly, as noted in section 4.1.1, class
names tend to be nouns, whereas module names are often adjectives (Stack
versus Stacklike).
A class can have only one superclass, but it can mix in as many modules as it wants. If
you’re using inheritance, give priority to creating a sensible superclass/subclass
relationship. Don’t use up a class’s one and only superclass relationship to
endow the class with what might turn out to be just one of several sets of characteristics.
Summing up these rules in one example, here is what you should not do:
module Vehicle
...
class SelfPropelling
...
class Truck < SelfPropelling
include Vehicle
...
Rather, you should do this:
module SelfPropelling
...
class Vehicle
include SelfPropelling
...
class Truck < Vehicle
...
The second version models the entities and properties much more neatly. Truck
descends from Vehicle (which makes sense), whereas SelfPropelling is a characteristic of vehicles (at least, all those we care about in this model of the world)—a characteristic that is passed on to trucks by virtue of Truck being a descendant, or specialized
form, of Vehicle.
I think mixins are a great idea, but there's another problem here that nobody has mentioned: namespace collisions. Consider:
module A
HELLO = "hi"
def sayhi
puts HELLO
end
end
module B
HELLO = "you stink"
def sayhi
puts HELLO
end
end
class C
include A
include B
end
c = C.new
c.sayhi
Which one wins? In Ruby, it turns out the be the latter, module B, because you included it after module A. Now, it's easy to avoid this problem: make sure all of module A and module B's constants and methods are in unlikely namespaces. The problem is that the compiler doesn't warn you at all when collisions happen.
I argue that this behavior does not scale to large teams of programmers-- you shouldn't assume that the person implementing class C knows about every name in scope. Ruby will even let you override a constant or method of a different type. I'm not sure that could ever be considered correct behavior.
My take: Modules are for sharing behavior, while classes are for modeling relationships between objects. You technically could just make everything an instance of Object and mix in whatever modules you want to get the desired set of behaviors, but that would be a poor, haphazard and rather unreadable design.
The answer to your question is largely contextual. Distilling pubb's observation, the choice is primarily driven by the domain under consideration.
And yes, ActiveRecord should have been included rather than extended by a subclass. Another ORM - datamapper - precisely achieves that!
I like Andy Gaskell's answer very much - just wanted to add that yes, ActiveRecord should not use inheritance, but rather include a module to add the behavior (mostly persistence) to a model/class. ActiveRecord is simply using the wrong paradigm.
For the same reason, I very much like MongoId over MongoMapper, because it leaves the developer the chance to use inheritance as a way of modelling something meaningful in the problem domain.
It's sad that pretty much nobody in the Rails community is using "Ruby inheritance" the way it's supposed to be used - to define class hierarchies, not just to add behavior.
The best way I understand mixins are as virtual classes. Mixins are "virtual classes" that have been injected in a class's or module's ancestor chain.
When we use "include" and pass it a module, it adds the module to the ancestor chain right before the class that we are inheriting from:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Every object in Ruby also has a singleton class. Methods added to this singleton class can be directly called on the object and so they act as "class" methods. When we use "extend" on an object and pass the object a module, we are adding the methods of the module to the singleton class of the object:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
We can access the singleton class with the singleton_class method:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby provides some hooks for modules when they are being mixed into classes/modules. included is a hook method provided by Ruby which gets called whenever you include a module in some module or class. Just like included, there is an associated extended hook for extend. It will be called when a module is extended by another module or class.
module M
def self.included(target)
puts "included into #{target}"
end
def self.extended(target)
puts "extended into #{target}"
end
end
class MyClass
include M
end
class MyClass2
extend M
end
This creates an interesting pattern that developers could use:
module M
def self.included(target)
target.send(:include, InstanceMethods)
target.extend ClassMethods
target.class_eval do
a_class_method
end
end
module InstanceMethods
def an_instance_method
end
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end
class MyClass
include M
# a_class_method called
end
As you can see, this single module is adding instance methods, "class" methods, and acting directly on the target class (calling a_class_method() in this case).
ActiveSupport::Concern encapsulates this pattern. Here's the same module rewritten to use ActiveSupport::Concern:
module M
extend ActiveSupport::Concern
included do
a_class_method
end
def an_instance_method
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end
Right now, I'm thinking about the template design pattern. It just wouldn't feel right with a module.