On Thu, Dec 27, 2018 at 8:43 AM Konrad Hinsen <konrad.hinsen@fastmail.net> wrote:
Hi everyone,

I am confronted with an implementation choice that I expect to be not so
rare, and I wonder what "the Pharo way" is for dealing with it. I will
use a toy example for illustration, my real case is more complex but not
fundamentally different.

Suppose I want to represent arithmetic expressions that support various
operations (evaluation, simplification, compilation to whatever
language, ...). In the textbook discussion, I'd have a class hierarchy
such as

�� �� Expression (abstract)
�� �� �� ��IntegerExpression
�� �� �� ��VariableNameExpression
�� �� �� ��SumExpression
�� �� �� ��ProductExpression
�� �� �� ��...

What I really want is not some IntegerExpression, but plain Pharo
integers, and for variable names I want to use plain Pharo symbols.

I understand your desire to utilize the existing Smalltalk mechanisms. But, I think the most important thing is modelling consistency.

What are the behaviours you expect from Expression, SumExpression, and ProductExpression? Do they know their parent expression? Their children? Other things? What was their actual representation (source code)? 16rDEADBEEF may be more meaningful than 3735928559, for example. Likewise, 2r111110111101110110101�� versus 2063285. Being able to reason fully about what was parsed will almost always be important.

I think that, in general, you will benefit from fully and consistently modelling the parse tree. The actual evaluation is probably the smallest part of the problem.

e.g. if every node implements #evaluate, it is easy to implement their operations. SumExpression would answer "self leftNode evaluate + self rightNode evaluate". IntegerExpression would implement is as "^self value" or something similar.


>From my current understanding of Pharo, my options are

��1. Use wrapper objects for integers and symbols, i.e. have a class
�� �� IntegerExpression that stores an integer in an instance variable.

��2. Add the methods of my abstract Expression class to all the classes
�� �� representing integers and symbols.

��3. Implement my own dispatch that does not rely on method lookup.

None of these really looks attractive. 1) adds a lot of overhead, both
in the code ("IntegerExpression withValue: 5" rather than just "5") and
at runtime. 3) also adds a lot of overhead because I have to implement
my own dispatch. 2) would probably be the least effort, but looks like a
kludge.

For comparison, in the Lisp world (CLOS, Racket, ...) that I know much
better, I would use generic functions and provide implementations for
integers and symbols as well as for my own Expression types.

So... how would you approach this problem?

Thanks in advance,
�� Konrad.