This is indeed an issue I'd like to see solved.
Class initialization is just an instance of a more general isssue.

In SUnit, defining abstract classes is dirty. The code often looks like this

MyTestClass class>>#isAbstract
^self == MyTestClass
In PharoJS we face the issue of class specific methods. Upon transpiling to JS, 
we want to perform some actions for some classes and not their subclasses.

A possible solution is to introduce class specific properties through an 
extra-layer of metaclasses.

Noury

On Jan 18 2024, at 3:38 pm, David Mason <[email protected]> wrote:
> I like James' suggestion.
>
> It shouldn't matter if someone defines a class initialize or not, or whether 
> they call super initialize. So either Object class should have an empty one 
> (like Object>>initialize) or Behavior>>initialize should do the right thing.
>
> The Smalltalk way would be for it to go in Object class, because even 
> infrastructure code like Behavior should avoid condition checking when the 
> dispatch rules can already solve the problem.
>
> ../Dave
> On Wed, 17 Jan 2024 at 22:52, James Foster via Pharo-dev 
> <[email protected] (mailto:[email protected])> wrote:
> > 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
> >
> > > On Jan 17, 2024, at 12:37 PM, stephane ducasse <[email protected] 
> > > (mailto:[email protected])> wrote:
> > >
> > > 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
> > >
> > >
> > >
> > >
> > >
>
>

Reply via email to