Info on Smalltalk DSLs or Metaprogramming...

Rich Warren rwmlist at gmail.com
Fri Aug 18 10:35:20 UTC 2006


On Aug 17, 2006, at 6:44 AM, Ramon Leon wrote:

>> All my DSL examples are in Ruby.
>>
>> For DSL's, Ruby's syntax seems slightly more flexible than
>> Smalltalk (or maybe I just know how to abuse it more).
>>
>
> Might I suggest that Smalltalk itself, isn't so much a language, as  
> it is a
> notation for creating DSL's.  Smalltalk for example, models  
> predicate logic,
> with simple objects and blocks, no special keywords such as
> if/unless/do/while are necessary.  Ruby can't do this, and requires  
> special
> syntax in the language, due to its inability to pass multiple  
> blocks and its
> lack of Smalltalk style keyword selectors.  I'm curious where you  
> see Ruby's
> syntax being more flexible?
>
>

Before I get too far into this, let me again point out that my sense  
that Ruby handles DSLs (as I am currently thinking about them)  
possibly better than Smalltalk may simply be because I am more  
familiar with Ruby syntax than Smalltalk. And because I have several  
good examples that give clear examples of different methods for  
building Ruby classes/methods/etc. to support DSLs.

So, please, please, please. If anyone knows of any good examples that  
show how to do these things in Smalltalk, please let me know. That  
might give me a better handle on how to approach this in Smalltalk,  
and might just win me over.

First off, I'm talking exclusively about using internal DSLs here.  
That is, I will be using the natural features of a general purpose  
language. I'm not talking about building a full-fledged parser/ 
interpreter. However, I do want to be able to read in and interpret  
arbitrary text files at runtime.

I think the approach should be similar in both the Ruby and Smalltalk  
case. Take a line of text. Evaluate it as code in a context so that  
the individual words in the line get interpreted as objects/messages/ 
methods/arguments/whatever.

If this is the case, then I can see a few places where Ruby would be  
simpler. For example, if you're executing text as code within an  
object, you don't need 'self' when referencing methods. As a result,  
most Ruby DSLs execute inside objects--I suspect Smalltalk DSLs don't  
do this.

To me, this seems to imply that in Smalltalk, the first word on each  
line will typically be a class, followed immediately by either a  
class method or a constructor. Ruby DSLs can do this as well, but  
they can also start immediately with a method call on the containing  
class. That, potentially, gives Ruby a considerable bit of extra  
flexibility.

Second, in Ruby methods that take arguments do not need to end in a  
colon. This can help keep the DSL syntax clean, particularly for  
single-argument methods. Ruby methods can also have default values  
set for the parameters (which I don't believe is available in  
Smalltalk), and if the final parameter is a hash, you can use the  
simplified hash syntax.

On the smalltalk side, I suspect cascading and the separate selector  
for each argument could produce highly readable DSL syntax--but I'd  
really like to see a few demo examples to get an idea of how it all  
fits together.

There may also be ways of doing things in Smalltalk syntax that could  
make DSLs easier--things that I don't know, or that I'm just not  
thinking about. For example, I don't see how avoiding if/unless/do/ 
while really gains anything (especially since 'if' is arguably more  
human readable than 'ifTrue:'). I also don't see a big gain in  
passing single blocks vs. multiple blocks. I doubt I'd use blocks in  
the DSL directly anyway (or 'if' for that matter)--since the block  
syntax is a bit ugly in both languages--and I can't imagine it being  
necessary.

Really, I'll probably be implementing something very simple--so it's  
probably a wash.

It looks like I'll need to set the following information:

Run name, ID, number of agents, target function, max error,  
visualization on/off, verbose on/off

In Ruby this could be done as follows (calls the new_run method and  
passes in a hash):

new_run name => 'my name', id => 0, agent_count =>  200,  target =>  
30sphere ,error => 1e-10, visualize => true

Since we are passing a hash into the new_run method, these arguments  
can be in any order. They can also be omitted (the target object  
presumably sets a default for anything not present).

The same thing in smalltalk would look like this (note, they can be  
in almost any order--'name:' is a constructor and must come first-- 
the others can be in any order and can be dropped):

TrialRun name: 'my name'; id: 0; agentCount: 200; target: 30sphere;  
error: 1e-10; visualize: true

or, for a prettier option (but one that sacrifices flexibility)

TrialRun name: 'my name' id: 0 agentCount: 200 target: 30sphere  
error: 1e-10 visualize: true verbose: false

None of them are really as readable as I would like, but any would  
do. The last one is the most readable, but if the number of optional  
flags started to grow--it would quickly become a real pain.

-Rich-



More information about the Squeak-dev mailing list