I too have wanted something easier to work with than function() ...
end. For
example, let's say I want to write code that will lock a mutex
around the
execution of some other code. What I can write in Lua right now is:
Mutexes.withMutexDo( mutex, function()
-- do stuff while holding the mutex
end )
What I would like to write is something more like:
Mutexes.withMutex( mutex ) do
-- do stuff while holding the mutex
end
This avoids the line extending function() and avoids the closing )
after the
end.
[What I really want is:
Mutexes.withMutex mutex do
-- do stuff while holding the mutex
end
But I have no idea what syntactic rule makes that sort of construct
work.]
From an implementation standpoint, the rule might be that a "do" that
appears on the same line as the end of a function call defines a
function to
be passed as an extra parameter to the function call. (If one
doesn't like
changing the meaning of "do", then consider using something like
"begin".)
That convoluted specification is intended to support constructs like:
profileSection "Section Name" do
-- do work to be profiled
end
This sort of construct could also change Lua's module construct
such that
modules would have explicit rather than implicit ends:
module( "MyModuleName" ) do
-- module guts
end
In looking a bit at Ruby on Rails, I was appreciating how Ruby's
syntax
supports data description by allowing one to execute code in the
midst of a
definition which allows for adding multiple fields at once. Using
the above
Lua-ish notation:
ORB.entity "MyEntity" do
field "myField"
hasOne{ fieldName = "childName", childType = "ChildType" }
end
[The do above looks a bit odd and could be an argument for using
some other
lexeme, but I don't have a good proposal in that regard. Colon would
probably be my first choice were it not already in use.]
What's nice about the Ruby definitions is that they exploit what
amounts to
a change of global environment but it is essentially transparent to
coders
unless they look underneath at how the syntax manages to do what it
does.
Adding this feature, however, probably opens up a variety of pressure
points:
1. Do these actually work like strings and table declarations with
respect
to function calls so that one can write:
myFunction do
-- do stuff under the control of myFunction
end
I haven't done a syntax review, but that still seems tenable.
2. There will be a natural pressure to figure out how to add
argument list
support. We could say that one has to fallback to function() to get
that or
we probably end up looking at further rules about line breaks so
that one
can write:
myFunction( argument ) do( x ) end
but just as the meaning of do has been transformed, so has the
meaning of
the parentheses in this context.
3. This is designed to look like a syntactic construct but note
that it
changes the meaning of "return" in that a return inside some
do..end blocks
returns from the do..end block and inside some other blocks returns
from the
enclosing function. How much of a problem is that in practice? Does
the use
of a separate keyword like "begin" solve the problem? Is there
pressure
created for non-local returns with the policy that they become
invalid upon
exiting the relevant stack frame?
4. It makes creating closures "cheaper" and more invisibly
syntactically.
That will probably tend to create pressure to make their actual
creation and
destruction cheaper. Generational garbage collection or some form of
reference counting is probably the answer here though I could also
see more
constrained support specifically for stack scoped entities.
Finally, my guess is that this isn't something that can be done
with token
filters unless one builds in support for the whole grammar.
Mark