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. |
Administrator
|
On Thu, Dec 27, 2018 at 8:43 AM Konrad Hinsen <[hidden email]> wrote: Hi everyone, 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.
|
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. |
On Fri, 28 Dec 2018 at 16:30, Konrad Hinsen <[hidden email]> wrote: Richard Sargent <[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' cheers -ben |
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
|
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. > |
In reply to this post by khinsen
On Thu, Dec 27, 2018 at 5:43 PM Konrad Hinsen <[hidden email]> wrote: Hi everyone, 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
|
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. |
Konrad, On 31/12/18 8:59, Konrad Hinsen via
Pharo-users wrote:
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 |
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. |
Free forum by Nabble | Edit this page |