I saw something like this this library:
class A
# ...
class B < A
# ...
end
end
Is this not weird? I get the concept that you can declare classes inside other classes, but those nested classes inherit from the parent one. Is that not like an infinite loop?
Maybe it is simpler than it looks like, but this image makes me hesitate a lot. Am I missing some hiding benefit here, or a special Ruby idiom that I do not know?
Namespace and subclassing are two different things. They have no relation to each other.
By doing:
class A
class B
end
end
you define B in the namespace of A, hence A::B (but B is not a subclass of A; in fact it is a subclass of Object).
By doing:
class A
end
class B < A
end
you define B as a subclass of A (but B is not in the namespace of A; in fact it is in the namespace of the main environment :: (or Object::).
In your example:
class A
class B < A
end
end
both happened simultaneously, but they are independent of one another, and there is no contradiction.
In addition to #sawa's answer: this can be useful as an intermediate step during refactoring.
Say, I come across some big fat class and I clearly see that several subclasses can be extracted here. But I don't know their names yet. And when I do, I might rename them several times in the process. This makes creating a file for each subclass an unnecessary hurdle. So I start with declaring subclasses right there, and move code within the same file. When I'm somewhat satisfied, then I will move the subclasses to their dedicated files. Or maybe I will not, if they are very small (and I'm feeling that they don't deserve a separate file).
Related
Is it conventional to define a subclass under it's parent class like below?
class Element
class Div < Element
end
class Paragraph < Element
end
end
Or is it more appropriate to make a module to contain the subclasses?
class Element
end
module Elements
class Div < Element
end
class Paragraph < Element
end
end
Or to create a "base" class in a module and define the subclasses within the same module?
module Element
class Base
end
class Div < Base
end
class Paragraph < Base
end
end
Or is it better to force a naming convention?
class Element
end
class DivElement < Element
end
class ParagraphElement < Element
end
It seems every library chooses a different namespacing/naming convention.
Which is the best to use?
What are the pros and cons of each?
TL;DR: The most conventional and best way to do this is with a module containing a base class and its subclasses. But let's go over everything.
There aren't many official sources on this; however, it is the style to use modules to contain libraries, code, and groups of classes.
Subclasses in Superclass
Pros:
Self-contained: The entire class system is contained under one name
Cons:
Unnatural: Who would think to look inside a superclass for a subclass?
Having the subclasses in a superclass really depends on situation. However, any benefits of this method are also achieved by the module method. But in practice, this just isn't done. Classes are here to contain methods, instance variables, class methods, etc. But classes can be thought of as a last level of nesting -- you don't have a class in a class unless it's a very specific circumstance.
The one case where I can think of this making sense is a case where the only way subclasses are used is through the superclass, for example a Formatter class that has internal subclassses like XML, PDF, etc. Let's say that you only use these classes by doing things like Formatter.new(:xml). But if we're doing this, the subclasses should be private and not accessible to the outside world anyway. And at that point, inheritance is a very C++y way and not Rubyish at all.
Base class outside module, subclasses within
Pros:
I can't think of any
Cons:
Implies Non-conected: If Element is not in the same namespace as its children, what, beyond the name tells me that it's even related?
This method is very unnatural. It makes it look as if Element has nothing to do with it's children, or if looked at differently, that it's children are internal implementation details that aren't to be dealt with. Either way it looks like shabby, sloppy naming and bad code structure planning. If I were reading code using this, I'd have to look at the contents of the Elements module to see that Element was subclassed at all -- and this isn't the most natural thing to do.
Class and subclasses in module (best solution)
Pros:
Contained: The superclass and all the Element classes are contained in one namespace, allowing them to be easily imported, required, iterated, etc. Also assists metaprogramming.
Includable: The classes can be easily includeed into any code.
Clear: There is an obvious association between Element and the subclasses. They are obviously a bundle of functionality.
Cons:
Encourages lazy naming: This does encourage you to name classes things like Base that are very ambiguous.
This is the best approach. It makes the classes a neat bundle, while still showing an obvious association and an obvious "Here, use my Div class" (as opposed to the subclasses-in-class strategy). Also, this is really helpful for metaprogramming, where having everything in a module is crucial to make things work. Finally, this works well with constructs like autoload, require_relative, include, etc. Those show that this is the way the language was designed to be used.
Force a naming convention
Pros:
Simple: No complexity here.
Removes ambiguity: Removes ambiguity from short names like Div or Para by turning them into DivElement and ParaElement.
Cons:
Archaic: Naming conventions to group classes or methods should only exist in languages that don't have a better way to do it, like C or Objective-C. C++ dropped it as soon as it got namespaces.
No programatic grouping: These naming conventions, while clear to humans, make the class structure very cloudy to metaprograming code, and make it impossible for the program to deal with the classes as a group
Pollutes global namespace: This creates many, many names in the global namespace, which is always a bad idea.
This is a very, VERY bad solution. It encorages writing sloppy, C-style code with little organization and little sense. These kinds of naming conventions should only be used in languages where there is no better solution, and Ruby has plenty of better solutions. Even defining all the classes in an array is better than a naming convention.
Note: However, if you really want to, you can define a naming convention on short names like Div or Para as long as you still keep them in a module, so that it's Elements::DivElement. However, this violates DRY, and I wouldn't suggest it.
Conclusion
So, you really have two options. Just put everything in a module:
module Elements
class Element; end
class Div < Element; end
#etc...
end
Or, put everything in a module with a naming convention:
module Elements
class Element; end
class DivElement < Element; end
#etc...
end
I sugest the former for clarity, use of standard methods, and metaprogramming reasons.
This is a problem I have faced many times - you have some shared functionality and a few different implementation classes that use it - it's natural for the shared functionality and the namespace for the implementation classes to have the same name.
I have never had a problem defining a subclass under its parent class as in your first example - except for the fact that it has sometimes confused other developers on my team. So depending on who you are working with and what their preferences are I don't think there's any problem with this approach.
I would still prefer the second approach, with a different name for the namespace, if there was a name that made sense. If there isn't, I'd use the first approach.
I would avoid using names like Base, as in my opinion this sort of generic name encourages you to just throw any old stuff in there, whereas a name that describes what the class does will (hopefully) make you think each time you add a method if it really belongs there.
And I'm really not a fan of compound names as in your naming convention example, which I justify to myself with a sort of vague feeling that it's like database normalisation - each field (or class name) should contain only one piece of information.
Anyway, I hope this helps you. I can't really draw from any sources other than my own experience (it's for you to decide if you think that's 'credible'), as I do think there's no absolute answer to this question. It is in a large part subjective.
Name space and inheritance are for different purposes. Use name space to encapsule a module within another. Use inheritance to define a module using the methods/variables/constants of another as a default.
It could happen in principle that you may want a module to both be within the name space of and inherit from the same single module, but that depends on your use case. Without discussing over a particular use case, it cannot be decided which way among the ones you presented is the best.
I am just starting Ruby and learning the concept of modules. I understand that one use of modules is to better organize your code and avoid name clashes. Let's say I have bunch of modules like this (I haven't included the implementation as that's not important)
:
module Dropbox
class Base
def initialize(a_user)
end
end
class Event < Base
def newFile?
end
def newImage?
end
end
class Action < Base
def saveFile(params)
end
end
end
and another module:
module CustomURL
class Base
def initialize(a_user, a_url, a_method, some_args, a_regex)
end
end
class Event < Base
def initialize(a_user, a_url, a_method, some_args, a_regex)
end
def change?
end
end
class Action < Base
def send_request(params)
end
end
end
I am going to have a bunch of these modules (10+, for gmail, hotmail, etc...). What I am trying to figure out is, is this the right way to organize my code?
Basically, I am using module to represent a "service" and all services will have a common interface class (base for initializing, action for list of actions and event for monitoring).
You are defining families of related or dependent classes here. Your usage of modules as namespaces for these families is correct.
Also with this approach it would be easy to build abstract factory for your classes if they had compatible interface. But as far as I see this is not the case for current classes design: for example Dropbox::Event and CustomURL::Event have completely different public methods.
You can reevaluate design of your classes and see if it is possible for them to have uniform interface so that you can use polymorphism and extract something like BaseEvent and BaseAction so that all Events and Actions will derive from these base classes.
Update: As far as you define services, it might be useful to define top-level module like Service and put all your classes inside this module. It will improve modularity of your system. If in the future you would refactor out some base classes for your modules services, you can put them in the top-level namespace. Then your objects will have readable names like these:
Service::Dropbox::Event
Service::Dropbox::Action
Service::CustomURL::Event
Service::CustomURL::Action
Service::BaseEvent
Service::BaseAction
I have some similar code at work, only I'm modeling networking gear.
I took the approach of defining a generic class with the common attributes and methods, including a generic comparator, and then sub-class that for the various models of hardware. The sub-classes contain the unique attributes for that hardware, plus all the support code necessary to initialize or compare an instance of that equipment with another.
As soon as I see the need to write a method similar to another I wrote I think about how I can reuse that code by promoting it to the base-class. Often this involves changing how I am passing parameters, and instead of using formal parameters, I end up using a hash, then pulling what I need from it, keeping the method interface under control.
Because you would have a lot of sub-classes to a base class, it's important to take your time and think out how that base-class should work. As you add sub-classes the task of refactoring the base will get harder because you will have to change other sub-classes. I always find I go down some blind-alleys and have to back up a bit, but as the class matures that should happen less and less.
As you will notice soon, there is no 'right way' of organizing code.
There are subtle differences in readability that are mostly subjective. The way you are organizing classes is just fine for releasing your code as a gem. It usually isn't needed in code that won't be included in other peoples projects, but it won't hurt either.
Just ask yourself "does this make sense for someone reading my code who has no idea what my intention is?".
I have an external file: path_to_external_file.rb with some class definition:
class A
some_definitions
end
And I want to load that within module B so that the class A defined above can be referred to as B::A. I tried:
class B
load('path_to_external_file.rb')
end
but A is defined in the main environment, not in B:
A #=> A
B.constants # => []
How can I load external files within some class/module?
Edit
Should I read the external files as strings, and evaluate them within Class.new{...}, and include that class within B?
You cannot. At least using load or require, the Ruby files will always be evaluated in a top context.
You can work around that problem in two ways:
Define class B::A directly (but you are probably trying to avoid that)
Use eval(File.read("path_to_external_file.rb")) within your B class
Edit: Maybe, this library is interesting for you: https://github.com/dreamcat4/script/blob/master/intro.txt
Generally, it's a bad idea to define a class as "class A" but then "magically" make it contained by module B. If you want to refer to class A as B::A, you should define it using either:
module B
class A
# contents
end
end
or:
class B::A
# contents
end
Otherwise anyone who reads your code will be confused. In this case, you don't gain anything in clarity, brevity, or convenience by using "tricks", so straightforward code is better. There is a lesson here: the metaprogramming features of Ruby are great, but there is no need to use them gratuitously. Only use them when you really gain something from doing so. Otherwise you just make your code hard to understand.
BUT, having read your comment, it looks like there is really a good reason to do something like this in your case. I suggest that the following solution would be even better than what you are envisioning:
m = Module.new
m.module_eval("class C; end")
m.constants
=> [:C]
m.const_get(:C)
=> #<Module:0xfd0da0>::C
You see? If you want a "guaranteed unique" namespace, you can use an anonymous module. You could store these modules in a hash or other data structure, and pull the classes out of them as needed. This solves the problem you mentioned, that the users of your app are going to be adding their own classes, and you don't want the names to collide.
In Ruby, one can declare classes like
class A
class B
end
end
and then instantiate the inner class like A::B.new.
Does B have some sort of special relationship with A (as is the case in Java) or is A just its namespace? In other words, is nesting a class in a class the same as nesting it in a module?
This is one of those times when you should really just fire up irb and try it.
Yes, a class can be defined within another class. Since a class's superclass is Module (i.e. Class extends Module), they can do almost everything a Module can. A notable exception is that you cannot include (mixin) a class.
That said, there's very little reason to actually use this design pattern. It is more likely that A and B can be considered siblings. There is no need to arbitrarily namespace until you are blue in the face. If you are more than 3 levels deep, stop and consider refactoring.
A better design pattern for this example might be:
module Alphabet
class A; end
class B; end
end
For something more complicated, this continues to work nicely using Mixins:
module Animals
class Dog
include Walking
end
module Walking
# some methods pertaining to the ability to walk
end
end
Yes, it's essentially the same as nesting in module. Nested class does not have any kind of special relationship to the class it's nested in.
Yes and...no. A Module can't be instantiated whereas a class can, so there is a difference in nesting a class within a Module vs. using a class nested within a class.
For example: You cannot instantiate an object of Ford here (i.e. Cobra, F-150, Mustang, etc.) because you cannot instantiate a module,.
`module Ford
class Engine
...
end
end`
But you can have an instance of the class Ford as well as instances of Ford engines with using nested classes like so:
`class Ford
class Engine
##actions = ['list', 'find', 'add', 'quit']
def self.actions; ##actions; end
end
def self.truck_exists?
#Some more stuff here
end
end`
Classes (and Modules) have different usages:
Namespace: when you define a class (or module) inside another class (or module), you have to use a different notation outside the defining class to reach the inner class or module.
Template for instances: There modules and classes behave totally (well mostly) different.
Inheritance: You may extend a class, so you inherit all its attributes and methods, which works for modules as well. Or you may include a module (not: a class) to add its methods (and attributes) to your scope. Ruby plays here tricks by mixin the module in the class hierarchy.
So in the context of using name spaces, they are the same. However I would all the time use modules (only), but that is more a matter of style. The best book on this topic is in my opinion "Metaprogramming Ruby" by Paolo Perrotta.
I'm pretty familiar with when to use subclasses and modules, but more recently I've been seeing nested classes like this:
class Foo
class Bar
# do some useful things
end
end
As well as classes nested in modules like so:
module Baz
class Quux
# more code
end
end
Either documentation and articles are sparse or I'm not educated on the subject enough to grope for the right search terms, but I can't seem to locate much information on the topic.
Could somebody provide examples or links to posts on why/when those techniques would be used?
Other OOP languages have inner classes which cannot be instantiated without being bound to an upper level class. For instance, in Java,
class Car {
class Wheel { }
}
only methods in the Car class can create Wheels.
Ruby doesn’t have that behaviour.
In Ruby,
class Car
class Wheel
end
end
differs from
class Car
end
class Wheel
end
only in the name of the class Wheel vs. Car::Wheel. This difference in name can make explicit to programmers that the Car::Wheel class can only represent a car wheel, as opposed to a general wheel. Nesting class definitions in Ruby is a matter of preference, but it serves a purpose in the sense that it more strongly enforces a contract between the two classes and in doing so conveys more information about them and their uses.
But to the Ruby interpreter, it’s only a difference in name.
As for your second observation, classes nested inside of modules are generally used to namespace the classes. For instance:
module ActiveRecord
class Base
end
end
differs from
module ActionMailer
class Base
end
end
Although this is not the only use of classes nested inside of modules, it is generally the most common.
In Ruby, defining a nested class is similar to defining a class in a module. It doesn't actually force an association between the classes, it just makes a namespace for the constants. (Class and Module names are constants.)
The accepted answer wasn't correct about anything. In the example below I create an instance of the lexically enclosed class without an instance of the enclosing class ever existing.
class A; class B; end; end
A::B.new
The advantages are the same as those for modules: encapsulation, grouping code used in only one place, and placing code closer to where it is used. A large project might have one outer module that occurs over and over in each source file and contains a lot of class definitions. When the various frameworks and library codes all do this, then they contribute only one name each to the top level, reducing the chance of conflicts. Prosaic, to be sure, but that's why they are used.
Using a class instead of a module to define the outer namespace might make sense in a one-file program or script, or if you already use the top level class for something, or if you are actually going to add code to link the classes together in true inner-class style. Ruby doesn't have inner classes but nothing stops you from creating about the same behavior in code. Referencing the outer objects from the inner ones will still require dotting in from the instance of the outer object but nesting the classes will suggest that this is what you might be doing. A carefully modularized program might always create the enclosing classes first, and they might reasonably be decomposed with nested or inner classes. You can't call new on a module.
You can use the general pattern even for scripts, where the namespace isn't terribly needed, just for fun and practice...
#!/usr/bin/env ruby
class A
class Realwork_A
...
end
class Realwork_B
...
end
def run
...
end
self
end.new.run
You probably want to use this to group your classes into a module. Sort of a namespace thing.
for example the Twitter gem uses namespaces to achieve this:
Twitter::Client.new
Twitter::Search.new
So both Client and Search classes live under the Twitter module.
If you want to check the sources, the code for both classes can be found here and here.
Hope this helps!
There is yet another difference between nested classes and nested modules in Ruby prior to 2.5 that other answers failed to cover that I feel must be mentioned here. It is the lookup process.
In short: due to top level constant lookup in Ruby prior to 2.5, Ruby may end up looking for your nested class in the wrong place (in Object in particular) if you use nested classes.
In Ruby prior to 2.5:
Nested class structure:
Suppose you have a class X, with nested class Y, or X::Y. And then you have a top level class named also Y. If X::Y is not loaded, then following happens when you call X::Y:
Having not found Y in X, Ruby will try to look it up in ancestors of X. Since X is a class and not a module, it has ancestors, among which are [Object, Kernel, BasicObject]. So, it tries to look for Y in Object, where it finds it successfully.Yet it is the top level Y and not X::Y.
You will get this warning:
warning: toplevel constant Y referenced by X::Y
Nested module structure:
Suppose in the previous example X is a module and not a class.A module only has itself as ancestor: X.ancestors would produce [X].
In this case, Ruby won't be able to look for Y in one of ancestors of X and will throw a NameError. Rails (or any other framework with autoloading) will try to load X::Y after that.
See this article for more information: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Top level constant lookup removed.You may use nested classes without fear of encountering this bug.
In the addition to previous answers: Module in Ruby is a class
$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object