Summary
Macros are a frequently overlooked yet tremendously useful language feature. What if we give them a more modern twist?

Advertisement

Any selection of imperative language constructs a language designer comes up with is completely arbitrary, and is going to be limiting in one way or another. I think the best way to deal with this problem is to provide macros. When I talk about macros I am not talking about the nasty C pre-processor, but something more closely resembling macros in MacroML or Lisp.

I envision macros being well-integrated into the language and part of the type system. For instance it makes sense to me to be able to pass macros as template parameters. It also makes sense for macro parameters to be typed.

Consider the following code:

int x;
repeat (42) { ++x; }

This is not valid Heron code, but it makes sense. Instead of adding a new language construct my plan is to allow the programmer to define it as a macro as follows:

So as you may realize the macro is defined using a functional meta-language. _cond is the same as the Lisp function COND. The 'int represents a meta-int value, which is equivalent to a constant literal integer value. The 'code represents a statement or code block. The above example clearly won't work in the following scenario:

Take a look at Meta OCaml or `C (Tick C - which has only two levels though). The advantages would be that you have an entire programming language for the meta programming rather than some exotic spinoff using a different paradigm (the meta programming that you can do with C++ and, I reckon, Heron, resembles a functional language much more than the host language).You would need some sort of staging construct. I guess TickC would be your best source of inspiration here - it allows you to write code literals, I think, using a back quote operator. I haven't used it though so I am not quite sure.

Even if you don't go all the way to a multi-stage language, or something like that, what you've shown in the examples is typically called unnamed functions or lambda functions, which I'm sure you're aware of.

These exist in various forms in some other languages as, well, such as in Smalltalk, where you can pass a code block to a method. It can also be done, to some extent (and with a "ton" of library code) in C++ with Boost.Lambda.

A challenge with lambda functions is references to variables outside the function, and managing their lifetimes (such as if you store a lambda function for later use, such as a callback). Java "simulates" somewhat such lambda functions/closures with anonymous inner functions, where the compiler inserts references to external variables, where needed, in the generated code, and lifetimes being handled with the garbage collector (actually, it only handles storage, since GC in effect simulates "infinite lifetime").

It would have been nice with support for lambda in C++, as well, but with all the proposals being worked at (such as support for concepts, and DbC), it probably won't be included in the next standard.

> Even if you don't go all the way to a multi-stage> language, or something like that, what you've shown in the> examples is typically called unnamed functions or lambda> functions, which I'm sure you're aware of.

The proposed Heron macro is similar but does not have a stack frame and, at least for now, can't be recursive. The macro is always inlined.

> These exist in various forms in some other languages as,> well, such as in Smalltalk, where you can pass a code> block to a method. It can also be done, to some extent> (and with a "ton" of library code) in C++ with> Boost.Lambda.> > A challenge with lambda functions is references to> variables outside the function, and managing their> lifetimes (such as if you store a lambda function for> later use, such as a callback).

One solution to this problem I have been exploring is that closures (my definitions: functions referring to variables outside of the scope of the function) as having a lifetime which is equivalent to the shortest lived object referenced.

I mention this approach in the thread "Musing about Closures" http://www.artima.com/forums/flat.jsp?forum=106&thread=129705 . This seems to be a novel idea, but I am still trying to ascertain the expressive power of it. It is not as powerful as a closure in many functional languages, but IMO it is still very useful.

> Java "simulates" somewhat> such lambda functions/closures with anonymous inner> functions, where the compiler inserts references to> external variables, where needed, in the generated code,> and lifetimes being handled with the garbage collector> (actually, it only handles storage, since GC in effect> simulates "infinite lifetime").

The "infinite lifetime" of objects in a GC, is exactly something I want to avoid in Heron at all costs. The idea of a programmer unintentionally extending lifetimes of objects, and having to do extensive post-analysis to identify object lifetime issues, is a nightmare I want to avoid.

/* So what is the benefit of closures? Is the model of only local variables, parameters and / or class members not much clearer with regards to sideeffects?*/

My understanding of closures is that we're talking about local variables. A closure is simply a technique that that lets you pass variables to a function/function like object a few at a time, and then get the return value after you've passed all the necessary parameters.

> A closure is simply a technique that that lets you pass> variables to a function/function like object a few at a> time, and then get the return value after you've passed all> the necessary parameters.

What you describe above sounds very much like one particular implementation technique called lambda lifting: http://www.google.com/search?q=lambda+lifting . There are other ways to implement first-class anonymous functions with lexical scoping.

> This seems to be a novel idea, but I am still trying to> ascertain the expressive power of it.

I'm a bit too lazy at the moment to dig my bookshelf for references, but I think that Pascal already incorporated a very similar idea. The idea is that a procedure may contain nested procedures that may refer to the local variables of the surrounding procedure. This was called block structure: http://www.google.com/search?q=block+structure+pascal . Actually, I think that there are several languages that effectively incorporate the same idea. In Lisp parlance it was called downward funargs: http://www.google.com/search?q=downward+funargs .

Assuming that curly braces are used to denote blocks/scopes, then the above seems rather meaningless to me. The last two f(); calls should be compile-time errors (unless, of course, an outer scope contains another definition of f).