Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I thought the industry standard for game scripting is Lua. I mean - if you want to attract the wide range of game devs, why choose lisp?


Because you're John Carmack. You'll attract devs no matter what you use, so it makes sense to use the best tools available.


Yes, he of course can afford this - to play with things he likes. But will it blend?


Does it need to blend? Were Racket the only supported scripting language for Oculus I'm sure people would just learn Racket rather than skipping out on Oculus.


As sklogic said, no need to learn Racket:

It has multiple Lipsy dialects: http://docs.racket-lang.org/guide/dialects.html

And a datalog one: http://docs.racket-lang.org/datalog/index.html

It knows C: http://pkg-build.racket-lang.org/doc/c/index.html

And Javascript: https://github.com/lwhjp/ecmascript

And Algol: http://docs.racket-lang.org/algol60/index.html

And Pascal: https://github.com/soegaard/minipascal

It shouldn't be too difficult to teach it Lua ;).


No need to learn Racket, it's easy to build any language on top of it. Having a single meta-language as a base allows diversity and choice for end users that is not possible with any of the inferior (non-meta) languages.


Best? If we'd all agree on what "best" means, we wouldn't discuss anything ever.

Scheme and all the other Lisp variants look terrible to me. Having an excessively simple syntax doesn't mean that it's nice to use. They went too far.

This is probably the primary reason why Lisp dialects aren't more popular. Even the simplest code examples look like some sort of practical joke.

    (let ((hello0 (lambda() (display "Hello world") (newline))))
      (hello0))
