On 05.11.2025 13:28, Josep Maria Blasco wrote:
Missatge de Jean Louis Faucher <[email protected]> del dia dc., 5 de nov.
2025 a les 11:56:
On 5 Nov 2025, at 11:05, Josep Maria Blasco <[email protected]>
wrote:
I can see two different topics here:
1. Clearly differentiating between object creation and object
initialization.
2. Making all objects adhere to the "NEW passes all arguments to INI" idea.
As far as I can see, item 2 can be readily fixed, but we'd run into the
risk of breaking
existing programs For example, TUTOR has been written against this anomaly,
and would require
some changes.
I agree with the risk of regression
Out of curiousity, can you show an example of impact on TUTOR?
Oh, the impact on TUTOR is really minimal, I was only using it as an example of
possible regression.
* BYTES is a subclass of STRING. It defines an INIT method that does nothing
(in particular,
it does /not/ call init:super). It's probably a remnant of a time when this
INIT method was
doing something, but I can't seem to remember.
* CODEPOINTS is a subclass of BYTES. It also has an INIT method. In this
case, the method does
some things, but it does /not/ call init:super.
* GRAPHEMES is a subclass of CODEPOINTS. INIT first calls super:init, and
then breaks the string
into graphemes.
* TEXT is a subclass of CODEPOINTS. This is the only case that would need
rewriting. A TEXT
string is auto-normalized to NFC, so that we can't store the string as-is.
That's why we have
to operate at NEW nevel. We pick the string, convert it first to NFC,
/then/ call new:super
with the just normalized string, and finally return this same string as the
result of NEW.
The important thing to remember is that NEW returns an object, while INIT doesn't return anything,
and therefore it's NEW that should be responsible for object creation.
And, indeed, as we have seen, the impact on TUTOR is null. After all, no rewriting is necessary.
But the NEW/INIT distinction is there. I think it should be explained and documented as clearly as
possible.
We could also opt for leaving things as they are, but then it would be
imperative to document
and explain the anomaly.
+1
Regarding item 1, it would be nice if we could add a new section to rexxref
(maybe 4.2.8)
called "Creation", or "Object creation". It would document the whole
process of giving birth
to an object as composed of two phases, creation and initialization. And it
should explain
that, in some cases, it can be necessary (or more convenient) to process
the arguments in
NEW, and, in other cases, in INIT.
+1
That could be illustrated by the Array class versus the Queue class.
Array's NEW checks the arguments and allocate the requested storage.
Then the INIT message is sent with no argument.
Queue is a subclass of Array, so in theory, should follow the same protocol
as Array.
Queue is a subclass of Array? You must be speaking of the implementation level (I remember the
Dallas report, where many of the collections are implemented as arrays).
>rexx -e "q = .queue~new; Say q~isa(.Array)"
0
But a design decision has been taken to let pass the NEW arguments to INIT.
QueueClass::initRexx
// It would be nice to do this expansion in the new method, but it sort
// of messes up subclasses (e.g. CircularQueue) if we steal the first
new
// argument. We will set the capacity here, even if it means an
immediate expansion
Some native classes respect the protocol "NEW sends the INIT message with
all the received
arguments):
Bag, Directory, EventSemaphore, IdentityTable, List, MutexSemaphore,
Object, Queue,
Relation, Set, StringTable, Supplier, Table.
Some native classes proceed differently:
- Class, Method, MutableBuffer, Package, Routine, Stem, String and
WeakReference
remove the arguments they use, and pass the rest to INIT
(well, there are special cases where it's not true)
- Array send the INIT message but doesn't pass the arguments
This clearly does not make any sense, it's difficult to explain, and still more difficult to
remember. If at all possible, it should be fixed. It's very ugly when you say how things should be
and and the same time you proceed differently, as it installs the idea that what you're advising
doesn't work -- even for yourself.
+1
Finally, we should stress on the fact that calling the INIT method for the
superclass is not
mandatory in all cases, but only when the initialization is, so to speak,
distributed in
several scopes. For example, in example 4.12, class Savings calls the INIT
method of its
superclass, because the superclass has to store the balance, but class
Account does not call
the INIT method of its superclass (in this case, Object). And, of course,
if some of the
built-in classes needs that its INIT method is called by subclasses, this
should also be
documented.
+1
The interpreter could be made more robust to detect when a native INIT
method has not be
called by a subclass.
Illustration with Supplier
s = .myUnitializedSupplier~new
say s~available -- Segmentation fault: 11
This is horrible. The interpreter should/ never/ crash because of a user error!
+1
::class myUnitializedSupplier subclass Supplier
::method init
say "I don't forward INIT"
Maybe one could approach these problems as follows?
* Add an INIT method to all those built-in classes that do not have an INIT
method yet, which
forward the INIT invocation to the superclass (either "self~init:super" or
"forward class
(super)", depending on the current behaviour to remain backwardly compatible)
* Change NEW in all those classes Jean Louis has identified, that do not send
an INIT message yet,
and have an INIT message sent to the newly created object with all supplied
arguments. (Make
sure that all NEW methods forward arguments, if they consume arguments so
far, only supply the
non consumed arguments? In the case of Array start to supply the
non-consumed arguments on the
INIT message which by default gets intercepted in the new INIT method needed
for Array?)
This should allow INIT methods in subclasses to get and learn about all
arguments supplied to
the NEW class method and passed on to the INIT message by it.
o Maybe let NEW consume arguments it uses, if that is the current
behaviour; if not documented
yet, this must be documented in all affected classes.
Could that solve the problem in a backwardly manner, taking care of the possible problems mentioned
so far?
Would that also solve the problem that native INIT methods get invoked by ooRexx subclasses (like
the example myUninitializedSupplier class above)?
---rony
P.S.: Sorry for the communication delays, being "under-water" at the moment with other obligations
off the computer...
_______________________________________________
Oorexx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/oorexx-devel