leafo / moonscript

:crescent_moon: A language that compiles to Lua
https://moonscript.org
3.18k stars 190 forks source link

Pass-by-Reference semantics with a new operator #95

Open exists-forall opened 11 years ago

exists-forall commented 11 years ago

This proposal was sparked by another issue, which is where I actually wrote my thoughts on the subject. As far as I know, the github issues list doesn't have the equivalent to wikipedia split/merge recommendations, so I'm just linking to the discussion (manifesto). You can see my proposal here. Let me know what you think - I'm sort of on the fence about how commonly it's needed, but when you do need it it's very useful.

stevedonovan commented 11 years ago

It is a cool concept, but may fall into the 'occaisionally useful' category that language designers try to stay out of.

I've hit exactly that kind of issue you had with love with wx, and it was just a matter of writing a function - especially if the generated variables are kept as fields of a table.

I wonder how useful a proper macro facility would be. Did some experiments in that direction with LuaMacro, which was lexical-only but did have the great property that arbitrary code could be invoked at expansion time. Of course, the smart money is on macros that operate on the AST (like metalua) but they are harder to use in a language which actually does have syntax, unlike Lisp ;)

exists-forall commented 11 years ago

IMHO full-on macros are code smell. They're unpredictable, difficult to debug, and are inherently counter to the philosophy in dynamic language design of "late-binding." The three good uses for macros (and their safer replacements) are, in my experience:

Incidentally, I'm working on a language built around the idea of providing all the power of macros with run-time facilities and normal functions. It has a lot of experimental features, including spaces in identifiers and fine-grained control over whether or not functions are dispatched dynamically. I'll let you know more when It gets farther along, since i don't want to just be promising vapor ware.

stevedonovan commented 11 years ago

On Thu, Apr 4, 2013 at 11:05 AM, SelectricSimian notifications@github.comwrote: IMHO full-on macros are code smell. They're unpredictable, difficult to debug, and are inherently counter to the philosophy in dynamic language design of "late-binding."

Well I actually came to that same point of view by working with macros ;) The problem is that, given infinite power to shape a language to our purposes, we will all end up with different dialects. The use case for 'custom dialects' would be embedded DSLs, but MS already has such an expressive syntax that it's better than Lua for that purpose (e.g. as you say, fuss-free table constructors and (NB) lightweight closure notation).

Nowadays I use LuaMacro to preprocess C, which really could do with a good preprocessor. E.g. fun starts here:

https://github.com/stevedonovan/winapi/blob/master/winapi.l.c#L149

exists-forall commented 11 years ago

I agree that macros are indeed useful in compiled languages. In an ideal language, unconstrained by the limits of processor speed, they're generally a bad idea, but practically, when you want compiled, on-the-metal code like C, macros give you a significant fraction of the power of a dynamic language with little-to-no performance penalty. Although lua is interpreted, it generally is used by people who care quite a bit about speed. Under those cirumstance, tools like LuaMacro (which looks really amazing, although I haven't had time to try it yet) are great.

speaking of preprocessing of c code, I've been looking for a tool that lets one write C In a lisp-style syntax with macros, compiling to C later. Something like

(defun int (main int argc (ptr (ptr char)) argv)
    (printf "hello, world!")
    (return 0))

(Which seems a little like a Frankenstein monster)

Do you know of any? Maybe I could build one on top of LuaMacro :)

stevedonovan commented 11 years ago

On Thu, Apr 4, 2013 at 11:30 AM, SelectricSimian notifications@github.comwrote:

of the power of a dynamic language with little-to-no performance penalty. Although lua is interpreted, it generally is used by people who care quite a bit about speed. Under those cirumstance, tools like LuaMacro (which looks really amazing, although I haven't had time to try it yet) are great.

Right - case in point is LuaJIT. Although it can bite gcc's ankles on a good day, generally people don't see anything like that in real applications. Because it's a young optimizing compiler, and so there's a few man-years versus hundreds for C. We found that clever loop unrolling with macros could drastically speed up some numerical algorithms into ankle-biting territory. Perhaps one day MS' code generation can be tuned to make best use of Mike Pall's amazing beast?

(Which seems a little like a Frankenstein monster)

There was an optimizing Scheme compiler called Stalin which was doing very well at the Language Shootout. A pity that LuaJIT was disqualified, probably for making everyone else look bad.

exists-forall commented 11 years ago

All this talk of optimization is making me worry about how my language is a performance nightmare. It's far too flexible for any assumptions to be made. For example, every single if statement is just a call to a function named if with a boolean parameter and two block parameters, with each block parameter being, in turn, a call to a function named block with a procedure parameter (which is like an AST). To add insult to injury, not only is it a function, but it's a typed-based multiple dispatch function. This possibly makes it the most un-optimizable language design possible, as a result of extreme flexibility. Do you think this is worth it? Is there a niche for glacially slow language?

etandel commented 11 years ago

Is there a niche for glacially slow language?

Well, if the language is pretty, people will still use it. See Ruby, for instance.

exists-forall commented 11 years ago

Does pretty on the inside count?

It's a collection of design choices that, theoretically, should be elegant and productive, such as being able to redefine control structures. The syntax, however, suffers a little bit because of that. Here's a Moonscript squaring function

square = => self * self

and here's a squaring function in my language

def: 'square, case:[:num, Number], {num * num}

there's so much going on here it's rather hard to explain in a sentence or a paragraph, but the important points are that def is just a function, 'square is a reference parameter (note the ' - otherwise it would be a classic symbol lookup. I like the different between these to be explicit), case:[:num, Number] is the signature for this implementation (since every function is a multimethod), and {num * num} is the actual implementation, as a block. Also, a lot of the punctuation, like the : for the function call and the ,s for variables is so spaces in identifiers are unambiguous. For example, this would be syntactically correct as well:

define function: 'calculate square, case:[:num to square, Real Number], {num to square * num to square}

It's got like 10 times more line noise, but it's all for a reason. Maybe it's all unreadble, I don't know.

EDIT: the syntax is completely decoupled from the runtime and the AST, so users will be able to write their own syntaxes if they like, as long as they all end up representing the same underlying structure. Graphical editors and structure editors are even an option, as are s-expressions. If you want it to look more like python, or ruby, or Lua, or Moonscript, there's nothing stopping you. I think anyone doing that would quickly realize, however, that every little bit of easy-on-the-eyes syntax they add sacrifices a little bit of semantic goodness.