[squeak-dev] [ANN] Tirade

Göran Krampe goran at krampe.se
Tue Mar 17 16:35:02 UTC 2009


Hi!

(snipping a bit)

Nicolas Cellier wrote:
>>  Can you tell you won't ever need 1/2 for example?
>> Yes, I can tell you that. :) You can create tons of "nice things to have"
>> but if you really think about it there are a lot of ways already in Tirade
>> to avoid adding support for "expressions" like that, for example, simply
>> make sure to send a message that knows that the argument is a mathematical
>> expression that the builder can evaluate:
>>
>> mathematicalExpression: '1/2'
> 
>  I understand you added a syntax for Associations because you need some
> Associations NOW in delta...
> .. Or maybe for imitating JSON structures...

More for that, I was not particularly aiming at anything in Deltas.

> But to me, above sentence is heavy (pathological?) for such a simple thing
> as a Fraction.
> It's like writing some C code: Cat aCat; /* this is a cat */ ;)
> Of course, Fraction might probably not be a problem for deltas for few next
> years, but i want to explore other possible applications of your ideas :)

Sure, but... a Fraction? :) It is not that often that you sit around 
with a Fraction in your hand so to speak.

Btw, I just modifified Tirade to now support the full Squeak Number 
syntax. So you can do radix, exponents, floats etc.

And I hacked up that TiradeStackReader too. :)

Also, do recall that JSON is wildly successful and it only does numbers 
and strings. Definitely no Fractions there. :)

>>  I mean representing arbitrary deep oject trees (not speaking of general
>>> graphs).
>>> The example you are presenting seems flat. Could you expose how you would
>>> build a deeper object?
>>>
>> Sure, either you build depth in "nested data":
>>
>> structure: {'key'-> {
>>                'a'->12.
>>                'b'->13'.
>>                'c'-> {
>>                        'd'->{123. 345. 567}.
>>                        'e'->12}}}
>>
>> ...and let the builder create whatever objects it likes given that data.
> 
> Sure, VW GUI specs did (do?) use this kind of scheme...
> You have sort of JSON in Smalltalk Array Literal, maybe more powerfull
> because you can even intermix unary messages.

Yes, the supported syntax for "data" should cover JSON.

But "intermix unary messages"? Not inside the data. Tirade is strictly a 
sequence of messages with 0-n arguments where each argument is more or 
less like a JSON doc:

keyword1: <data> keyword2: <data>.
unary.

> {'MyObject' 'a'->0. 'beAGoodObject'}.
> It might event be possible to use n-ary.
> I guess you ommitted class names in above hierarchy by accident...

You mean in my little "structure"? No, it is up to builder to "know" 
what to create. Sure, you can embed class names or other Strings as 
hints to what classes the builder should use, but it is not always needed.

> But then it's kind of troubling to have a Date string syntax in JSON syntax
> in Tirade syntax in Smalltalk.
> Doesn't that deserve more thoughts ?

What deserves more thought, Dates? Tirade does not have "JSON syntax" - 
it just happens to more or less match JSON in capability, when it comes 
to literal syntax.


> Yes, but nothing above tells to store the Leg object in the leg slot of the
> Animal.

This may be one of our "differences" in view. I do not intend to use 
Tirade as a strict "serialization mechanism". I will not iterate over 
ivars and write all state out including info about which concrete class 
it was etc. And while reading I do not expect to get specific concrete 
class names and ivar names and all their contents.

Instead I aim to write and read a series of messages that is "just 
enough" to recreate objects. So the above was actually a rather bad 
example, I was just pseudo coding from the hip.

> With DNU and other tricks, this might be doable, I trust your talent, and i
> am impatient to read your next solution.

I added TiradeStackReader, it seems quite nice.

> What I can tell you is that my first scheme for saving objects trees was
> built on such a stack pattern...
> ...But I then switched to a syntax with file scope variables support to get:
> 1) more power (ability to save arbitrary graphs)
> 2) readable code (I don't consider a tree spanning over several pages
> readable)
> 3) plenty of deprecated messages for handling stack (they don't add value to
> the API, do they ?)
> 4) no more bytecode limitations
> 5) a scheme that could be used to transcript (log) user graphical actions
>>From this time on, the application lived twenty years with constant upgrades
> without file format problems.
> 
> Again, this is probably too much for deltas, and does not meet all your
> requirements.
> Sure, a collection of flat objects might be more than enough.
> But it's worth thinking twice for possible evolutions or other apps.

It might be worth noting that I want something simple that people can 
use with very little effort. This means cutting some corners.

But I also don't want to do "plain serialization", instead I want to 
create a *custom* builder (serializers have a generic builder for all 
kinds of Smalltalk objects) that works in *tandem* with the domain 
objects it constructs (by utilizing real instance creation methods 
taking arguments and not just "basicNew" followed by stuffing ivars) and 
that can be driven by Tirade messages.

The above paragraph catches it quite well I think. So construction looks 
like this perhaps:


"tirade message sequence" => TiradeParser (parses) => TiradeStackReader 
(security checks and maintaining stack of receivers) => DeltaBuilder => 
"delta domain objects"

Now, a very small example:

Tirade input:
---------------
createDelta: 'Name of delta'.
   addRenameClass: #OldClassName.
     newClassName: #NewClassName.
   end.
   addRenameClass: #AnotherOldClassName.
     newClassName: #AnotherNewClassName.
   end.
end.
-----------------------------

DeltaBuilder>>createDelta: aName
	^DSDelta named: aName

DSDelta>>addRenameClass: oldClassName
      "Here we return the DSClassRenameChange instance.
      Thus it will be the stacked receiver for Tirade messages."
      ^self addChange: (DSClassRenameChange from: oldClassName)

DSClassRenameChange>>newClassName: newClassName
      newName := newClassName


...ok, so the DeltaBuilder creates a Delta and returns it as the next 
receiver on the stack.

Then comes another message to add a "rename class" change. (A Delta is a 
sequence of Changes basically). We do that BUT we also return this new 
DSClassRenameChange object so that it will be the next receiver.

#newClassName: is thus not sent to the DSClassRenameChange object, 
setting one of its attributes. It returns self so it will still be the 
receiver for more messages. If it returned nil it would cause the 
TiradeStackReader to pop it, thus an object can actually "pop itself".

More likely the Tirade input knows when we are done setting attributes 
so it sends #end. This message is a message that TiradeStackReader 
intercepts and causes it to pop the stack. The final #end pops the Delta 
too.

Note that we are not naming ivars in the Tirade input, we aren't even 
naming the class DSDelta! Everything is a message with data as arguments.

regards, Göran




More information about the Squeak-dev mailing list