Stef,
Your comments brought to mind a few thoughts.
First, initialize methods should, in general, be idempotent; that is, running them repeatedly should not make further changes after the first run (along the lines of your mention of lazy initialization). For example, if a variable is nil then it should be set to an empty set; if it is already a set, don���t replace it.
Second, many packaging systems have scripts for pre-load, post-load, pre-remove, and post-remove. Instead of having initialize methods on a class, we could have scripts associated with a package. (Presumably a package will be a first-class object and have methods to handle these action.)
Third, following a model from upgrading databases, one would have a ���version number��� stored somewhere (perhaps a class variable) and scripts that upgrade and downgrade the version. Rerunning the ���upgrade��� would be idempotent since we would already be on the latest version.
As to the specific situation, yes, there is a problem with Behavior>>#initialize that arises from Behavior���s unique position where instances are classes and we have an unfortunate gratuitous polymorphism between instance initialization in which we are creating a new instance of Behavior (and giving it an empty method dictionary) and class initialization which is typically associated with _loading_ or _installing_ a class. Perhaps with a time machine the right solution would be separate names for these concepts (#initialize for instances, and #postLoad for classes). But really, the only place this is confusing is with Behavior, so maybe we should treat it as a special case rather than reaching for a general solution.
I think that rather than trying to prevent calling super initialize on classes (when failing to call super initialize on instances is a common bug) or trying to prevent an initialize from reaching Behavior>>initialize (by blocking it on the class side of Object), we should simply have Behavior>>initialize recognize its special position (and unique risk for confusion) by being idempotent. That is, if we already have a method dictionary, then there is no reason to do any further initialization; just protect the existing code with a check of ���are we already initialized?��� (Do the simplest thing that could possible work!)
So, while we could look at bigger solutions like package managers or image versions, we should just start by making Behavior>>#initialize smart enough to recognize its unique danger and handle the problem there. I don���t like the situation in which some initialize methods _must_ call super and some initialize methods _must not_ call super.
In fact, I could imagine that there are some times when class initialization _should_ call super. Perhaps I have an abstract superclass that builds and caches a list of its subclasses (in GemStone this would be non-trivial). When a new subclass is added and the subclass is initialized, I want the super initialize method to be called so the superclass can reinitialize its cache. Perhaps this is a contrived case, but the point is that it isn���t really appropriate to put in a rule that you should not send super initialize.
Just some ideas and thoughts to let you know I���m reading your posts���
James Foster
>
> Hi community
>
> I would like to get use your ideas.
>
> Here is the case
>
> Context: Class side initialize are not good.
> We fixed a bug with guille today (should do a PR) this bug was breaking some projects by changing the superclass of classes to Object. Radical!
>
> It was produced by the removal of DependentFields in Object and the removal of the class side Object initialize method
> Needed to initialize DependentFields (RIP).
>
> Doing so when a class was doing a super initialize it executes the Behavior>>#initialize (which reinitialize the class and its superclass) and was not reachable before because blocked by Object class>>#initialize.
>
> Two Situations.
>
> When we do a class super initialize there are two cases
>
> Case 1. the super reaches Behavior>>#initialize and your class gets killed.
> Solution 1. Easy we will define a class side initialize method to protect the execution of Behavior>>#initialize.
> Ideally raising a warning so that people can find their problems.
>
> Case 2.
> You have a little hierarchy Root and Subclass1 Subclass2 classes
> Root class defines an initialize method.
>
> You should not redefine initialize in Subclass1 and do a super initialize
> else we get a double initialize. Not easy to grasp so I guess that many people are making this mistake.
>
> Solution 2.
> Cyril added a rule in a ReleaseTest (yes this is cool and we should use more rules and not code by hand in the releaseTest)
> that checks for no class side super initialize in Pharo.
>
> Now long time ago I thought that this class initialize is not that good and that I would like to have
> a way that class state dependencies do not have to be resolved by the developers by initializing first A then B
> but that the system could do it automatically. In this case we would not need initialize by class construction.
>
> Do you have an idea how such design could be?
>
> I���m too dead right now to think but to me it feels a bit similar to lazy initialization.
> If all the shared variables would be only accessed by lazy accessors then we do not need to initialize them statically.
> Now this is a bit extreme but this is to illustrate my wish.
>
> So let us know :)
> Stef
>
>
>
>
>