I admit this is a feature I've wanted for some time but was not sure how to
actually do it. Since Erich opened the feature request, I thought I should
give it a closer look. I've gotten far enough into this that I believe it
can be done, with some restrictions. There are a few items where decisions
need to be made on which direction to proceed.

So, basically this will work by building a special method that runs on the
class object during the package install process. Each class directive will
have its own special method and the instructions executed will be any
::constant directive that has a non-constant expression value. There should
be no restrictions on the expressions and the variables SELF and SUPER will
have the expected values for a method run on a class object. The
expressions when run will be traceable if ::options trace is used, even
interactive trace. I've got most of the mechanisms on how to do all of this
worked out and it looks pretty clean.

My first thought was to apply the current rules for parsing ::CONSTANT and
anything that fell outside of the current rules would be a constant. This
works, but there is a gotcha. The current rules allow constants to be
defined using

::constant aconstant foo

where foo is a symbol treated as a constant. Going this route means

::constant aconstant self
::constant anotherConstant (self)

would produce different results. The parsing code could consider
non-constant symbols to be expressions, which would cause these to have the
same values, and most ::constant declarations would be unaffected because
the variable would be uninitialized, and thus have the same values...with
the exception of the variables SELF and SUPER, which will have a value.
There's also the issue of ::options novalue error, which will suddenly
start getting tripped by instructions that were fine before.

Right now, I'm leaning toward an explicit syntax to indicate the value
needs to be computed at class creation time. We already have a precedent of
using parens to indicate a general expression, so I believe we should use
that. No parens, old rule, in parens, an expression to be evaluated.

Part of the processing I envision is the constant methods are created
initially, but are "incomplete" and if they are invoked before they are
"completed", they will raise a new subcode of error 97 to indicate the
constant had not been initialized. Initialization occurs in declaration
order, so constants can refer to other constants of the same class, as long
as they were declared prior to the usage. That is

::constant fullsize (2**12)
::constant halfsize (self~fullsize/2)

Would work, but

::constant halfsize (self~fullsize/2)
::constant fullsize (2**12)

would give an error evaluating self~fullsize. Directives with true constant
values will be available always, so

::constant halfsize (self~fullsize/2)
::constant fullsize 4096

would work because fullsize method was complete at parse time.

The next issue I'm wrestling with is when to perform the calculation. The
current package installation code does things in two passes. During
parsing, the classes are analyzed for inheritance dependencies and the
classes are created so that classes that are required by other classes are
created first, so these are not done in top-down declaration order.

Once all of the class objects have been created, a second pass is done to
call the activate() methods on the new class objects.

The dynamic constants (looking for a better name for these...) introduce a
third stage to this processing. I see three approaches that can be used:

1) Completing the constants is part of the class creation, so it is done
for each class in turn. This will limit somewhat the ability to refer
classes defined within the same package.
2) Perform a complete pass through the class objects initializing the
constants. This allows some capability to reference other classes and all
of the constants are completed before any of the activate() methods are
invoked.
3) Perform the constant initialization at the same time activate() is
called on the class. Again, this limits the ability of class activate()
methods to use the constants defined by another class.

Right now, I'm leaning toward 2), because it means the classes are all
fully initialized as class objects before any of the activate() methods are
calls.

Those are the biggest issues I see here. I've got enough code roughed out
to believe this can work, but I have quite a bit more to go.

Rick
2) Completing
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to