(no subject)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

(no subject)

khinsen
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.

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.

Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Richard Sargent
Administrator
On Thu, Dec 27, 2018 at 8:43 AM Konrad Hinsen <[hidden email]> 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.

Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

khinsen
Richard Sargent <[hidden email]> writes:

> 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?

I certainly agree that this should be the main consideration, but in my
case that's done. Each Expression subclass stored its own specific
information, which for leaf nodes such as integer expressions is really
just a value. All I need is integers with added behavior.

> I think that, in general, you will benefit from fully and consistently
> modelling the parse tree.

I should have mentioned that my Expressions are not parse trees. They
are used as values in symbolic computation. They are constructed and
deconstructed all the time, which is one reason I want to eliminate
overhead, the other reason being clarity of code.

Konrad.

Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Ben Coman


On Fri, 28 Dec 2018 at 16:30, Konrad Hinsen <[hidden email]> wrote:
Richard Sargent <[hidden email]> writes:

> 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?

I certainly agree that this should be the main consideration, but in my
case that's done. Each Expression subclass stored its own specific
information, which for leaf nodes such as integer expressions is really
just a value. All I need is integers with added behavior.

> I think that, in general, you will benefit from fully and consistently
> modelling the parse tree.

I should have mentioned that my Expressions are not parse trees. They
are used as values in symbolic computation. They are constructed and
deconstructed all the time, which is one reason I want to eliminate
overhead, the other reason being clarity of code.

This may not be what you are looking for, but maybe help flesh out ideas.
Try debugging...
     OpalCompiler new evaluate: '1 + 2'  

cheers -ben
Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Tim Mackinnon
 I was going to chip in that every class inherits what compiler it uses and so you can easily override that to do something special (like wrapping classes).

However, is this possibly an area where the meta-links kicks in so you don’t have to do this and get a more generic solution? (I haven’t played with this, but there are a few threads where people are using it, and it’s progressed quite a lot in Pharo 7).

Tim

Sent from my iPhone

On 28 Dec 2018, at 16:37, Ben Coman <[hidden email]> wrote:



On Fri, 28 Dec 2018 at 16:30, Konrad Hinsen <[hidden email]> wrote:
Richard Sargent <[hidden email]> writes:

> 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?

I certainly agree that this should be the main consideration, but in my
case that's done. Each Expression subclass stored its own specific
information, which for leaf nodes such as integer expressions is really
just a value. All I need is integers with added behavior.

> I think that, in general, you will benefit from fully and consistently
> modelling the parse tree.

I should have mentioned that my Expressions are not parse trees. They
are used as values in symbolic computation. They are constructed and
deconstructed all the time, which is one reason I want to eliminate
overhead, the other reason being clarity of code.

This may not be what you are looking for, but maybe help flesh out ideas.
Try debugging...
     OpalCompiler new evaluate: '1 + 2'  

cheers -ben
Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Pharo Smalltalk Users mailing list
In reply to this post by khinsen
Did you already try to measure the impaired overhead of a wrapper  
solution? It might very well be negligible in an otherwise purely symbolic  
computation.

A hybrid solution might be - instead of wrapping each value - to add a  
single method to the value classes that wraps a value on the fly if  
needed, e.g.

Integer>>asExpression
   ^ExpressionWrapper wrap: self.

If the expression protocol is invoked only rarely on the pure values, this  
solution reduces the overhead while keeping the value classes clean of  
foreign methods.

Another option might be to build a trait that adds the behavior to the  
value classes.

Best, Steffen

Am .12.2018, 09:29 Uhr, schrieb Konrad Hinsen <[hidden email]>:

> Richard Sargent <[hidden email]> writes:
>
>> 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?
>
> I certainly agree that this should be the main consideration, but in my
> case that's done. Each Expression subclass stored its own specific
> information, which for leaf nodes such as integer expressions is really
> just a value. All I need is integers with added behavior.
>
>> I think that, in general, you will benefit from fully and consistently
>> modelling the parse tree.
>
> I should have mentioned that my Expressions are not parse trees. They
> are used as values in symbolic computation. They are constructed and
> deconstructed all the time, which is one reason I want to eliminate
> overhead, the other reason being clarity of code.
>
> Konrad.
>



Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

SergeStinckwich
In reply to this post by khinsen


On Thu, Dec 27, 2018 at 5:43 PM Konrad Hinsen <[hidden email]> 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.

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?


