Since if-statements are built out of blocks and message sending, you can easily do some cool things. One of them is building up an abstract syntax tree (AST) of an expression without parsing that expression.
E.g. suppose you want to build up an AST of the statement
(x < 0) ifTrue:[-x] ifFalse:[x]
Instead of starting with an x of type Number, you would start with an object of type ASTVariable, that responds to the message < by creating and returning an object ASTLessThan instead of the Boolean True or False. When that object is sent the ifTrue:ifFalse: message it evaluates both branches to create the ASTs for both branches and then creates an ASTIfStatement.
The lambda there is actually only ever called once, on the client-side, with an equivalent of your ASTVariable, to generate an AST of the comparison which is sent to the server and processed there.
You mean "rather than x being sent to some message"? E.g. 0 > x wouldn't work, because the message #> is sent to 0 with x as an argument? In a case like that you can still make it work by exploiting the fact that arithmetic and comparison operators implement double dispatch. The implementation of > for an Integer would send a message to x:
Even if x is passed as an argument, to interact with it at some point somebody has to send a message to it. I agree that it can become unwieldy to intercept all possible messages, but for a well-defined subset in your DSL, this can usually be done.
You can indeed accomplish some similar things with it.
> Does it have performance disadvantages?
A Common Lisp macro is evaluated once at compile time. In Smalltalk this is evaluated at runtime, so that adds some overhead. Usually you only have to build the AST only once though, and can use the result many times, so that overhead isn't really relevant.
E.g. suppose you want to build up an AST of the statement
Instead of starting with an x of type Number, you would start with an object of type ASTVariable, that responds to the message < by creating and returning an object ASTLessThan instead of the Boolean True or False. When that object is sent the ifTrue:ifFalse: message it evaluates both branches to create the ASTs for both branches and then creates an ASTIfStatement.As an sexp:
I've seen it used in a number of embedded languages in Smalltalk, such as SQL.