[Edit: This example was taken from Wikipedia's Scheme article.]

Something like that in Dart:

    hello() => print('Hello world');
    hello();
Dart's syntax is way more complicated, but this is much easier to understand, isn't it?


The second example is more readable for several reasons.

1. You chose a better function name (hello0 looks a little confusing)

2. You [EDIT: actually Wikipedia] decided for whatever reason to use let rather than define in the Scheme example.

3. Dart's "print" function is more suitable for console output on a single line than Scheme's "display".

Here's the fix:

  (define (print something)
    (display something)
    (newline))

  (define (hello)
    (print "Hello world"))
All of a sudden (f a b) doesn't seem way more complicated than f(a, b);.


For the sake of completion...

  (define (hello)
    (displayln "Hello world"))


Racket has a displayln that is similar to puts or System.out.println.


The code you pasted is used to illustrate the concepts of ports. You took it out of context. It's not an example of hello world like you're claiming. Also, the code on Wikipedia doesn't always match actual practice of programming in a language..

If you want to see more realistic examples go to RosettaCode, pick interesting task and look for Scheme, Racket and Clojure entries. You can then compare them to each other and to other languages you know.

The other thing is that your code in Scheme and Dart don't do the same thing at all, unless I underestimate Dart semantics very much. A translation of your Scheme code to JS, with as much semantics preserved as possible, would look something like:

    (function (){ // let introduces new scope
      var hello0 = function (){ // hello0 is a variable holding an anonymous function
        return console.log("Hello world"); 
      };
      return hello0();
    })();
That's quite a bit of work less in Scheme, isn't it? But for when you don't need these semantics you can do a translation the other way round (Dart->Lisps). In Racket your Dart example would look like:

    (define (hello) (displayln "Hello world"))
    (hello)
Now, that looks better, right? It's worth noting that the Racket version has only one pair of parens than Dart.


To expand on this a little, here is a thing that you can't translate to most programming languages. By defining a simple, pattern-based macro we can get much closer to the Dart version:

   (func: hello() => (displayln "Hello world"))
   (hello)
All you need to do this - to change the language syntax to look like that - is to write this:

    (define-syntax func:
      (syntax-rules (=>)
         [(_ name (formal ...) => expr ...)
          (define name (lambda (formal ...) expr ...))]))


Is this just trolling? Why a let and "hello0"? Is that just to make it look weird on purpose?

    (define (hello)
      (displayln "Hello, World!"))
    
    (hello)


I used to program in a LISP (the language predates Lisp) derivative called "Boot". (It booted a computer algebra system.) It added two rules to LISP: unparenthesized expressions bind "to the function call", using dynamic lookup to determine arity, and failing if the binding wasn't unambiguous; and, ';' to delimit expressions. It's been a decade since I used the language, but it would look something like this:

    define (hello)
        displayln "Hello, World!";

    hello;
The boot 'compiler' only did name resolution and parenthesization, then it kicked everything back to an underlying LISP. (In this case, SBCL, which rocked!)

The second level language built on Boot was Spad, which used a slightly friendlier syntactic top-form:

    e : t = x
With compact forms:

    e := x
    e = x
    e : t
    e
Which lets you uniformly parse packages, modules, domains, categories, functions, annotations, etc. etc. For instance, we had a Spad-lite syntax:

    Monoid : Domain = public :
        _* : (y : Monoid), (x : Monoid)
        _0 : Monoid
Then you could assert membership:

    assert(Integer, Monoid) :=
        _* : (y : Integer), (x : Integer) = (_*:Integer)(x, y)
        _0 = (0:Integer)
An implementation would be:

    Monoid : Domain = public :
       -- see above.
    = implements :
       -- implementations.


Quite a beautiful addition to sexps. I've seen implicit rules about top-level expression being implicitely wrapped in parens you one can write

    defun fact (n)
      (cond
         ..
         ..)
which makes lisp so much more bearable to parensophobic people.



Seriously ?

  (defn hello [] (println "hello world"))
  (hello) ;; in Clojure

  (defun hello () (format t "hello world"))
  (hello) ;; in Common Lisp.


The example was taken from Wikipedia's Scheme article.

I do not know how to write Hello World in Scheme.

By the way, I really like how everyone's Hello World looks different.


>I really like how everyone's Hello World looks different.

Because everyone is posting hello world examples in different languages. Lisp is a family, a category of languages, not a single language.


You can't effectively criticise a language without actually knowing it. That's why you're being downvoted.

The example you gave is using the lowest level primitives to printing with zero syntactic sugar. It's equivalent to writing the following in JavaScript (assuming functions called 'display' and 'newline':

    (function () {
        var hello = function() {
            display('Hello world');
            newline();
        };
        hello();
    })();
Practical Scheme implementations include additional macros that add syntactic sugar so you an use much more straightforward mechanisms to do things.


So, you know nothing about Scheme, but yet dare to have an opinion?


Yes, I "dare" to have an opinion on that syntax.

I like it from a theoretical point of view. It's very uniform which is convenient for implementers. It's brilliant, really.

However, I dislike it from a practical point of view, because this uniform soup is hard to scan and also hard to write.

I pretty much like any other language's syntax better than this one. Even fairly cryptic ones like Erlang's.


> However, I dislike it from a practical point of view,

How can you be disliking it from a practical point of view if you don't use it in practice? Don't you think it would be different if you tried actually learning Scheme for a week? Do you think it would still be unreadable to you after that week? Why do you think so?

Also, take a look at APL or J if you want to see "unreadable" language.


> How can you be disliking it from a practical point of view if you don't use it in practice?

I had plenty of exposure to deeply nested things. This is pretty much like nested function calls. "foo(a, b)" and "(foo a b)" isn't all that different, is it?

I prefer to have different bits of syntax for different things because it looks less uniform. I like it when different things stick out in different ways.

> Also, take a look at APL or J if you want to see "unreadable" language.

Both of these aren't even in the top 50. Can you think of a somewhat popular (non-legacy) language?


> I had plenty of exposures to deeply nested things. This is pretty much like nested function calls.

I have no idea what you mean here.

> I like it when different things stick out in different ways.

Here's your problem: the "things" are sticking out in a variety of ways in Lisps, you just don't know and can't recognize in what ways exactly.

> Both of these aren't even in the top 50. Can you think of a somewhat popular (non-legacy) language?

Again, I don't understand what you mean.


> I have no idea what you mean here.

Nested lists are similar to nested function calls. Did you skip the rest of the paragraph?

> the "things" are sticking out in a variety of ways

No, they don't. Syntax-wise, everything is the same.

"Scheme's very simple syntax is based on s-expressions, parenthesized lists in which a prefix operator is followed by its arguments. Scheme programs thus consist of sequences of nested lists."

There shall be nested lists. That's all, folks!

In other languages, you have syntax for importing stuff, syntax for declaring a variable, syntax for different loop constructs, syntax for branching, syntax for classes/methods/functions...

Each building block comes with its own syntax.

This isn't as elegant as having one universal construct for everything, but it's easier to use (once you got used to it), because the syntax itself carries a lot of the information.

  (define (square x)
    (* x x))
I rather write something like:

  square(x) => x * x;
"bla(...)" is a bit of syntax for defining a function. "=>" is a bit of syntax for defining a lambda. "x * x" is a bit of syntax for using x's "star" operator.

> Again, I don't understand what you mean.

J and APL aren't popular languages. There are many unpopular languages with worse syntax. They are also both array programming languages which is a rather odd niche.


This is simply the case of getting used to something. The Lisp code reads like this: (define A B) -> define A to be B. You define (square x) to mean (* x x). It requires you to know only one syntax rule - that (f a b ...) means "apply f to arguments a, b, ...". The above code basically reads "define applying square to x to mean applying * to x and x".

> They are also both array programming languages which is a rather odd niche.

Array programming may seem like an odd niche if the only thing one knows is web development, but the moment you actually start doing some maths, they become incredibly useful. Another, much more popular (and crappier, which seems to be a common correlation, but that's a different story) array programming language is MATLAB. Also you've probably heard of R, loved in statistics and sciences, which is another array language.


> This is simply the case of getting used to something.

My point was that other languages provide more visual hooks. Lisp is just words and parens. Nothing sticks out. Everything is the same.

So, you can't learn this "visual vocabulary" because there simply isn't any. There is a thing at the beginning of each list and what follows are the parameters. That's it.

"(define x 5)", "(square x)", and "(+ x x)" are syntactically the same thing.

> Array programming may seem like an odd niche if the only thing one knows is web development

You make it sound like it's either web stuff or maths.

Array programming languages aren't used for scripting (e.g. games), are they?


How many of those visual hooks are provided by syntax highlighting? You have that in Lisp as well. Moreover, you don't need that many syntax hooks; you learn to recognize words, just like when reading a book, and also indentation structure.

> Array programming languages aren't used for scripting (e.g. games), are they?

They've been used at least once, if you count one demo and one game I wrote in MATLAB. Man, you wouldn't believe how convenient array languages are when you need to do, things like polygon mesh interpolation (morphing), not to mention actual array operations like multiplying matrices or vectors. MATLAB may be a crappy language, but the array operations? I wish I had them in C++/Java for games.


If you interpret "array programming language" as "language with support for arrays and matrices as first-class objects with nice operators, etc" then you get a lot more things coming into the mix beyond oddballs like apl.


> but it's easier to use (once you got used to it)

No, actually it's easier to both read and write and edit sexps once you get used to it. This whole thread is about this: you have no practical Lisp experience yet you claim Lisp is not practical. You couldn't be bothered to actually learn more of a language, but you want to tell us how the experience of using it looks like.

It doesn't work that way. You can only compare things meaningfully when you have comparable knowledge of both. You apparently don't. There are many people who do know both "normal" languages and Lisps and most of them seem to agree that in practice Lisps are as readable as other syntaxes. But you don't want to believe in it for some reason and you don't even want to see for yourself.

> square(x) => x * x;

Why don't you answer my earlier posts, where I show how to make similar syntax in Lisp?

> J and APL aren't popular languages.

But that is completely irrelevant. I'm talking about language features and practice/experience of programming with it, I don't care at all about "popularity".


> You can only compare things meaningfully when you have comparable knowledge of both.

Lisp isn't the only language which allows you to nest things.

You can nest function calls, lists, objects, tuples, and whatever in any language.

  (a b (c d))

  a(b, c(d))
Impossible to imagine, eh?

> Why don't you answer my earlier posts, where I show how to make similar syntax in Lisp?

So, your solution to make Lisp usable is also to not write Lisp? And I'm supposed to take that as disagreement?

If you extend it with your own syntax, it becomes a different language.


> If you extend it with your own syntax, it becomes a different language.

...but that's exactly what programming Lisp looks like. Becoming a different language every time you need it to is business as usual in Lisp. Syntactic abstraction - ability to extend language syntax - is central to Lisp programming.


> If you extend it with your own syntax, it becomes a different language.

No. This is exactly what Lisp is for. If you're not transforming it into hundreds of small DSLs (with their own syntax and a wide variety of semantic properties), then you're not using it right, and missing on all of its expressive power. In such case, yes, you may get rightfully puzzled, what all the Lisp buzz is about if it's just all the same stuff, but with an ugly syntax.


I think this requires an obligatory image explanation for non-lispers: http://www.loper-os.org/wp-content/parphobia.png


> Yes, I "dare" to have an opinion on that syntax.

Is not it stupid, to have an opinion about something you do not know and do not understand?

> It's very uniform which is convenient for implementers.

It's not that uniform, really. It's so flexible that you can make it look any way you like. Any existing language syntax is a subset of this syntax.

> because this uniform soup is hard to scan and also hard to write

Just use a better text editor then.


> [Scheme's syntax is] not that uniform, really.

"Scheme's very simple syntax is based on s-expressions, parenthesized lists in which a prefix operator is followed by its arguments. Scheme programs thus consist of sequences of nested lists."

That's as uniform as it gets. Everything is the same.


Firstly, Racket is not a Scheme. There are reader macros and all that bells and whistles. Does this look like S-expressions to you?

https://github.com/soegaard/minipascal

Secondly, even most Schemes allow to use [ ] and { } in addition to ( ).


> Firstly, Racket is not a Scheme.

Did I talk about Racket anywhere?

> Does this look like S-expressions to you?

"MiniPacal implemented in Racket"

Are you really arguing that implementing some other language is the way to go?

https://github.com/eudoxia0/cmacro http://research.swtch.com/shmacro

Totally legit "C".


> Did I talk about Racket anywhere?

This is a thread about Racket, if you did not notice.

> Are you really arguing that implementing some other language is the way to go?

This is exactly what Lisps are about. You've got a nearly raw AST at the bottom (S-expressions) and then you build up a hierarchy of languages on top of it.


Even if you use this redundant `let` form you can still make it more readable by doing the following:

    (let ([hello-func (lambda ()
		        (displayln "Hello world!"))])
      (hello-func))
This applies globally; when it makes sense, differentiate between some lists by using brackets instead of parens. Some Lisps take this further by using other bracket types to signify certain things.

I would advise not to hop on Wikipedia and assume things about languages. Scheme is not very hard to get into and with variants where batteries included you can build useful stuff right out of the box.

Go to http://www.racket-lang.org/ if you want to see a good example of a pragmatic and useful Scheme variant that may just dispel some of your prejudices.


> Scheme and all the other Lisp variants look terrible to me

Baby duck syndrome?

> Having an excessively simple syntax doesn't mean that it's nice to use.

Having an excessively simple syntax ensures that you can add any amount of syntax on top of it, whatever you fancy. Do not like S-expressions? Fine. Code in any syntax you like.

> but this is much easier to understand, isn't it?

No, it is not.


That's mostly because such lisps are overly verbose. The same code in Clojure:

    (let [hello (fn [] 
                  (println "Hello World"))]
      (hello))
Or assuming hello is a global in your dart example:

    (defn hello []
      (println "Hello World"))

    (hello)
Nothing too complicated about that. Clojure is way less verbose than some scheme variants.


All Scheme variants are approximately as verbose as your second example, except you don't have to assume hello is global. Internal defines are part of the R4RS standard published in 1991.


The equivalent code in Racket is exactly as complex as your Clojure example.


> Or assuming hello is a global in your dart example

The way it's written implies that it's somewhere inside some block, because "main()" is always the entry point. I wrote it like that because I couldn't be bothered to figure out how this stuff works in Scheme.

With entry point:

  main() => print('Hello World');
Alternatively:

  main() {
    print('Hello World');
  }


> I wrote it like that because I couldn't be bothered to figure out how this stuff works in Scheme.

I think that sums everything up, really. This is how shallow the complaints about parens are. No one who actually bothers will make a point about what delimits expressions in a language.

To complain about parens is also doubly wrong, as they do bring something technical to the table.

What Carmack talks about when he says S-expressions are nice for reading in terms of network communication, for example, is that the messages can be read exactly like other expressions over the wire. This is true for any I/O; you can read the data just as if it was code, because the code is data. The same mechanism that reads the code you are executing is available to you to read full expressions through any medium, and use that data/code as you see fit.


"This stuff" was referring to the entry point.

I didn't complain about parenthesis. ASM's syntax is also extremely simple, but that doesn't make it easy to use, does it? If everything looks the same, it's hard to scan.

C-like languages provide more visual hooks than Lisp dialects.


I'm currently using Java and Javascript for work. Previously I used Scheme. I do find that scanning is important in Java and JavaScript because often you don't need to read a whole section, just a piece. Back when I worked with Scheme, if I didn't need to read a whole section, generally the part I needed to know was right at the beginning. I think all Lisp dialects work this way.

The worst example is immediate function application in JavaScript. You get to the end and all of a sudden the }(); tells you everything you've just read is a different context than you thought it was. In Scheme (and probably most Lisps) you'd recognize immediate function application at the beginning as soon as you saw ((.

I don't know how people get really good at JavaScript without learning Scheme first.


> You get to the end and all of a sudden the }();

With most code conventions, you wrap immediately invoked function expressions (IIFEs) in parens:

  var foo = (function () {
    ...
  }());
The only purpose of those extra parens is to act as marker.

Well, with block scope (`let` & `const`), IIFEs aren't really needed anymore.


>Clojure is way less verbose than some scheme variants.

Bullshit.


Eh, IMO

    (let [x (+ 1 2)
          y (+ x 3)]
      (* x y))
Is always less verbose than:

    (let ((x (+ 1 2))
          (y (+ x 3)))
      (* x y)) 
I program in Clojure every day, and that latter example makes me say "aahhhh! The parens!"


And the Clojure example makes me say "aaah the ambiguity!" The key/value pairs makes much more sense to me when they are delimited as such. It's a minor point, anyhow. Clojure is just fine. I just don't think that it is significantly less verbose than Scheme. Let's just keep hacking with Lisps and be happy. :)


It's dramatically less verbose when you are dealing with code that uses associative data structures, both because of having nicer literal syntax and because the data structures can be applied directly without needing to reach for things like hash-ref. (Which makes a boatload of sense, because immutable hash maps actually have more in common with mathematical functions than Scheme procedures do.) In addition, functional nested updates are very verbose in Scheme.

However, both of these problems can be solved in Racket by third-party libraries.


    (let* ([x (+ 1 2)]
           [y (+ x 3)])
      (* x y))
Less ambiguity, all of the clarity of what is what. I don't get why you use other delimiters for your Clojure code, but have this view that they can't be used in other Lisps/Schemes.

(You will also have to use `let*` in (most?) schemes because the binding for y has absolutely nothing to do with the binding for x and so cannot be used in the binding of y.)


>I don't get why you use other delimiters for your Clojure code

Do other delimiters mean the same thing as in Clojure tho ? I only know Clojure - in Clojure [] - vector- is a different data structure from () - linked list - which is different from {} - hash map. Is this similar to Racket or is it all just lists in Racket ?


In Racket all kinds of parenthesis are equivalent, using one or the other is a matter of convention and readability.

I think the newest Scheme standard takes the same approach.


Here's his (brief) answer (from the same thread):

John Carmack:

> >An imperative API makes functional abstraction harder. What are the main selling points for Scheme/Racket now?

> I am a big believer in functional programming (and static types) for large projects, but there is an undeniable bit of awkwardness compared to just imperatively poking things for small projects. That is one of the wins for Scheme -- I can make it super-easy to get easy things working, but it isn't just a "scripting language" unsuitable for large scale development. I am going to have to sort out my Racket / Chibi module strategy sometime soon, though.

> As far as language choice goes, I don't claim to have broadly evaluated every possibility and chosen the optimal one.

> Java or C# would have been more familiar to a broader base of game industry developers, but I really didn't want to drag in all the bulk of a JVM / .NET system, and a class focused world view seems less suited for the smaller scripting tasks.

> Javascript would have been more familiar to a broader base of web industry developers, but I have basically no experience with javascript, and little desire to explore it (which is admittedly a fault of mine).

> S-expression reading and writing is a strong factor for network communication, and I like the fact that there are available options for Scheme to interpret / compile / compile-to-C. I can see valid use cases for all of them, and I'm not sure how important each will be.

> The bottom line is that I have been enjoying myself working with Racket / Scheme this year, and I have evidence that it has been objectively productive for me, so I'm going out on a bit of a limb and placing a bet on it.

> >Initial impression: 7 years after starting to program in Racket, it still surprises me how easy it is to do something > >useful in just a few lines of code.

> A big goal here is to make the authored code very clear and simple. I may yet get to a single #lang vr <ip address> declaration that gets rid of the boilerplate at the top and bottom of the file and flips the right switches to make Racket closer to R7RS.

> There are sets of creative-types that are learning how to put things together in Unity to accomplish fairly simple media related tasks. I think I can make it easier for them with very domain specific helper libraries and a little bit of scheme.


> I am a big believer in functional programming

> I have basically no experience with javascript

> The bottom line is that I have been enjoying myself working with Racket

So there is no logical reason behind, he just loves Racket, ok


Programmer love is secretly (or not so secretly) the reason for all language choice. I say why hide it.


Not really. Domain often dictates. If AAA games could get away with using a garbage collected language, I'm sure they would.


Unreal has GC support for C++.

Unfortunately Unity broken GC is a side effect of them not wanting to improve the stone age runtime they are using.

I guess many AAA could actually be done in languages with GC support, but game devs tend to only change tools when the OS/console vendors force them.

All that is needed is having such a vendor pushing a language with the same effort as they are pushing for JavaScript JITs, lets say.


Programmer love would determine who'd make that change vs. who defended C++ to the death.

Domain is often dictated too—we're attracted to problems that fit our tools.


Not to worry, they will be forced for add javascript just to please the hordes of people who don't know any better.


Before that it had to be "VB like" scripting.


You forgot this part:

>and I have evidence that it has been objectively productive for me


He is fairly smart and has quite good taste, so I'll trust him to choose a good language.


It is logical for him to pick Racket because of these three points.


Only programmers would demand that you provide logical justification for an aesthetic preference :)


Ultimately, this is what art is. You need to go with what you love. 'logical argument' often just is a euphemism for rationalizing your convictions after the fact. You can't paint if you try to analyze every brush stroke. Let the subconscious flow.


Scheme (or any other Lisp) is the best choice for a baseline implementation, because it can be easily (and without any runtime cost) turned into any other language. You can do similar things with MetaLua, but at a greater cost.


I've worked at a couple of games companies and we didn't use Lua on any of the projects I worked on. One was starting to experiment with it when I left.

A large AAA studio I worked at actually rolled their own scripting language, compiler, and VM from scratch. I got to get my hands dirty with this. The only time since University I've had to utilise my compilers knowledge :)

Unity gives you the choice of C#, a JavaScript dialect, or a Python dialect.

Why not lisp? :D


Andy Gavin has a great series of articles on the making of crash bandicoot[0], [1]. (I'd recommend reading the entire series as it's very interesting).

It seems that in order to create an immersive world on the original playstation and keep up the speed of development, iteration and dynamism required for a game he wrote his own compiler (into assembly for the playstation one) for a lisp that he created called Game Oriented Object Lisp (GOOL)[1].

[0] http://all-things-andy-gavin.com/2011/02/02/making-crash-ban...

[1] http://all-things-andy-gavin.com/video-games/making-crash/

[2] http://all-things-andy-gavin.com/2011/03/12/making-crash-ban...


Because, in my opinion, when you create a tool for the masses, the individual preferences should be the last in line of factors when you choose scripting programming language for that.


God forbid javascript developers are being encouraged to broaden their horizons by a master of the discipline.

He is going to be forced to add javascript by whiners anyway, I am enjoying the pipe dream of keeping it away.


When you create a tool for the masses, you get a crap tool. You should focus on creating a good tool first; the masses will have to follow anyway.


> when you create a tool for the masses, the individual preferences should be the last in line

Well Javascript is Javascript because of some guy personal prefences at Netscape. The same is true for C# and Java in their respective companies, and they didn't start as popular languages either.


Javascript is literally the poster child for "accidental and completely illogical success". It's the only mainstream language that did not have to compete with anything else because of accidents of history.


Technically, it did have to compete with VBScript, back when IE had browser dominance and VBScript support.


But Netscape never had support for vbscript, so until they died Javascript/JScript was the only choice. By the time IE reached dominance, the industry had already standardized on JS.


JavaScript was supposed to be Scheme not once but twice, and the reason we use it instead of a Lisp in the browser is the insane competition with Microsoft. Source: interviews in Coders at Work.


And that guy wanted to just use Scheme, but got overruled by management.


By that line of reasoning, everything would be COBOL.


They masses don't know what they want. By choosing for them, you show them.


Lua's a minimal and easy-to-learn language that's easy to embed. But is it a good language? I'm not sure. It's weakly-typed and dynamically-typed, for example.


Lua is not weakly typed (at least not in the sense of Javascript and PHP where "3"+4 is either 7 or 34, can't remember which.

It is dynamically typed, but so is Scheme, so that's not a reason to choose Scheme over Lua.

It has the bestest JIT currently found in any dynamically typed language, and rivaling the best JITs of statically typed languages like Java.

What's your definition of a good language that accepts scheme but not Lua?


> Lua is not weakly typed (at least not in the sense of Javascript and PHP where "3"+4 is either 7 or 34, can't remember which.

In JS, "3" + 4 is "34", in PHP, it's 7. PHP separates concatenation and addition, unlike JS.

Anyway, huh? Lua has automatic type conversion. That's usually considered weak typing.


Its just for "+" and ".." though. For other things, such as equality and table indexing numbers and strings are not interchangeable.


In Lua "3"+4 is an error. Concatenation is a different operator than add, specifically to avoid confusing coersions.


Try it:

    Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
    > ="3" + 4
    7


Ah. Well at least there isn't a confusion between add and concat

"3"+4 is 7 4.."3" is "43"

"3hello"+4 is an error


Stand corrected with the example. I forgot about the lua auto type conversion - but that, on its own does not make weak typing - Python, C and Java do that between floats and ints, would you consider them weak typed?

I'm not familiar with a rigorous definition of weak typing - but my experience is that weak typing is usually reserved for languages like TCL, Snobol, and even Perl where there's no "type" of values to speak of - everything is equivalent and decoded according to context.


That's the problem with those terms, both 'weak' and 'strong' typing are purely subjective.


> bestest JIT currently found in any dynamically typed language

Aren't the best players in this field the JavaScript engines? Not because JS is the best language, but because Google, for example, hired people like Lars Bak to make them.


Javascript engines certainly have the best marketing going for them :) But Lua is a much simpler language and its much easier to write a JIT compiler for it than Javascript.

And if it comes to quality of programmers, LuaJIT has Mike Pall which is a bit of a legend for those who heard of him.


Which means LuaJIT suffers from Bus factor syndrome.


TypedRacket is statically typed.

Good language is a meta language. There is MetaLua, of course, which qualifies it as a "good" language, but Scheme got more bells and whistles.


Metalua isn't compatible with luajit. It needs the slower C based interpreter. Its problem was that it was based on a very old version of Lua and it needed things like goto that weren't in lua yet, so it goes straight to bytecodes.

I'm working on building languages on top of Lua/Luajit, since Lua has a good tracing jit, there's no reason you can't write an expanded metalanguage on it that will preprocess a bit and give you a brand new language.

By the time I'm done it will have the power of scheme (including continuations, with some functions compiled internally to use continuation passing style, since Lua guarantees tail call elimination) and macros. The main difference should be that the base type will be arrays and tables not lists, but that could be an improvement. I'll probably tack on something like s-expressions too.


You should find this interesting http://terralang.org

Took me a couple reads to figure out what it does. Luajit is the metalanguage for Terra. But, if you want to, you can run a mixture of Lua and Terra at runtime or statically compile to a pure Terra exe or .o with no Lua runtime at all.


that reminds me a bit of lush [http://lush.sourceforge.net/], one of a small handful of languages that i really feel should have made the jump to at least haskell-level popularity.

hn actually had a lush discussion recently: https://news.ycombinator.com/item?id=9602430


Also, I've worked in both Lua and Racket.

Racket's garbage collector is the only one I've ever used that actually made programs unusable.

Also, Racket's macro system feels like a mistake. While it's more powerful than most others, it's still rather incomplete, feels like a bad design, and ... well just look at the code that's used to implement the (sadly slow) object system. The code makes assembly language look clear by comparison. Dig under the surface and despair.

Scheme is very powerful, but in the end Lua programs are a lot more readable.


[edit, I wrote this before you changed your comment so say "one-shot". In short my continuations are not one shot, they are delimited though, by necessity because I don't rewrite ALL functions into continuation passing style, and you can't recast what lua calls metafunctions.]

Continuations are not coroutines.

Continuations let you save the current position, like setjump/longjump. But unlike setjump/longjump you can continue inside a function that already returned, ie as long as there is a continuation remembering that position then the activation record can't be deleted.

That means that activation records (ie local variables) can't be just the top of the stack - it changes things deep.

Also note that continuations only save the position, they don't restore the values of variables to what they were at that position, so re-evaluating continuation more than once will break any code that wasn't expecting to re-run.

Something that snapshots some local variables as well as the position will be more useful than raw continuations for things like search, backtracking, and logical programming languages.

[edit 2, I am ALSO adding snapshot continuations for these purposes]

Running an OUTER continuation rather than an inner one looks like an exception.


Doesn't Lua already have (one-shot) continuations, in the form of coroutines?


> Metalua isn't compatible with luajit.

Although there should not be any obstacles for porting (or re-implementing) MetaLua on top of the most modern luajit.

> The main difference should be that the base type will be arrays and tables not lists, but that could be an improvement.

That should only matter in compile time anyway, for your meta-language. Target may use whatever data structures you want.

> I'll probably tack on something like s-expressions too.

It's not necessary for a meta-language, as long as you have quasiquotation (that works both for constructing ASTs and for pattern-matching them). It's just the easiest way, but not the only one.


Lua, thanks to Metalua, works pretty well as a meta language, so you could easily add static typing, while keeping the benefits of its interpreter.

OTOH, the same is true for Scheme.


I think it is pretty much expected of devs to be able to learn new languages on the fly, as you need them.

Also, just because something is the "industry standard" (of popularity), doesn't mean you should always follow.


The Naughty Dog team made a lisp (GOAL) for some of their games.


When moving to PS3, they used Racket instead.

https://www.youtube.com/watch?v=oSmqbnhHp1c




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: