Proc and super: How can I apply a "proc pattern" in a superclass-subclass relationship?

I am a newbie on a journey to learn Ruby and Rails.

My toy project has a class hierarchy. All subclasses of a certain class have a method with this structure:

def mymethod
  code_A_common_to_subclasses
  subclass_specific_code
  code_B_common_to_subclasses
end

Normally, this would be an excellent case for yield:

def mymethod
  code A
  yield
  code B

where the subclass-specific code would be in a block provided to mymethod.

Since several subclasses use mymethod, it should be implemented in the superclass. However, my head spins trying to understand how a subclass can provide its subclass_specific_code block to the superclass method.

Does this make sense at all? Can this be done as outlined? How would you implement such a pattern?

Won’t you be better served with a lambda?

Why don’t you create a simple class hierarchy to demonstrate your intention clearly.

Re-reading your post I can recommend that you revisit the basics of object orient coding. In your re-reading, I would concentrate on modules and inheritance and how they are used to construct classes.

Thanks much, I will definitely review what I learned. However for now I would like to understand what I am missing. If you have enough patience to look into this sample hierarchy:

class Parent
  def initialize(a, b)
    @a = a
    @b = b
  end
end

class Child1 < Parent
  def initialize
    super
    @c1 = 23
  end
  def mymethod(n)
    @a += n
    @c1 -= n
    puts "#{@a} #{@b}"
  end
end

class Child2 < Parent
  def initialize
    super
    @c2 = 33
  end
  def mymethod(n)
    @a += n
    @c2 -= n
    puts "#{@a} #{@b}"
  end
end

So, the two mymethod definitions look very similar, with identical blocks at their beginning and end, and a subclass-specific block in the middle. I consider it a waste to have almost identical copies of mymethod in several subclasses (let alone the potential for errors due to redundancy).

I would like to define mymethod in Parent and only define the sub-class-specific code in Child1 and Child2. Is this the right way, is there a better way, is there no way?

Well you can define mymethod in parent and then override it in the child classes and use super in the child classes’s mymethod.

Something like this?

class Parent

  def initialize
  
    @parent_stuff = "This is some parent stuff"
  
  end
  
  def to_s
  
    "Parent Stuff: #{@parent_stuff} " + super.to_s
  
  end

end

class ChildOne < Parent

  def initialize
    
    super
    @childOne_stuff = "This is some childOne stuff"
  
  end
  
  def to_s
  
    "ChildOne Stuff: #{@childOne_stuff} " + super.to_s
  
  end

end

class ChildTwo < Parent

  def initialize
    
    super
    @childTwo_stuff = "This is some childTwo stuff"
  
  end
  
  def to_s
  
    "ChildTwo Stuff: #{@childTwo_stuff} " + super.to_s
  
  end

end

other = Parent.new

puts other

me = ChildOne.new

puts me

you = ChildTwo.new

puts you

Class isn’t considered a superclass with ruby.
With this being said you can have subclasses of classes as posted above.

super classes are modules and do not require to alias to the rest of the classes.

module Superclass
$a = “this string is in the superclass”
$b = “this string is for the second class”
end

class My_class
puts $a
end
class My_class2
puts $b
end

Anything inside module can be used by any classes globally inside the code.

Try and experiment with this

module Super_procs
$a = proc{puts “this proc is using a global variable inside a module”}

@a = proc{puts "this proc is using a instance variable inside the same module}

end

class My_class
$a.call
@a.call
end

How come all the super classes are modules?

It’s how Ruby was designed.

Classes can be subclasses to one another to incorporate code in the parent class, where as modules by the interpreter are super classes. Any data inside a module can be shared by any class. On top of that, data in modules can be used by any programs that require or load the module.

For regular classes, they cannot pull data from each other without aliasing them.

class Animal
attr_accessor :name , :type , :age
end

Class Cat
end

In order for the Cat class to use the data from the Animal class, you need to alias(or link them) together.

class Cat > Animal
end

smokey = Cat.new
smokey.name = “Smokey”
smokey.type = “feline”
smokey.age = 2

You will have to do this for every new class you make that uses the data from the Animal class. This is where modules come to play. By making the Animal class into a module,. Any new class can use the Animal data.

module Animal
attr_accessor :name , :type , :age
end

The Cat class will now look like this.

class Cat
Include Animal
end

honey = Cat.new
honey.name = “Honey”

Ruby is built for “only code once”. You don’t want to have to recode something from another class for every new class. Modules help this process. Becuase now you have a super class you can include into all new classes which has its own attributes and variants. Now we can expand the Cat class.

class Cat
include Animal
attr_accessor :breed , :tailed, :tailess
end

And a new Dog class.

class Dog
include Animal
attr_accessor :pedigree , :stature, :woof
end

Another main difference between modules and classes is that you cannot use variables, global variables, or instance variables between two classes unless you make one a child class.

In modules, you can use global variables inside or outside of classes without including or aliasing it.

Modules can also contain classes inside of it.

When I write this code:

class Animal
end

class Cat > Animal
end

I get SyntaxError… Have you rechecked it?

Woops I flipped the sign by mistake.
Should be

class Animal
end

class Cat < Animal
end.

Classes don’t always have to include/extend/prepend modules. Modules can be used without classes as well. For example, the Kernel module. You can define method:

Kernel.define_method(:hello) { |&block| block === self }
p 5.hello { |x| x.next }    # => 6
p 'hell'.hello { |s| s + ?0 }    # => "hell0"

And you have the hello method on every single object…

Also look at the 2D game development gem, Ruby2D. Where Ruby2D is a module… The Ruby2D module has classes. For example:

# Ruby2D::Window
module Ruby2D
    class Window
        <codes>
    end
end

And there’s the Net module, which has the HTTP class, which is from the standard library… There’s not much reason to write Net::HTTP, you can just Object.include(Net)!!

So basically there are a ton of reason to use the modules…

In general modules are used as an alternative to multiple inheritance because Ruby doesn’t support one class to inherit multiple classes…

Yes pretty much. Modules and classes work the same for those few exceptions. Modules are higher than classes in the chain.

Modules can be standalone, have nested classes, even act like a library for any class without needing in

And there are a Ton of options to use in ruby. Instead of puts you can use the stdout option, gets is a extension of stdin,. Instead of system Kernel.system or back ticks, etc. And if I remember right def is the short hand for Kernel.define_method.

Module is the Parent of Class

What is the super-class of Class?
p Class.superclass
This prints
Module

https://rubyplus.com/cheatsheets/561-ruby-class-object-and-module-hierarchy

Thanks a lot! Meanwhile, I also found that my thinking was too complex: I didn’t know that I can call a Child method in Parent. That makes it much easier. No need to think about blocks.

My code is nicer and shorter now.

Cufe says:

Class isn’t considered a superclass with ruby.

The official Ruby documentation says:

In OO terminology, the smaller class is a subclass and the larger class is a superclass .

That’s also my definition. No modules around here.