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 <[email protected]> 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 <[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
> >
> >
> >
> >
> >