Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby - Structs and named parameters inheritance

This question is strictly about Struct behavior, so please no "why in the wide world of sports are you doing it that way?"

This code is INCORRECT, but it should illustrate what I am trying to understand about Ruby Structs:

class Person < Struct.new(:name, :last_name)
end

class ReligiousPerson < Person(:religion)
end

class PoliticalPerson < Person(:political_affiliation)
end

### Main ###

person = Person.new('jackie', 'jack')
pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
political_person = PoliticalPerson.new('frankie', 'frank', 'Connecticut for Lieberman')

As you can see, there's an attempt to define a class inheritance using Structs. However, Ruby gets cranky when you try to initialize ReligiousPerson or PoliticalPerson, of course. So given this illustrative code, how is it possible to inherit named params using this type of class inheritance using Structs?

like image 403
keruilin Avatar asked Jul 31 '11 17:07

keruilin


People also ask

How does inheritance work in Ruby?

How does Inheritance Work in Ruby? 1 Here class A is the parent class and it contains the method a. 2 Class B and Class C are the subclass which are inheriting the properties of class A. 3 When we use the command B < A and C < A, class C and class B will get the reference of the attributes stored for method A. More items...

How to create structs in Ruby?

How to Create Structs in Ruby. You can create a Struct by calling new & passing in a list of symbols that’ll become the instance variables of this class. They’ll have accessor methods defined by default, both for reading & writing. Here’s an example: Person = Struct.new(:name, :age, :gender) Now you can create a objects like this:

Can a class have its own object in Ruby?

You can also add its own objects, methods in addition to base class methods and objects, etc. Note: By default, every class in Ruby has a parent class. Before Ruby 1.9, Object class was the parent class of all the other classes or you can say it was the root of the class hierarchy.

What is the parent class of fruit in Ruby?

Fruit (more generic) is the parent class of Orange (more specific). In Ruby it looks like this: One of the implications of inheritance in Ruby is that every method & every constant defined on Food will be available on Fruit, and also on Orange.


2 Answers

You could define new Structs, based in Person:

class Person < Struct.new(:name, :last_name)
end

class ReligiousPerson < Struct.new(*Person.members, :religion)  
end

class PoliticalPerson < Struct.new(*Person.members, :political_affiliation)
end

### Main ###

person = Person.new('jackie', 'jack')
p pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
p political_person = PoliticalPerson.new('frankie', 'frank', 'Connecticut for Lieberman')

Result:

#<struct ReligiousPerson name="billy", last_name="bill", religion="Zoroastrianism">
#<struct PoliticalPerson name="frankie", last_name="frank", political_affiliation="Connecticut for Lieberman">

Immediate after posting my answer I had an idea:

class Person < Struct.new(:name, :last_name)
  def self.derived_struct( *args )
    Struct.new(*self.members, *args)
  end
end

class ReligiousPerson < Person.derived_struct(:religion)  
end

class PoliticalPerson < Person.derived_struct(:political_affiliation)
end

### Main ###

person = Person.new('jackie', 'jack')
p pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
p political_person = PoliticalPerson.new('frankie', 'frank', 'Connecticut for Lieberman')

Works fine!

You may also add #derived_struct to Struct:

class Struct
  def self.derived_struct( *args )
    Struct.new(*self.members, *args)
  end
end
like image 73
knut Avatar answered Oct 02 '22 07:10

knut


Ruby gets cranky when you try to initialize ReligiousPerson or PoliticalPerson, of course

I think it's more likely that it's erroring out when you try to define ReligiousPerson and PoliticalPerson. This is because Person(:religion) looks like an attempt to call Person as if it were a function. Obviously, that's not going to work because Person is a class.

It's perfectly valid though to subclass Person:

class ReligiousPerson < Person
  attr_accessor :religion

  def initialize(name, last_name, religion)
    super(name, last_name)
    @religion = religion
  end
end

pious_person = ReligiousPerson.new('billy', 'bill', 'Zoroastrianism')
pious_person.religion #=> "Zoroastrianism"

Struct.new isn't really doing anything special by the way, it's just dynamically creating a class based on the values you pass it. You are then creating a new class (Person) which subclasses the class created by Struct.new:

new_struct = Struct.new(:name, :last_name)
class Person < new_struct
end  

Person.superclass == new_struct #=> true

Also, you may want to take note of this property of some of the previous answers:

class Person < Struct.new(:name, :last_name)
end

class ReligiousPerson < Struct.new(*Person.members, :religion)  
end

ReligiousPerson.ancestors.include?(Struct) #=> true
ReligiousPerson.ancestors.include?(Person) #=> false

If you do it that way, ReligiousPerson is actually not a subclass of Person.

like image 37
Ajedi32 Avatar answered Oct 02 '22 09:10

Ajedi32