Hi Konrad,

in your case I would write a parser for your specific concrete syntax with PetitParser
and then generate an instance of the abstract syntax you have defined.

Regards,
--
Serge Stinckwic
h

Int. Research Unit
 on Modelling/Simulation of Complex Systems (UMMISCO)
Sorbonne University
 (SU)
French National Research Institute for Sustainable Development (IRD)
U
niversity of Yaoundé I, Cameroun
"Programs must be written for people to read, and only incidentally for machines to execute."
https://twitter.com/SergeStinckwich
Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Pharo Smalltalk Users mailing list
In reply to this post by Ben Coman
Thanks to everyone who replied - the sum of the answers is actually a
lot more useful than each one individually, as each one points to a part
of the puzzle that Pharo is (for me, at least, after roughly one month
of use).

Ben Coman <[hidden email]> writes:

> This may not be what you are looking for, but maybe help flesh out ideas.
> Try debugging...
>      OpalCompiler new evaluate: '1 + 2'

An interesting experience indeed!

Tim Mackinnon <[hidden email]> writes:

>  I was going to chip in that every class inherits what compiler it
>  uses and so you can easily override that to do something special
>  (like wrapping classes).

An interesting feature, though it seems a bit too low-level for my
project, and definitely too low-level for my current Pharo competence.

>  However, is this possibly an area where the meta-links kicks in so
>  you don’t have to do this and get a more generic solution? (I haven’t
>  played with this, but there are a few threads where people are using
>  it, and it’s progressed quite a lot in Pharo 7).

That sent me off research meta-links:

  https://pharoweekly.wordpress.com/2018/03/27/understanding-metalinks/

Interesting stuff as well, but the same comment applies: this looks too
low-level for what I consider boring code implementing routine
techniques.

Steffen Märcker via Pharo-users <[hidden email]> writes:

> Did you already try to measure the impaired overhead of a wrapper
> solution? It might very well be negligible in an otherwise purely
> symbolic computation.

I did not look into performance questions at all for now. What scares me
most is the overhead in code size, in particular in my test suite.

> A hybrid solution might be - instead of wrapping each value - to add a  
> single method to the value classes that wraps a value on the fly if  
> needed, e.g.
>
> Integer>>asExpression
>    ^ExpressionWrapper wrap: self.

That looks like an interesting compromise, and one that I have seen used
elsewhere.

> Another option might be to build a trait that adds the behavior to the  
> value classes.

A nice suggestion as well - I haven't looked at traits yet in any
detail.

Serge Stinckwich <[hidden email]> writes:

> in your case I would write a parser for your specific concrete syntax
> with PetitParser and then generate an instance of the abstract syntax
> you have defined.

My first reaction was that this looks like overkill for my problem. But
then, considering that I will eventually need a parser anyway, why not
start that way and use it in my own test cases? A path worth exploring.

Thanks again to everyone - your comments will keep me busy for a while!

Konrad.

Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Offray Vladimir Luna Cárdenas-2

Konrad,

On 31/12/18 8:59, Konrad Hinsen via Pharo-users wrote:

Thanks to everyone who replied - the sum of the answers is actually a
lot more useful than each one individually, as each one points to a part
of the puzzle that Pharo is (for me, at least, after roughly one month
of use).


It's really nice to have you hear. I remember some of our Twitter conversations about reproducible research and the advantages that Pharo could bring in that front and is good to know that they will continue here with the stuff you're working on.

I restarted with Pharo in 2014, after a short revealing experience with Squeak, EToys and Bots Inc in 2006-2007 and now I'm enjoying the Joyride[1]

[1] https://twitter.com/offrayLC/status/493979407011561473

Yes, Pharo is strange and awesome and the same time. Be around, you'll be amazed.

Offray

Reply | Threaded
Open this post in threaded view
|

Re: (no subject)

Pharo Smalltalk Users mailing list
Offray,

> It's really nice to have you hear. I remember some of our Twitter

Thanks for the welcome!

> I restarted with Pharo in 2014, after a short revealing experience with
> Squeak, EToys and Bots Inc in 2006-2007 and now I'm enjoying the Joyride[1]
>
> [1] https://twitter.com/offrayLC/status/493979407011561473

Nice :-)

I guess the tough part is figuring out where you are on that curve!

Konrad.