About removing class side initialization

SD
stephane ducasse
Wed, Jan 17, 2024 8:37 PM

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

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
JF
James Foster
Thu, Jan 18, 2024 3:52 AM

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 stephane.ducasse@inria.fr 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

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 <stephane.ducasse@inria.fr> 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 > > > > >
PT
Pablo Tesone
Thu, Jan 18, 2024 11:06 AM

Yes to all, I always hated the #initialize in class side, I think we
should divide them. It will be easy to remove the #initialize in
Behavior and rename it to something else that is called during the real
initialization of the objects.

In the long time I think we should change the initialize name to
something like "doWhenTheClassIsInstaller" or maybe less verbose :P

I am not sure about lazy initialization, but it also is a nice solution.

Cheers,

Pablo

On 17/01/2024 21:37, stephane ducasse 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

Yes to all, I always hated the #initialize in class side, I think we should divide them. It will be easy to remove the #initialize in Behavior and rename it to something else that is called during the real initialization of the objects. In the long time I think we should change the initialize name to something like "doWhenTheClassIsInstaller" or maybe less verbose :P I am not sure about lazy initialization, but it also is a nice solution. Cheers, Pablo On 17/01/2024 21:37, stephane ducasse 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 > > > > > >
DM
David Mason
Thu, Jan 18, 2024 2:38 PM

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 <
pharo-dev@lists.pharo.org> 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 <

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

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 < pharo-dev@lists.pharo.org> 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 < > stephane.ducasse@inria.fr> 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 > > > > > > > > > > >
NB
Noury Bouraqadi
Wed, Jan 31, 2024 2:03 PM

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 dmason@torontomu.ca 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 <pharo-dev@lists.pharo.org (mailto:pharo-dev@lists.pharo.org)> 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 <stephane.ducasse@inria.fr (mailto:stephane.ducasse@inria.fr)> 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

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 <dmason@torontomu.ca> 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 <pharo-dev@lists.pharo.org (mailto:pharo-dev@lists.pharo.org)> 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 <stephane.ducasse@inria.fr (mailto:stephane.ducasse@inria.fr)> 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 > > > > > > > > > > > > > > > > >
MD
Marcus Denker
Wed, Jan 31, 2024 2:36 PM

For both #isAbstract and #initialize, one can understand both as cases where we have to use behavior for something that should actually be a kind o declarative property of the objects.

  • isAbstract

This is a property of the class.

  • initialize

This is a property of the Variable. It’s really unfortunate to have to fall back on code execution for that. What the initalize does is to say

“the default value of this Variable is this literal value”
or
“send this message to the new object to set the default value”

Anything else that you could do in #initialize is IMHO bad style.

We always are proud that “Everything is an Object”. But as soon as we talk about the language itself, Smallkers suddenly forget everything we know about objects: Everything has to be a Class or a Method ! there is no other way!

We really need to try to free ourselves from this mindset and start to model our programs better.

With fluid class defintions and First Class Variables, we can do this:

Object << #MyClass
slots: {};
sharedVariables: { #ClassVar => InitializedClassVariable default: 1 };
package: ‘MyPackage’;

(this works and even is correctly stored in GIT or even when filed out)

Instead of #isAbstract, we can just tag the class as Abstract, we could add a method on the classBuilder:

Object << #MyClass
slots: {};
sharedVariables: { };
package: ‘MyPackage’;
beAbtract

or have some way to specify properties

Object << #MyClass
slots: {};
sharedVariables: { };
package: ‘MyPackage’;
properties: {#abstract }

There is even already a property API on class, but no support on the level of the class builder / class parser yet.

And of course, we have to then make sure this is stored correctly in Git.

Marcus

On 31 Jan 2024, at 15:03, Noury Bouraqadi bouraqadi@gmail.com wrote:

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 dmason@torontomu.ca 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 <pharo-dev@lists.pharo.org mailto:pharo-dev@lists.pharo.org> 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 <stephane.ducasse@inria.fr mailto:stephane.ducasse@inria.fr> 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

For both #isAbstract and #initialize, one can understand both as cases where we have to use behavior for something that should actually be a kind o declarative property of the objects. - isAbstract This is a property of the class. - initialize This is a property of the Variable. It’s really unfortunate to have to fall back on code execution for that. What the initalize does is to say “the default value of this Variable is this literal value” or “send this message to the new object to set the default value” Anything else that you could do in #initialize is IMHO bad style. We always are proud that “Everything is an Object”. But as soon as we talk about the language itself, Smallkers suddenly forget everything we know about objects: Everything has to be a Class or a Method ! there is no other way! We really need to try to free ourselves from this mindset and start to model our programs better. With fluid class defintions and First Class Variables, we can do this: Object << #MyClass slots: {}; sharedVariables: { #ClassVar => InitializedClassVariable default: 1 }; package: ‘MyPackage’; (this works and even is correctly stored in GIT or even when filed out) Instead of #isAbstract, we can just tag the class as Abstract, we could add a method on the classBuilder: Object << #MyClass slots: {}; sharedVariables: { }; package: ‘MyPackage’; beAbtract or have some way to specify properties Object << #MyClass slots: {}; sharedVariables: { }; package: ‘MyPackage’; properties: {#abstract } There is even already a property API on class, but no support on the level of the class builder / class parser yet. And of course, we have to then make sure this is stored correctly in Git. Marcus > On 31 Jan 2024, at 15:03, Noury Bouraqadi <bouraqadi@gmail.com> wrote: > > 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 <dmason@torontomu.ca> 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 <pharo-dev@lists.pharo.org <mailto:pharo-dev@lists.pharo.org>> 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 <stephane.ducasse@inria.fr <mailto:stephane.ducasse@inria.fr>> 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 > > > > > > > > > >
GP
Guillermo Polito
Thu, Feb 1, 2024 8:45 AM

El 31 ene 2024, a las 15:36, Marcus Denker marcus.denker@inria.fr escribió:

For both #isAbstract and #initialize, one can understand both as cases where we have to use behavior for something that should actually be a kind o declarative property of the objects.

  • isAbstract

This is a property of the class.

  • initialize

This is a property of the Variable. It’s really unfortunate to have to fall back on code execution for that. What the initalize does is to say

There is out there indeed code that uses class side initialize methods to initialize class variables to constants.
But that is not the only case.

Some class side initalizes have complex initializations.
Some are used to register the loaded class to some registration mechanism.

On 31 Jan 2024, at 15:03, Noury Bouraqadi bouraqadi@gmail.com wrote:

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.

Yes, I agree. I would like to have two levels of “Metaclasses”.
Actually, one metaclass that is the traditional metaclass defining the class behavior.
One “companion” object where we can define domain concerns.

The companion object should respect the double hierarchy, but it will not class anymore with the meta-behaviour in the class!
We will be able to freely program there without mistakenly overriding critical behavior from classes :).
And we will be able to define metaclasses with really specific behavior for a single class in the hierarchy chain.

G

> El 31 ene 2024, a las 15:36, Marcus Denker <marcus.denker@inria.fr> escribió: > > For both #isAbstract and #initialize, one can understand both as cases where we have to use behavior for something that should actually be a kind o declarative property of the objects. > > - isAbstract > > This is a property of the class. > > - initialize > > This is a property of the Variable. It’s really unfortunate to have to fall back on code execution for that. What the initalize does is to say There is out there indeed code that uses class side initialize methods to initialize class variables to constants. But that is not the only case. Some class side initalizes have complex initializations. Some are used to register the loaded class to some registration mechanism. > >> On 31 Jan 2024, at 15:03, Noury Bouraqadi <bouraqadi@gmail.com> wrote: >> >> 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. Yes, I agree. I would like to have two levels of “Metaclasses”. Actually, one metaclass that is the traditional metaclass defining the class behavior. One “companion” object where we can define domain concerns. The companion object should respect the double hierarchy, but it will not class anymore with the meta-behaviour in the class! We will be able to freely program there without mistakenly overriding critical behavior from classes :). And we will be able to define metaclasses with really specific behavior for a single class in the hierarchy chain. G