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.
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.
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:
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:
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:
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':
> 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?
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".
> 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.
"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.
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.
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?
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.
> 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.
> 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.
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.
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.
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 ?
> >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.
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.
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].
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.
> 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.
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.
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.
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.
> 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.
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.
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.
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.
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.