Project

General

Profile

Actions

Feature #11708

closed

Specify a way to override Struct-subclass constructor

Added by prijutme4ty (Ilya Vorontsov) over 8 years ago. Updated over 8 years ago.

Status:
Closed
Target version:
-
[ruby-core:71553]

Description

It's common to create simple data-object with some constraints. One can either implement custom class or use Struct. Struct is generally simpler and helps to avoid some mistakes as non-defined #hash and #eql?. But at the same time it's more difficult to make validation for Struct subclass.

Point = Struct.new(:x, :y)

NonnegativePoint = Struct.new(:x,:y) do
  def initialize(*args, &block)
    super
    raise 'Negative coordinates are not allowed'  if x < 0 || y < 0
  end
end

Above written code solves the problem but has one flaw. Struct.new creates a subclass of Struct and defines some methods as #x, #x=. And there are no guarantees that NonnegativePoint#initialize wasn't redefined too.
We can check that Point.new without explicitly defined #initialize actually hits Struct#initialize and Point#initialize not defined:

Point.instance_method(:initialize)
# => #<UnboundMethod: Point(Struct)#initialize>
NonnegativePoint.instance_method(:initialize)
# => #<UnboundMethod: NonnegativePoint#initialize>

But nothing in Struct documentation or test suite states that this behavior can't be changed in newer ruby versions.

I propose either to declare in docs and test that initialize method can be safely overriden because #initialize is not defined in Struct subclasses.
In you assume that one day current behavior can change (e.g. for perfomance reasons), then it's reasonable to create an extension point like '#after_initialize' which is called from Struct's subclass #initialize method.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0