Inheriting from Array or not

Hi all !

Until now I refrained myself to use a class that inherits from array.

class Register
end

class CPU
  @regs : Array(Register)
end

But I’ve added more and more functions to the CPU class to handle registers, like

add_register(reg : Register)
add_register(name : String, size : Int32, index = false, virtual = false, reserved = false)
add_virtual_registers(num : Int32, reg_size : Int32)
find_good_registers(size : Int32) : Array(Register)

And so on

At the end, I think I should make the Register class inherit from Array and move these functions to the Register class

I say inherit because I still want to say
some = registers.select{|r| some_cond}

Seems logical, but your advice is welcome - Do you see any caveat ?

Edit : Question 2 - if inheriting from Array makes sense, should I rename the Register class to Registers ?

Edit 2 : Question 2 is silly - I need to create a Registers class but keep the Register one, because Registers will be a bag of Register

Edit 3 : So, RegPool is a better name ;-)

I think it’s a bad idea. I think you’d be better off including Enumerable(T) - Crystal 1.11.2 and having it be based on the wrapped array. Gives you the same benefits but without the code smells associated with inheriting from a type you don’t own.

I’d also look into forward_missing_to and/or delegate. These will allow you to use methods defined on Array directly on your CPU type. The main difference between the two, is forward_missing_to basically exposes all Array methods, while delegate only exposes those you whitelist explicitly. It won’t help with everything, but would allow replacing #add_register with #<< without manually defining #<< manually.

3 Likes

I understand the first part of your answer and will go that way, I didn’t even thinked about using Enumerable, so good point here

But the second part is black magic to me, but don’t worry I’ll come back on it at a later time

Always prefer composition over inheritance. It makes you life much easier in the long run.

And more specifically, I’d advice specifically not to inherit any classes that you don’t own or which are explicitly meant to be inherited (for implementation of a strategy pattern, for example).

1 Like

Yep I agree, Go for example does enforce composition because there’s no inheritance and I like the idea, but really the “include Enumerable” is puzzling me

I remember to had a lot of chat on Discord about this topic, around march 2023 or so… And I barely get the point - Not only about Enumerable but also Indexable

For now I changed my mind about Crystal : if I don’t understand something, don’t use it and see later because the topics covered by the language are very very wide. I could ask some help about my RegPool, at the end some of you will provide a answer and I’ll copy/paste/adapt to my need but without really understanding what’s going on.

So, I’ll keep it in my mind and try to find a better solution with Enumerable at a later time - Inheriting from Array works, so let’s go further

1 Like

I don’t think this is a good approach. Spend the extra time to understand the proper solution to your problem(s). This will not only make future programs easier as you have a greater breadth of knowledge, but also make your application easier to maintain. Otherwise you’re just introducing foot guns and tech debt into your application that could have been avoided from the start.

They’re basically just helper mixins (traits if you’re familiar with PHP). Including the module defines a bunch of helper methods related to enumerating a type, of which you gain by just implementing a single method. E.g. something like


def each(&)
  @arr.each do |item|
    yield item
  end
end

Indexable is similar, but intended for if your collection object is array like in that it can access things at specific indexes. Including Indexable implicitly includes Enumerable

Today I switched from Array inheritence to Enumerable and it’s been smooth

I don’t know why I was thinking that Enumerable where hard to grasp, may be caused by this old Discord chat where I was trying to do kindof recursive enumeration or so… I don’t remember well

No matter, thanks all for your help !

3 Likes