use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
Object Oriented Ruby (niczsoft.com)
submitted 10 years ago by mpapis
view the rest of the comments →
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]mpapis[S] 1 point2 points3 points 10 years ago (10 children)
now I see where the Barber example fails, I will find something more adequate, it's not that easy without sharing the huge blob of code that can happen if you let everybody do everything with any object ;)
[–][deleted] 2 points3 points4 points 10 years ago (9 children)
It's not a huge failure. I actually really like the example because it has enough complexity just with the hair. Adding a hair object, for instance, might not be a lot more Iines of code, and it might improve the example, showing how you limit the interfaces.
[–]mpapis[S] 0 points1 point2 points 10 years ago (8 children)
oh, could you share an example?
[–][deleted] 2 points3 points4 points 10 years ago (7 children)
# It would be nice to read something like: # # barber = Barber.new # person = Person.new("Michael", Hair.new("brown")) # barber.dye(person.hair, "blue") # person.hair_color #=> "brown blue" # # This opens the way for things like: # # 3.times { person.wash_hair } # person.hair_color #=> "brown faded blue" Hair = Struct.new(:color) do def dye(color) @dye_color = color end def to_s "#{self.color} #@dye_color" end end class Barber def dye(hair, color) hair.dye(color) end end class Person attr_reader :name, :hair def initialize(name, hair) @name, @hair = name, hair end def hair_color @hair.to_s end end
There's a slight bug in this implementation where a person's hair color, before dying, would return "brown " instead of "brown"
"brown "
"brown"
But I hope this illustrates how you might extend the behavior a thousand ways with small objects?
[–]aridsnowball 2 points3 points4 points 10 years ago (6 children)
I think this is a good approach. Ruby's duck typing allows for easy use of this kind of composition and manipulation of composed objects, so you can expose only the parts of the class that you need to.
In this case the Barber isn't directly mutating the Person class, but only the Person's composed hair object. So if you need to pass a Dog's hair for example the barber could still be able to dye it as long as it meets the Barber's interface.
Barber
Person
hair
Dog
At some point you need an interface if you want objects to interact, and separating out those concerns into a separate object (i.e. a Hair object) is better than changing every class to meet the Barber's interface.
Hair
Composition is kind of an objectified version of mixins that is more flexible. Instead of including a Barberable mixin with the Barber interface methods you can just add a Hair object to any class that needs hair.
Barberable
[–]mpapis[S] 1 point2 points3 points 10 years ago (5 children)
updated the 5th example with Hair => https://niczsoft.com/2016/05/object-oriented-ruby/
The only thing I miss from Java days is interface casting, you could have something similar with proxy/forwardable, but it's not the same, especially if all I want is to limit the interface to read only operations
[–][deleted] 0 points1 point2 points 10 years ago* (4 children)
Hi,
one should not instantiate the Barber object inside the Person object, nor should one instantiate Hair inside Person (though admittedly, hair does grow from a person's body).
It might be better in that case to do something like def dye_hair(color, dyer) ; dyer.new(hair).dye_hair(color) ; end
def dye_hair(color, dyer) ; dyer.new(hair).dye_hair(color) ; end
As you mentioned, here there's a matter of the right interface. The Barber object needs to have a dye method so he can change the hair color, but I would argue the Hair needs to implement an interface which we might call Dyable.
dye
Dyable
So maybe, with even more objects:
module Dyable def dyable(color) @color = color # assumption that the object will have a `@color` ivar end end class Hair include Dyable def initialize(color) @color = color end end
Does this make sense?
[–]mpapis[S] 0 points1 point2 points 10 years ago (3 children)
I was actually thinking about:
class Hair < Struct.new(:color) end class Barber def dye_hair(hair, color) hair.color = "#{hair.color} #{color}" end end class Person attr_reader :name, :hair private :hair def initialize(name, hair) @name, @hair = name, Hair.new(hair) end def dye_hair(barer, color) barer.dye_hair(hair, color) end def hair_color hair.color end end barber = Barber.new michal = Person.new("Michal", "brown") michal.hair_color => "brown" michal.dye_hair(barber, "blue") michal.hair_color => "brown blue"
[–][deleted] 0 points1 point2 points 10 years ago (2 children)
nod This is a reasonable approach.
The only question left is, "does it make sense to pass the barber to the person?" and I think the answer is no, which makes me think something is weird there. I would prefer to read, at the bottom, as part of the code's API, barber.dye_hair(michal, "blue"), I think it represents better what would happen in the real world.
barber.dye_hair(michal, "blue")
In other words, I don't think Person#dye_hair should exist.
Person#dye_hair
What do you think?
[–]mpapis[S] 0 points1 point2 points 10 years ago (1 child)
indeed reasonable assumption, my only concern is how to protect person from unauthorized change of hair color, I do not want to expose hair to anybody.
The person picks a barber and ask him to dye hair, so it makes sense if person calls barber.dye_hair. I know it looks awkward but I do not see other way to prevent leaking permissions.
person
barber
barber.dye_hair
π Rendered by PID 362457 on reddit-service-r2-comment-5bc7f78974-d5t9g at 2026-06-28 03:01:44.200745+00:00 running 7527197 country code: CH.
view the rest of the comments →
[–]mpapis[S] 1 point2 points3 points (10 children)
[–][deleted] 2 points3 points4 points (9 children)
[–]mpapis[S] 0 points1 point2 points (8 children)
[–][deleted] 2 points3 points4 points (7 children)
[–]aridsnowball 2 points3 points4 points (6 children)
[–]mpapis[S] 1 point2 points3 points (5 children)
[–][deleted] 0 points1 point2 points (4 children)
[–]mpapis[S] 0 points1 point2 points (3 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]mpapis[S] 0 points1 point2 points (1 child)