lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



On 29 Sep 2006, at 00:14, Glenn Maynard wrote:

On Thu, Sep 28, 2006 at 10:34:00PM +0200, Mike Pall wrote:
  local userops = {
    PI =     { arity = 0, op = math.pi }, -- arity 0 are constants
    sin =    { arity = 1, op = math.sin },
    cos =    { arity = 1, op = math.cos },
    ["|"] =  { arity = 2, op = bit.bor },
    ["<<"] = { arity = 2, op = bit.lshift },
["//"] = { arity = 2, op = function(a, b) return math.floor(a/ b) end },
  } -- These should of course better be light functions.

  loadstring([[
    local a, b = ...

    print( PI * sin a + cos b )
    print( (a << 11) | (b << 3) | 5 )
    print( "Rici buys", 1.38 // 0.16, "apples." )

Intuitively, I don't like this. I don't want to use a language where people
are almost defining their own syntax inside the language.  That takes
the evils that operator overloading can cause in C++ (people using operators for things unrelated to their original cause, like overriding + for "set union"), and makes it an order of magnitude worse, allowing making whole
new operators.

That's not to say it couldn't be used well, just like operator overloading
can be used well; it just seems to invite incredible abuse.  Practical
languages can't make it impossible to write bad code, of course-- people will--but this seems at such a level that in order to read anyone else's code, I'm going to have to learn their own personal sub-language first.

See below.


(I don't understand how a parser could support this, since the language
is being defined by the language being compiled.)

No it's not. The table defining the language, userops above, is not part of the program being compiled, the string argument to loadstring. I assume Rici Lake meant to pass userops to loadstring or something like that. Effectively the compiler (as embodied in loadstring for example) changes from a function of type "string -> function" to one having type "string x language -> function" where "language" could be specified as a table like Rici Lake has done.

On sub-languages:

One paradigm for programming solves problems by creating a new language in which the expression and solution of the problem in hand is, in some sense, "nice". This is one of the reasons people use different languages for different problems. To some extent it's possible to regard _all_ programming as the creation of a new language in which the problem solution is expressed.

For example when looking at a random program in C, say the Lua system, it's not possible to understand the code without understanding the specialised language that has been created. Concretely, here's a snippet of code from Lua:

        int b = GETARG_B(i);
        int nresults = GETARG_C(i) - 1;
if (b != 0) L->top = ra+b; /* else previous instruction set top */
        L->savedpc = pc;

Now, this is fairly plain C, but knowing C doesn't really help you understand what's going on. You have to understand the language of "GETARG_B" and "L->top" and such like. A language has been created with the "C language programming system".

Where programming systems (languages) differ is in how much flexibility they offer you in defining your own language. My assertion is that you'll be defining your own domain-specific language anyway, regardless of how much support you get from the programming system you are using. Languages like Java offer almost no flexibility. Your language pretty much must consist of objects and method calls, so it's all in the names and typical usage idioms. Languages like C offer quite a bit more (because of the horrible macro system); you can to some extent define you're own syntax for some things. Languages like Prolog or Lisp offer a huge range of flexibility due to the way you can get at the internals of the parser ("reader").

Lua seems to occupy a sort of middle ground somewhere between Java and Lisp. You can make languages that look a bit declaration and configuration-like by using syntax like:

base { pos={3, -7}, health=50 }

you can make fairly ordinary "just a pile of functions" languages:

base[i] = newBase({3, -7}, 50)

And you can also make some quite funky languages by messing around with metamethods and the built-in operators.

Observe that load takes a function that generates input, so one could regard this as a sort of completely general front-end to the Lua "parser" capable of transforming any language into Lua. That kind of thinking would place Lua near the Lisp end of the spectrum, but it's not really because of the general difficultly of creating typical transformations.

Perhaps it boils down to: to what extent do you trust your developers (people that write code that you have to look at, say) to design sensible languages? I observe that what C++ makes easy, operator overloading, seems to make it easy for people to create languages that are not intuitively understood, and are therefore "bad".

I find all this a bit ironic since you Glenn have created your own sub-language with stuff like: http://stepmania.cvs.sourceforge.net/ stepmania/stepmania/Themes/default/metrics.ini? revision=1.1344&view=markup . In order to "understand" that document I have to understand the sub-language of "[ScreenUnlockStatus]" and "# blah blah blah" and so on. I'm not saying that's difficult in this case, I'm just saying that you create sub-languages of your own.

Personally I really like the fact that compilation in Lua is currently a function of type "string -> function". The result of compilation does not depend on the compilation environment. OTOH I also think much of the recent "syntax modification" discussions and developments, such as Silverstone's token-processing patch and Lake's example above, are very interesting.

drj