One of the best articles I’ve read about general programming language topics is Jonathan Amsterdam’s Java’s new Considered Harmful (click on “Print” for a less ad-cluttered version.) He criticizes the use of the new Constructor(...)
statement in Java on a functional level, concluding that “…for statically typed languages, it may not be possible to do better…”.
If you are interested in the never-ending discussion about static versus dynamic typing, I encourage you to read it. If you’re not, well, do something else.
Amsterdam also mentions Ruby’s approach to object creation, stating that it fixes a problematic behaviour of Smalltalk. Still, according to him, one problem remains:
A second drawback with […] Ruby is that initialize, being an ordinary method, does not chain: You must remember to begin your initialize methods with a call to the superclass’s initialize method.
That is true; I indeed remember having forgotten it, resulting in wild debugging. Typically, when you inherit from core classes like String
or Hash
, there’s nothing to initialize (actually, for most core classes it suffices to call allocate
instead of new
, bypassing initialize
.) When you inherit from your own classes, you are likely to remember to call super
when overriding initialize
. But when you inherit from somebody else’s class – say ActiveRecord::Base
, and you’re not DHH – you run into problems.
A {background: silver; padding: 0em 0.2em}warning: initialize method does not call super!
would be annoying, since a lot of good code would raise it. Disallowing the redefinition of initialize
in favor of a after_initialize
hook method:
class Foo def initialize ... after_initialize end def self.method_added meth if meth == :initialize raise TypeError, 'Please override after_initialize instead of initialize.' end end def after_initialize; end end
would only solve the problem for direct subclasses.
Anybody got a better idea?