From: duerst@... Date: 2015-12-16T02:11:56+00:00 Subject: [ruby-core:72167] [Ruby trunk - Feature #11708] Specify a way to override Struct-subclass constructor Issue #11708 has been updated by Martin D��rst. I'm not Matz, but in general, everything in Ruby is dynamic. The documentation doesn't say for each feature that it is going to be kept dynamic in the future. That would be a lot of useless text in the documentation. ---------------------------------------- Feature #11708: Specify a way to override Struct-subclass constructor https://bugs.ruby-lang.org/issues/11708#change-55578 * Author: Ilya Vorontsov * Status: Open * Priority: Normal * Assignee: Yukihiro Matsumoto ---------------------------------------- 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. ```ruby 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: ```ruby Point.instance_method(:initialize) # => # NonnegativePoint.instance_method(: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. -- https://bugs.ruby-lang.org/