I have tons of different methods in a particular class that all calculate unique instance variables. I've been using the attr_reader to access these without any problem, but now I've got dozens of these and wondering if there's a preferred / eloquent way to access all of these instance variables - not just a solution, but a generally accepted preferred method/style.
I've seen similar questions regarding class level variables, but that's something I'd like to avoid. Maybe I can do this with a Module, but I thought those were for storing piles of constants? But maybe it's something I'm missing with regular Class inheritance? Inheriting self?
If you imagine the pile of these instance variables as mathematical constants (pi, eulers, etc.) that all get a number added to them (depending on user input). I'm aware of classes and methods doing one thing, which the Stack class and method definitely do one thing - they're just storing pieces of data that are needed by many other classes and methods.
An example of code that I'm working with:
class Stack
attr_reader :pi, :euler # ... and dozens more of these
def initialize
#pi = 3.14 + 8
#euler = 0.577 + 8
# dozens more assignements here
end
end
class Overflow
def show
a = Stack.new
p a.pi # attr_reader works fine here
end
end
class AnotherClass
def some_method_that_needs_all_variables_in_Stack
# Do I need to create another instance of the
# Stack class like I did in Overflow?
# or should AnotherClass somehow inherit all the instance variables?
end
end
Overflow.new.show # => 11.14.
Thanks!
Have you heard about Single Responsibility Principle? It says, that 1 class should do only 1 thing, but do it well. Having a hundred (man, even five of them should make you doubt if your code is good) of instance variables, means that you have an antipode: God object, that does everything. This code is very hard to change because of myriad of hidden dependencies between method calls and instance variables.
The solution: Move out new classes and make them talk to each other. Read some book on the Object Oriented Programming, there are tons of them, and you'll immediately start feeling better about your code.
Related
I have a class QuestionList that stores a list of 'Question' objects.
class QuestionList
attr_accessor :questions
def initialize
#questions = []
end
end
I then add questions to the list and then "ask" these questions from my main class as so:
list = QuestionList.new
list.questions << Question.new(5, 3)
list.questions << Question.new(1, 5)
list.questions << Question.new(2, 4)
list.questions.each do |question|
puts "#{question.ask}"
end
where Question.ask simply outputs the question as a string.
I'm not sure how acceptable it is to be writing to an instance variable from my main class using the << operator, and list.questions.push(Question.new(5, 3)) is even more unclear from the main class.
Would it be better to have a QuestionsList.add_question(question) method?
The same goes for list.questions.each - is this acceptable to be used in the main class?
I think your use of attr_accessor here is fine, though depending on how much functionality you continue to add, it will likely be clearer to restrict functionality of that class to the class itself.
Regarding your question on using a method within QuestionList, this would come down to readability. Something to note first, however: you used QuestionsList.add_question(question) as an example. This would create a class method. What you really want here is an instance method, which would read as list.add_question(question), since you already have an instance of the list created. This blog post has some good information on the difference between class and instance methods.
I personally find instance methods would most clearly communicate your intent. I would write out QuestionList as follows:
class QuestionList
def initialize
#questions = []
end
def add_question(question)
#questions << question
end
def print_all_questions_in_list
#questions.each do |question|
puts "#{question.ask}"
end
end
end
This SO post has some excellent information on Ruby's attr methods, if you'd like additional info there.
The #questions array is a private internal implementation detail of your class. It should never ever get exposed to clients. There are many reasons for this, two examples are:
You overpromise an interface: now, all your clients depend on it being an array. What if you later want to change it to something else? A textfile? A database? A webservice?
You expose operations that break your object invariants: a client can, for example, add an integer to that array. Or nil. Or anything else that is not a Question.
How you store your questions should be an implementation detail. The QuestionList should have methods to manage the list of questions. It should probably have an each method (and include Enumerable), and an add method (possibly aliased to <<). Maybe also an [], if that makes sense. These methods could simply be delegated to the array, if convenient, but the point is: if you later decide to not use an array, you can do that without anyone even noticing. You can decide to only support those methods you actually want to support, as opposed to all ~100 methods of Array.
Can someone please provide some insight as to when to use delegation via DelegateClass (e.g. Seller < DelegateClass(Person)) and when to use class inheritance (e.g. Seller < Person) in ruby?
class Seller < DelegateClass(Person)
def sales
...
end
end
class Seller < Person
def sales
...
end
end
When I was looking over the Ruby on Rails source on Github I found quite a few uses of DelegateClass.
There are a couple of differences that can help provide insight as to which approach to use.
1) You can safely delegate to primitives (e.g. String), but cannot always safely inherit from them
If you're building on top of Hash or String or Fixnum, you're safer using DelegateClass (or another delegator). For more on why, Steve Klabnik's cautioning is a good place to start).
2) DelegateClass makes it easy to “convert” a more general object into a more specific one
This makes it easier to accept an instance of a general object and make it behave in a way that's specific to your implementation:
class Message < DelegateClass(String)
def print
upcase
end
end
# […]
def log(message)
message = Message.new(message) unless message.is_a?(Message)
end
3) A gotcha: DelegateClass subclasses expect an instance of the delegated class as an argument to new
This can make it tricky to “subclass” classes that you're handing to library code. For example, this is a fairly common practice that won't work out of the box with DelegateClass:
class MyLogger < DelegateClass(ActiveSupport::Logger); end
Foo::ThirdParty::Library.configure do |c|
c.logger = MyLogger # no good
end
This doesn't work because our library expects to behave like most loggers and instantiate without arguments. This can be addressed by defining initialize and creating an instance of ActiveSupport::Logger, but probably not the right solution in this case.
delegates model different behaviors of Person based on the context. e.g. the same person could be a seller in one context or a buyer in a different context. Inheritance is more rigid: a Bear and Tiger inherit from Animal, but an instance of Animal would never need to sometimes behave like a Bear and sometimes behave like a Tiger. An instance of a descendent of Animal is either one or the other.
I found examples of a mixin that makes assumptions about what instance variables an including class has. Something like this:
module Fooable
def calculate
#val_one + #val_two
end
end
class Bar
attr_accessor :val_one, :val_two
include Fooable
end
I found arguments for and against whether it's a good practice. The obvious alternative is passing val_one and val_two as parameters, but that doesn't seem as common, and having more heavily parameterized methods could be a downside.
Is there conventional wisdom regarding a mixin's dependence on class state? What are the advantages/disadvantages of reading values from instance variables vs. passing them in as parameters? Alternatively, does the answer change if you start modifying instance variables instead of just reading them?
It is not a problem at all to assume in a module some properties about the class that includes/prepends it. That is usually done. In fact, the Enumerable module assumes that a class that includes/prepends it has a each method, and has many methods that depend on it. Likewise, the Comparable module assumes that the including/prepending class has <=>. I cannot immediately come up with an example of an instance variable, but there is not a crucial difference between methods and instance variables regarding this point; the same should be said about instance variables.
Disadvantage of passing arguments without using instance variable is that your method call will be verbose and less flexible.
Rule of thumb: Mixins should never make any assumptions about the classes/modules they may be included in. However, as it usually goes, any rule has exceptions.
But first, let's talk about the first part. Specifically, accessing (depending on) including class instance variables. If your mixin depends on anything within the including class, then it means that you can not change that "anything" in the parent class with a guarantee that it would not break something. Also, you will have to document that dependency of mixin not only in documentation related to mixin, but also in the documentation of the class/module that includes the mixin. Because, down the road, the requirements may change or someone might see an opportunity in refactoring your class/module code. Obviously, that person will not dig for that class's documentation or know that that specific class/module has a section in your documentation.
Anyhow, by depending on including class internals, not only your mixin made itself dependant, but also ended up making any class/module that includes it a dependant. Which is definitely not a good thing. Because, you can not control who or which class/module has included your mixin, you will never have a confidence to introduce a change. Not having that confidence to change without a fear of breaking anything is project drainer!
The "workaround" may be - "covering it with test". But, consider yourself or someone else maintaining that code in 2 years. Will you remember to cover your new class, that includes the mixin, to make sure it complies with all mixin dependency requirements? I am sure you or the new maintainer will not.
So, from the maintenance or basic OOP principles, your mixin must not depend on any including class/module.
Now, let's talk about that there is alway an exception to the rule bit.
You can make an exception, provided that mixin dependency does not introduce "surprises" to your code. So, it is ok, if the mixin dependencies are well known among your team or they are a convention. Another case could be when the mixin is used internally and you control who uses it (basically, when you are using it within your own project).
The key advantage of OOP in developing maintainable systems was its ability to hide/encapsulate the implementation details. Making your mixin dependant on any class that includes it, is throwing all the years of OOP experience out the window.
I'd say a mixin should not make assumptions about a specific class it is included in, but it's totally fine to make assumptions about a common parent class (respectively its public methods).
Good example: It's fine to call params in a mixin that will be included in controllers.
Or, to be more precise according your example, I'd think something like this would totally be fine:
class Calculation
attr_accesor :operands
end
module SumOperation
def sum
self.operands.sum
end
end
class MyCustomCalculation < Calculation
include SumOperation
end
You should not hesitate, even for a second, to include instance variables in your mixin module when the situation calls for it.
Suppose, for example, you wrote:
class A
def initialize(h)
#h = h
end
def confirm_colour(colour)
#h[:colour] == colour
end
def confirm_size(size)
#h[:size] == size
end
def confirm_all(colour, size)
confirm_colour(colour) && confirm_size(size)
end
end
a = A.new(:colour=>:blue, :size=>:medium, :weight=>10)
a.confirm_all(:blue, :medium)
#=> true
a.confirm_all(:blue, :large)
#=> false
Now suppose someone asks for the weight be checked as well. We could add the method
def confirm_weight(weight)
#h[:weight] == weight
end
and change confirm_all to
def confirm_all(colour, size)
confirm_colour(colour) && confirm_size(size) && confirm_weight(size)
end
but there is a better way: put all the checks in a module.
module Checks
def confirm_colour(g)
#h[:colour] == g[:colour]
end
def confirm_size(g)
#h[:size] == g[:size]
end
def confirm_weight(g)
#h[:weight] == g[:weight]
end
end
Then include the module in A and run through all the checks.
class A
include Checks
def initialize(h)
#h = h
end
def confirm_all(g)
Checks.instance_methods.all? { |m| send(m, g) }
end
end
a = A.new(:colour=>:blue, :size=>:medium, :weight=>10)
a.confirm_all(:colour=>:blue, :size=>:medium, :weight=>10)
#=> true
a.confirm_all(:colour=>:blue, :size=>:large, :weight=>10)
#=> false
This has the advantage that when checks are to be added or removed, only the module is affected; no changes need to be made to the class. This example is admittedly contrived, but it is a short step to real-world situations.
Although it is common to make these assumptions, you may want to consider a different pattern in order to make more composable and testable code: Dependency Injection.
module Fooable
def add(one, two)
one + two
end
end
class Bar
attr_accessor :val_one, :val_two
include Fooable
def calculate
add #val_one, #val_two
end
end
Although it adds an extra layer of indirection, often times it will be worth it because of the potential to use the concern across a larger number of classes, as well as making it easier to test code.
Something that I see in a lot of code:
class Foo
attr_accessor :bar
# lots of code omitted
def baz
'qux' if bar
end
end
The exact form of the baz method is not too important - it's just that bar here is a reference to the getter method for the instance variable #bar, called from within the instance's class. I would favor retrieving the value from #bar explicitly. Are there any opinions on this?
I've never seen anything in the ruby style guide or similar covering this. I personally find that doing the former makes it harder to read and understand, especially when classes are over several hundred lines long.
Edit:
Perhaps to illustrate what I would consider to be the awkwardness of this design, let's re-evaluate a pretty standard initialize method:
class Foo
attr_accessor :bar, :qux
def initialize(bar, qux)
#bar = bar
#qux = qux
end
end
If we use the setter method, we cannot use bar = ? by analogy. Instead, we have:
class Foo
attr_accessor :bar, :qux
def initialize(bar, qux)
self.bar = bar
self.qux = qux
end
end
which has lost some of the elegance of the first. We have a more flexible design in that we are now free to rewrite our setter method and do away with attr_writer. But I've just some points in style, and it feels a lot like configuration over convention rather than the converse, something that Russ Olsen has declared a design 'pattern' not just of Rails but of Ruby too.
Accessing the attribute through the getter has the advantage of providing encapsulation. The use of an instance variable to store the value is an implementation detail in some respects. Whether that's appropriate is, of course, situational. I don't recall reading anything explicit this style issue, however.
Found https://softwareengineering.stackexchange.com/questions/181567/should-the-methods-of-a-class-call-its-own-getters-and-setters, which discusses the issue from a language-independent point of view. Also found https://www.ruby-forum.com/topic/141107, which is ruby-specific, although it doesn't break any new ground, let alone imply a Ruby standard.
Update: Just came across the following statement on page 24 of http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330/ref=sr_1_1?s=books&ie=UTF8&qid=1376760915&sr=1-1, a well-respected book on Ruby: "Hide the variables, even from the class that defines them, by wrapping them in methods." (emphasis added). It goes on to give examples of methods in the class using the accessor methods for access.
I would favor retrieving the value from #bar explicitly. Are there any
opinions on this?
Yes, direct access is not as flexible of a design. Getters and setters can be used to transform values. That is why java programmers spend half their lives banging out do nothing setters and getters for their private variables--they want to present the setters and getters as their api, which allows them to change their code in the future to transform values on the way in or the way out without changing the api.
Then ruby came along with the neat attr_accessor method, which meant that writing do nothing setters and getters wasn't painful anymore.
Python goes one step further. In python, instance variables are public and you can directly access them, e.g.
print my_dog.age
A java programmer writing a python program would implement get_age() and set_age() methods:
class Dog:
def get_age(self):
return self.age
def set_age(self, age):
self.age = age
The java programmer would then fly over all the towns in the land and drop leaflets describing the getter and setter methods as the api for getting and setting the age instance variable, and they would warn people not to access the instance variables directly--or else things might break.
However, python has a feature that allows programmers to eliminate getters and setters until they are actually needed to do something useful--rather than dumbly getting or setting a value. Python allows you to transform direct access to instance variables by client code into method calls. To the client it's transparent. For instance, the client code may be accessing an instance variable in a class by writing:
my_dog.age
Python allows the writer of the class to subsequently implement a method named age(), and my_dog.age can be made to call that method instead of directly accessing the instance variable (note that in python, unlike in ruby, you can't normally call a method without the parentheses). The newly implemented age() method can then do anything it wants to the age instance variable before returning it to the client code, e.g. transform it into human years, or retrieve the age from a database.
It's actually faster to use a getter, mainly because attr_reader and attr_accessor are written in C instead of Ruby.
As someone who's been coding Ruby for a few years, I think using attr_* is much more readable. But that's probably just something I've gotten used to.
This is not specific to Ruby, but I happen to be using Ruby at the moment.
Here is a class that provides text printing functionality.
class Printer
# some static methods
def self.fancy_print(text)
# do fancy formatting
end
def self.print(text)
fancy_print(text)
end
# some instance methods
def initialize(text)
#text = text
end
def print
#somehow call fancy_print(#text)
end
end
Is it bad design to provide both instance and static methods in a class?
Sometimes I would like to keep several instances of Printer lying around. Other times, I just need to say Printer.print(text) and just grab that text without bothering to store it for later, hence resulting in a static print method and an instance print method.
No, it's not bad design.
It's completely normal–some methods are class methods, some are instance methods. I'm not sure what the perceived issue might even be. It's somewhat difficult to even find classes with only one or the other, although in Java you frequently see static utility classes.
Edit IMO the question is misleading; you're actually asking if it's bad design to have static and instance methods of the same name.
It's tricky if both are public because it isn't necessarily obvious how to use the class. In other words, is it designed to be used via the static, or instance method? Both? What's different about them? Should that difference be... differentiated by a name?
Ultimately it depends on context and usage–there's no single answer.
That's okay, I think. Here's how you would code the Printer#print method
class Printer
def print
self.class.fancy_print(#text)
end
end
There is nothing wrong with having class methods and instance methods for a specific class, as long as they make sense belonging to the class.
I.e. what does fancy_print do? Is it something specific to the Printer class. If it is, then you shouldn't worry.
On the other hand, if it is to be used for any string value, you can do something cheekier, i.e. adding this method to the string class
String.class_eval do
def fancy_print
## implementation
end
end
Now you can do "Hello".fancy_print
Hope this answer was of any use. Also write test cases!