Say I have a parent class:
class Stat
def val
raise "method must be implemented by subclass"
end
end
And a subclass:
class MyStat < Stat
def val
#performs costly calculation and returns value
end
end
By virtue of extending the parent class, I would like the subclass to not have to worry about caching the return value of the "val" method.
There are many patterns one could employ here to this effect, and I've tried several on for size, but none of them feel right to me and I know this is a solved problem so it feels silly to waste the time and effort. How is this most commonly dealt with?
Also, it's occurred to me that I may be asking the wrong questions. Maybe I should't be using inheritance at all but composition instead.
Any and all thoughts appreciated.
Edit:
Solution I went with can be summed up as follows:
class Stat
def value
#value ||= build_value
end
def build_value
#to be implemented by subclass
end
end
Typically I use a simple pattern regardless of the presence of inheritance:
class Parent
def val
#val ||= calculate_val
end
def calculate_value
fail "Implementation missing"
end
end
class Child < Parent
def calculate_val
# some expensive computation
end
end
I always prefer to wrap the complex and expensive logic in its own method or methods that have no idea that their return value will be memoized. It gives you a cleaner separation of concerns; one method is for caching, one method is for computing.
It also happens to give you a nice way of overriding the logic, without overriding the caching logic.
In the simple example above, the memoized method val is pretty redundant. But the pattern it also lets you memoize methods that accept arguments, or when the actual caching is less trivial, maintaining that separation of responsibilities between caching and computing:
def is_prime(n)
#is_prime ||= {}
#is_prime[n] ||= compute_is_prime
end
If you want to keep the method names same and not create new methods to put logic in, then prepend modules instead of using parent/child inheritance.
module MA
def val
puts("module's method")
#_val ||= super
end
end
class CA
def val
puts("class's method")
1
end
prepend MA
end
ca = CA.new
ca.val # will print "module's method" and "class's method". will return 1.
ca.val # will print "module's method". will return 1.
Related
I apologize up front. I'm going to struggle articulating this question.
TL;DR - I have an object I'm using to call a method in the subclass. That method needs access to a method in a parent class (forcing inheritance...read below). I'm thinking this won't work because I'm instantiating the subclass, so the inheritance won't work right, but I'm not sure. I'm still seeking out documentation. Basically, the method in the parent class is not "seen" the way I'm doing this - NoMethodError is the exception.
I prefer DRY code, as most people do. I usually use compositing in lieu of inheritance in my code, but I think I'm at a point where if I want to keep this DRY, I have to use inheritance (though I could be wrong, so I'm open to suggestions), and so I'm trying it out, which leads me to this question.
Given the following Ruby "pseudo" code or example to kind of demonstrate what I'm trying to accomplish:
module SomeModule
class ParentClass
def initialize
end
def method_i_want_to_use(arg1, *args)
# does all the things
end
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.class.method_i_want_to_use(arg1, arg)
end
end
end
And then in a different file, same module
module SomeModule
class SubClass < ParentClass
def initialize
end
# this isn't working
def my_other_method
# things get done and then
method_i_want_to_use(arg1, args) ## <<=== fails
end
end
end
Yet in another file
module SomeModule
class Thing
def initialize
#my_obj = SubClass.new
end
def my_method
#my_obj.my_other_method
end
end
end
So one important thing I missed. The method method_i_want_to_use is a method that is used all over the place in my code. It just so happens that in this one class, inheritance was NOT originally used because this class is basically atomic with the exception of this one method. So my problem is either I copy the method into this class and use it (but that kinda breaks the DRY principle sorta) or I find a way to share this method between classes.
This gets into OOP design pretty heavily and I am aware of that. One could ask: well, is the inheritance as it currently sits even relevant to the objects in question? Yes...and no. They can be. In short, principally, it works, but frankly, I don't like it. TBH, I almost prefer to just copy the method into the "subclass" and remove the inheritance and be done with it, but DRY -- unless I'm going a little too wild with DRY in this context and I kinda think I am.
Anyway, just curious what folks with more knowledge than I have for me on this. This really is the first time I've dabbled this deeply into inheritance. :)
I'd love pointers on how I can keep from implementing
There are two different methods here:
an instance method:
def method_i_want_to_use(arg1, *args)
# does all the things
end
and a class method:
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.class.method_i_want_to_use(arg1, arg)
end
but what you probably want in this case is
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.new.method_i_want_to_use(arg1, arg)
end
There are a few choices and it depends on what method_i_want_to_use is doing. Is it a separate thing? Then you can call it as a class method ParentClass.method_i_want_to_use inside the SubClass without inheritance.
Another way is to define it in a module and include it
include ModuleX
# and then in your code
method_i_want_to_use(...)
I'd use inheritance if you want to have some kind of common abstraction layer and you expect multiple subclasses to behave the same way. If the classes/objects that need to use method_i_want_to_use have different behaviours then inheritance is not the correct choice. Let's say you have a class that send a request to a 3rd party API and you have a class that does saves records to your db. For some reason you need to use the same piece of code (a method) in both cases, maybe to calculate some value. Using inheritance to include the method would be a mistake, because both classes have different behaviours.
Hope that helps.
After fixing some of the syntax errors and changing the call self.class.method_i_want_to_use to self.new.method_i_want_to_use as Adam also mentioned in his answer, this code seems to work fine.
I did not get any undefined methods until I tried to call SomeModule::ParentClass.method_i_want_to_use(3,4) and that was fixed by the change from class to new. Are you sure your undefined method error was not related to that?
module SomeModule
class ParentClass
def initialize
end
def method_i_want_to_use(arg1, *args)
# does all the things
puts "here #{arg1} , #{args}"
end
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.new.method_i_want_to_use(arg1, arg)
end
end
end
module SomeModule
class SubClass < ParentClass
def initialize
end
# this isn't working
def my_other_method(arg1, arg2)
# things get done and then
method_i_want_to_use(arg1, arg2) ## <<=== fails
end
end
end
module SomeModule
class Thing
def initialize
#my_obj = SubClass.new
end
def my_method(arg1,arg2)
#my_obj.my_other_method(arg1, arg2)
end
end
end
SomeModule::Thing.new.my_method(1,2)
SomeModule::ParentClass.method_i_want_to_use(3,4)
prints:
here 1 , [2]
here 3 , [4]
I'm wondering if there's a convention / best practice for how initialize should be used when building Ruby classes. I've recently built a class as follows:
class MyClass
def initialize(file_path)
#mapped_file = map_file(file_path)
end
def map_file(file_path)
# do some processing and return the data
end
def run
#mapped_file.do_something
end
end
This uses initialize to do a lot of heavy lifting, before methods are subsequently called (all of which rely on #mapped_data).
My question is whether such processing should be handled outside of the constructor, with initialize used simply to store the instances' inputs. Would the following, for example, be preferable?
class MyClass
def initialize(file_path)
#file_path = file_path
end
def run
mapped_file.do_something_else do
etc_etc
end
end
def mapped_file(file_path)
#mapped_file ||= map_the_file_here
end
end
I hope this question isn't considered too opinion based, but will happily remove if it's deemed to be.
So, is there a 'correct' way to use initialize, and how would this fit with the scenarios above?
Any questions or comments, let me know.
As was mentioned in the comments, constructor is usually used to prepare the object, not do any actual work. More than a ruby convention, this a rule of thumb of almost all Object-Oriented languages.
What does "preparing the object" usually entail? Initializing members with default values, assigning passed arguments, calling the initializer of a super-class if such exists, etc.
In your case, this how I would rewrite your class:
class MyClass
def initialize(file_path)
#file_path = file_path
end
def map_file
#mapped_file ||= map_file_here(#file_path)
end
def run
map_file.do_something
end
end
Since run requires the file to be mapped, it always calls map_file first. But the internal map_file_here executes only once.
Due to the fact that Ruby doesn't support overloading (because of several trivial reasons), I am trying to find a way to 'simulate' it.
In static typed languages, you mustn't use instanceof, (excepting some particular cases of course...) to guide the application.
So, keeping this in mind, is this the correct way to overload a method in which I do care about the type of the variable? (In this case, I don't care about the number of parameters)
class User
attr_reader :name, :car
end
class Car
attr_reader :id, :model
end
class UserComposite
attr_accessor :users
# f could be a name, or a car id
def filter(f)
if (f.class == Car)
filter_by_car(f)
else
filter_by_name(f)
end
end
private
def filter_by_name(name)
# filtering by name...
end
def filter_by_car(car)
# filtering by car id...
end
end
There are cases where this is a good approach, and Ruby gives you the tools to deal with it.
However your case is unclear because your example contradicts itself. If f.class == Car then filter_by_car accepts a _car, not a _car_id.
I'm assuming that you're actually passing instances of the class around, and if so you can do this:
# f could be a name, or a car
def filter(f)
case f
when Car
filter_by_car(f)
else
filter_by_name(f)
end
end
case [x] looks at each of its when [y] clauses and executes the first one for which [y] === [x]
Effectively this is running Car === f. When you call #=== on a class object, it returns true if the argument is an instance of the class.
This is quite a powerful construct because different classes can define different "case equality". For example the Regexp class defines case equality to be true if the argument matches the expression, so the following works:
case "foo"
when Fixnum
# Doesn't run, the string isn't an instance of Fixnum
when /bar/
# Doesn't run, Regexp doesn't match
when /o+/
# Does run
end
Personally, I don't see a big problem in branching that way. Although it would look cleaner with a case
def filter(f)
case f
when Car
filter_by_car(f)
else
filter_by_name(f)
end
end
Slightly more complicated example involves replacing branching with objects (ruby is oop language, after all :) ). Here we define handlers for specific formats (classes) of data and then look up those handlers by incoming data class. Something along these lines:
class UserComposite
def filter(f)
handler(f).filter
end
private
def handler(f)
klass_name = "#{f.class}Handler"
klass = const_get(klass_name) if const_defined?(klass_name)
klass ||= DefaultHandler
klass.new(f)
end
class CarHandler
def filter
# ...
end
end
class DefaultHandler # filter by name or whatever
def filter
# ...
end
end
end
There could be a problem lurking in your architecture - UserComposite needs to know too much about Car and User. Suppose you need to add more types? UserComposite would gradually become bloated.
However, it's hard to give specific advice because the business logic behind filtering isn't clear (architecture should always adapt to your real-world use-cases).
Is there really a common action you need to do to both Cars and Users?
If not, don't conflate the behavior into a single UserComposite class.
If so, you should use decorators with a common interface. Roughly like this:
class Filterable
# common public methods for filtering, to be called by UserComposite
def filter
filter_impl # to be implemented by subclasses
end
end
class FilterableCar < Filterable
def initialize(car)
#car = car
end
private
def filter_impl
# do specific stuff with #car
end
end
class DefaultFilterable < Filterable
# Careful, how are you expecting this generic_obj to behave?
# It might be better replace the default subclass with a FilterableUser.
def initialize(generic_obj)
# ...
end
private
def filter_impl
# generic behavior
end
end
Then UserComposite only needs to care that it gets passed a Filterable, and all it has to do is call filter on that object. Having the common filterable interface keeps your code predictable, and easier to refactor.
I recommend that you avoid dynamically generating the filterable subclass name, because if you ever decide to rename the subclass, it'll be much harder to find the code doing the generating.
I have a class in Ruby that holds some stuff, I'll call FooBox:
class FooBox
...
end
I have two possible backing-data stores for FooBox called BoxA and BoxB with different characteristics but the same interface:
class BoxA
include Enumerable
def put_stuff(thing)
...
end
end
class BoxB
include Enumerable
def put_stuff(thing)
...
end
end
How can I instantiate a FooBox, and, based on a parameter, decide whether to back it with a BoxA or BoxB implementation? I do not want to pass in the implementation into the constructor; I only want to pass something to determine which kind to use.
class FooBox
def initialize(implementation_choice)
# ???
end
end
I usually do something like this:
class BoxA
def self.match? options
# figure out if BoxA can be used given options
end
end
# Implement BoxB (and other strategies) similarly to BoxA
class FooBox
STRATEGIES = [BoxA, BoxB]
def initialize options
#options = options
end
def strategy
#strategy ||= STRATEGIES.detect { |strategy| strategy.match? #options }
end
end
This keeps the responsibility of “knowing” if the strategy is able to be used within the strategy itself (rather than making the context class monolithic), and then just picks the first one in the list that says it can work.
I’ve used this pattern (and similar variations for slightly different problems) several times and have found it very clean.
The simple solution is create a mapping for the strategy's type and strategy class, just like #Andrew Marshall's solution
But to be better I would considering two things:
The strategies' holder (here is the FooxBox ) now need to know every box implenentation, and hard-coding their names to itself; this is not a flexiable
approach, considering one day you want to add another strategy, go to the code and add it? With ruby we can do it with a 'self registering' easily.
You don't want to strategies holder will return implementation wildly, I mean both 'BoxA' and 'BoxB' or someday's 'BoxXYZ' should belong to same strategy
concept, in Java, it maybe means all of them should implemente an interface, with ruby we generally do it with include SomeMoudle
In my application I use the following solution(just demo)
module Strategies
def self.strategies
##strategies ||= {}
end
def self.strategy_for(strategy_name)
##strategies[strategy_name]
end
end
module Strategy
def self.included(base)
base.class_eval do
def self.strategy_as(strategy_name)
Strategies.strategies[strategy_name] = self
end
end
end
end
class BoxA
include Strategy
strategy_as :box_a
def do_stuff
puts "do stuff in BoxA"
end
end
class BoxB
include Strategy
strategy_as :box_b
def do_stuff
p "do stuff in BoxB"
end
end
## test
Strategies.strategy_for(:box_a).new.do_stuff
Strategies.strategy_for(:box_b).new.do_stuff
If you want to detect strategy with match block, you can change strategy_as to accept a block. then use Strategies.strategy_for{...}.new.do_stuff
I am working with data structures fundamentals in Ruby for learning at the CS sophomore/junior level.
My question: Given the following code, does anyone see any design issues with this approach to a data structures library in Ruby? Especially the Module#abstract_method. Is it okay to do this in terms of duck typing philosophy? Does this make the code clearer for people from static languages and give some semblance of an interface?
class Module
def abstract_method(symbol)
module_eval <<-"end_eval"
def #{symbol.id2name}(*args)
raise MethodNotImplementedError
end
end_eval
end
end
class AbstractObject < Object
abstract_method :compare_to
protected :compare_to
class MethodNotImplementedError < StandardError; end
def initialize
super
end
include Comparable
def <=>(other)
if is_a?(other.class)
return compare_to(other)
elsif other.is_a?(self.class)
return -other.compare_to(self)
else
return self.class <=> other.class
end
end
end
# methods for insertion/deletion should be provided by concrete implementations as this behavior
# is unique to the type of data structure. Also, concrete classes should override purge to discard
# all the contents of the container
class Container < AbstractObject
include Enumerable
def initialize
super
#count = 0
end
attr_reader :count
alias :size :count
# should return an iterator
abstract_method :iter
# depends on iterator object returned from iter method
# layer of abstraction for how to iterate a structure
def each
i = iter
while i.more?
yield i.succ
end
end
# a visitor provides another layer of abstraction for additional
# extensible and re-usable traversal operations
def accept(visitor)
raise ArgumentError, "Argument must be a visitor" unless visitor.is_a?(Visitor)
each do |obj|
break if visitor.done?
visitor.visit(obj)
end
end
# expected to over-ride this in derived classes to clear container
def purge
#count = 0
end
def empty?
count == 0
end
def full?
false
end
def to_s
s = ""
each do |obj|
s << ", " if not s.empty?
s << obj.to_s
end
self.class + "{" + s + "}"
end
end
class List < Container
def initialize
super
end
def compare_to(obj)
"fix me"
end
end
A few remarks:
Defining a method that only raises a NotImplemented error is somewhat redundant, since Ruby will do that anyway if the method does not exist. The code you wrote there is just as useful as simply putting a comment to say "You must implement a method called compare_to". In fact that is what the Enumerable module in Ruby's standard library does - in the documentation it specifically says that in order to use the functionality in Enumerable you must define an each() method.
a compare_to method is also redundant, since that is precisely what the <=> operator is for.
Using an actual iterator object is a bit overkill in Ruby, since blocks tend to have a much more elegant and simple approach. Same goes for your visitor pattern - you don't need to use a visitor for "extensible and re-usable traversal operations" when you can just pass a block to a traverse method. For example you have many of them in Enumerable: each, each_with_index, map, inject, select, delete_if, partition, etc. All of these use a block in a different way to provide a different type of functionality, and other functionality can be added on in a fairly simple and consistent way (especially when you have open classes).
Regarding interfaces, in Ruby (and pretty much any other dynamic language, like Python) people usually use interfaces that are implicit, which means that you don't actually define the interface in code. Instead you typically rely on documentation and proper testing suites to ensure that code works well together.
I think that your code may be more coherent to someone coming from a Java world because it sticks to the "Java way" of doing things. However to other Ruby programmers your code would be confusing and difficult to work with since it doesn't really stick to the "Ruby way" of doing things. For example, an implementation of a select function using an iterator object:
it = my_list.iter
results = []
while it.has_next?
obj = it.next
results << obj if some_condition?
end
is much less clear to a Ruby programmer than:
results = my_list.select do |obj|
some_condition?
end
If you would like to see an example of a data structures library in Ruby, you can see the algorithms gem here: http://rubydoc.info/gems/algorithms/0.3.0/frames
Also take a look at what is provided by default in the Enumerable module: http://www.ruby-doc.org/core/classes/Enumerable.html. When you include Enumerable you receive all of these functions for free.
I hope this helps!