Monday, February 04, 2008

Custom syntax: Macros and closures

I'm lots interested in getting custom syntax for this and that where I get annoyed by C++ or especially Java simply not letting me doing any. For example, in Java you need to write all these EJB-style accessors yourself. In ruby you just say attr_reader :attr1, :attr2, and when reading other people's code you can be sure that there isn't a typo that let getAttr1 return attr2 by accident.

Just as I was embracing the idea that macros are absolutely necessary for much stuff,
ruby came along and brought block arguments. And tada, you can do map and everything without macros just as regular function. Some guys even ported the idea to java. So I became unsure whether macros are really necessary. Ok, basically I still believe that because (programmatic) macros can do anything; I think they are the best way to integrate custom code generators.

And then came along Raganwald and wanted something like ph = find_whatever()&&.author&&.phone: Call find_whatever, and if it returns something, get the author, and if there is one, get his phone number. Otherwise the whole expression is nil.

Now it is amazing that you can get ruby to do something like that at all, even though it cheats on two points: It does not use the intended syntax (obj&&.name) but obj.andand.name (note the conspicious second dot), and it does not actually take the shortcut but instead goes through the rest with a dummy object.

But he does not just to avoid the helper variables, but also to get a left-to-right reading. You just can't do that in lisp, for instance. (Ok, it's going to be the inverse.)

But why this hit me: While I have somes idea how I would bring macros into language with syntax, I have no idea yet how I would make &&. definable. The problems here:
  • When you get to the &&. you are already in the middle of the expression the macro would need to replace, so there would be a need to allow operators be a kind of macro

  • Member selection is not a binary, but a postfix operator! While it looks like one, the right hand side is not an expression, but a compile-time constant. (In a sense there are many different operators, one for each possible member name.)

I guess I need to think about that some more...how to enable user-defined operators not only as functions, but also as macros.

5 comments:

Reginald Braithwaite said...

Thank you for your insights!

abas said...

Take a look at Scala, where one can define this operator.

helium said...

I'm pretty new to scala. while I could define an operator called "&&.", how could I make it behave like "&&." discussed here? It would have to be a postfixoperator that returns either its left operand or when it's null some special null-object which implements everything the object would, but all these implementations would have to return another special null-Object that in turn implement the methods the resulttype of the methodcall implements.
That look impossible to me. But perhaps I'm thinking in the wrong direction.

abas said...

Ouch, my bad; I've experimented more and indeed it's not possible to do what you meant. While Scala allows right-associative operators (they end with a colon), it's not possible to override a method invocation.

Patrick Logan said...

This seems to be "programming by explicit structure", which could be fine, but it loses the advantage of the message send. It will be significantly more brittle.

Message sending is far more flexible, but even for "programming by structure", it is probably better not using explicit structure. One way to avoid explicit structure, and still do something like this, would be to use an xpath-like query language, i.e. if you assume something has a single author field with a single phone field in an explicit path (thing.author.phone) you are making more assumptions than necessary -- always a bad thing.