2

I am using super to pass arguments to the parent initialize method, which is not called by default. This is what it looks like. (Notice the use of super on the last two arguments)

module Pet
  def initialize name, is_pet
    @is_pet = is_pet
    if is_pet
      @name = name
    else
      @name = "Unnamed"
    end
  end
  def pet?
    return @is_pet
  end
  def get_name
    return @name
  end
end

class Dog
  include Pet
  def initialize tricks, name, is_pet
    @tricks = tricks
    super name, is_pet
  end
  def get_tricks
    return @tricks
  end
end

Here's what I can do with it:

d = Dog.new ["roll", "speak", "play dead"], "Spots", true

d.pet?       #=> true
d.get_tricks #=> ["roll", "speak", "play dead"]
d.get_name   #=> "Spots"

It works fine, but I'm just wondering if there's a better way to do this.

1
  • you don't need return as the last value is automatically the return value. Commented Sep 19, 2018 at 10:39

2 Answers 2

1
  • It is not a good programming practice to hard code a fixed string like "Unnamed" as the value for @name. In such case, you should assign nil, and do whatever modification to it when you print it. Suppose you do this.

  • Then is_pet can be deduced from whether name is nil or not, so it is redundant to have that as an instance variable. You can simply apply !! to name in order to get is_pet. Therefore, you should get rid of such instance variable.

  • You have get_ prefixes as getter methods, but in Ruby, it is a better practice to have the same name as the instance variables (without the atmark) as the getter name.

This will give you:

module Pet
  attr_reader :name
  def initialize name; @name = name end
end

class Dog
  include Pet
  attr_reader :tricks
  def initialize tricks, name
    @tricks = tricks
    super(name)
  end
end

d = Dog.new ["roll", "speak", "play dead"], "Spots"
d.tricks #=> ["roll", "speak", "play dead"]
d.name   #=> "Spots"
!!d.name #=> true (= `is_pet`)
Sign up to request clarification or add additional context in comments.

Comments

0

Do not write code that calls super to get into an included module. Don't write modules that will expect children to call super. That's not the point of modules.

It's good object oriented style to not ask about what things are. Look up "tell, don't ask" and duck typing in general.

If you want to provide a default initialize method, you probably want inheritance. But there are occasionally valid use cases for overriding initialize in a module. The idiomatic thing to do here is a hook method:

module Pet
  def initialize(options = {})
    @name = options[:name]
    post_initialize(options)
  end

  def post_initialize(options = {})
    # can be overridden in including modules
  end
end

class Dog
  include Pet

  def post_initialize(options = {})
    @tricks = options[:tricks]
  end
end

dog = Dog.new(name: "Fido", tricks: ["play dead", "roll over"])

A module is for including some shared behavior among many different things. It's good to consider it like an adjective describing what you might do with a class that includes it. Words that end in "-able" (like Enumerable or Comparable), describing a receiving class, or "-or" (Iterator, Interactor), describing a doing class, are good candidates for being modules.

1 Comment

The reason I'm using a module to do this is because I have multiple classes inheriting from the "Mammal" class. The Dog is inheriting from "Mammal" so I can't also inherit from Pet. Also pet is more of a blanket and less an object, and I thought that's what modules did.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.