The Fay Programming Language
chrisdone.com
chrisdone.com
* Build the next generation browser that supports a proper programming language.
* Write migration instructions.
* Convince major web-app providers that they need to migrate.
* Help with migration.It just isn't standardized, or made available to website authors directly (there would likely need to be significant extra security audits before you could contemplate something like that...).
Same with Java. JVM had (and AFAIK still has) a horrible cold startup time which locked the entire browser up, causing the user to curse profanely.
* You have to know what platform you're targeting (ARM vs. x86), which eliminates the browser/JS advantage of architecture abstraction
* You have to recompile specifically for NaCl, which removes any potential benefit on binary reuse
As others have noted, NaCl is closer to ActiveX-reborn than it is to a generic web runtime architecture.
Besides: I can't think of language-neutral bytecode projects that ever worked. Remember Parrot?
I suspect that minifier arguments are no-win situations: either someone doesn't like that they can't easily read the JavaScript, or someone complains it takes too long to load the scripts for a given page.
If the writer wants you to see the source, you can download it elsewere (githun, etc) if not, there is no difference between not getting the source to office 98 and not getting the source to google docs.
When the Web was young and there was no GitHub, viewing a page's source made it so that you could see by example how every page worked. It exposed you to a huge number of possibilities. The Web partially owes its success to this feature because without it far fewer people would have made it to the stage where they could produce their own pages. Every web developer/designer has used this to help them -- guaranteed.
Besides, the feature would have sprung up anyway whether the browser vendors wanted it included or not. Third parties would have stepped in. It's plain text transmitted over the wire. Unlike the source of Office 98 which is not retrievable from the Office 98 binary, a page's source is readily available to the machine that has to cobble it all together when viewing that page.
In my book, some kind of byte code or other intermediate language is a lot better idea than distributing the source code of web apps. There are a lot of disadvantages to delivering programs (for immediate execution) as source code. Note: this is orthogonal to open source and licensing.
So what would be needed is an intermediate program representation that:
- Is well defined
- Is a good compilation target from various source languages
- Is easy to validate for correctness and security
- Is fast to interpret and compile
- Distributed in fast to read binary format
- Suits a dynamic language
In my opinion LLVM IR or CLR bytecode are the most technically suitable alternatives out of existing ones.The web has quite a long legacy of Javascript and a tradition of supporting deprecated browsers so this kind of revolution is unlikely to happen any time soon.
> Besides: I can't think of language-neutral bytecode projects that ever worked. Remember Parrot?
JVM, CLR and LLVM are all popular compilation targets that are used with dozens of different source languages each. Bytecode and program representation was never the hard part, it's the frameworks of the OS/platform underneath.
> Bytecode and program representation was never the hard part
Bytecode is very much a hard part if you're trying to support more than a single language, many bytecode have both language and VM semantics leaking in, which essentially makes them even less useful than cross-language compilation.
Most of LLVM IR is portable, but naturally there are target-specific parts. If LLVM IR was to be used in the web, these target specific parts would be defined for the "web" target. LLVM IR is used in a similar manner in NaCl and OpenCL where it is used as a portable binary format.
> Bytecode is very much a hard part if you're trying to support more than a single language
It's not easy but it's mostly a solved problem. JVM was designed with a single language in mind, yet it's used by dozens of languages today. Similarly LLVM and CLR are widely used.
How is this statement qualitatively different from "JavaScript was designed with human writers in mind, yet it's used by dozens of languages today"?
That the web is by default open presents the social dynamics that are quite different than in systems like java applets, which are by default closed.
Open source can exist regardless of whether the web is open or not, but you are kidding yourself if you think whether or not source is distributed with a web page doesn't effect the open source landscape.
Instead, JavaScript is used as a program representation with small size and immediate execution in mind, and it really sucks in that role.
Even if the code is distributed in source code form with white space, identifier names and comments intact (bandwidth isn't cheap, you know), licensing is still the factor that legally determines if it is free software or just open source by default.
View source is important both for the sake of debugging in the case of 3rd party javascript, and also for the sake of being able to teach others.
Regardless of the minification issue, it's possible to use a code formatter to expand a minified file and at least identify where declarations are being made and what functional behavior is being specified. Minification makes viewing source inconvenient, but that's not equivalent with closed.
If you go to that length you can just as well use a decompiler, no difference.
Minified files, more often than not, have the original identifiers, original code structure (e.g. you know a for from a while ). With a decompiler, you lose all of that.
Google closure is a compiler (and thus loses a lot of this data), but most minifiers are not semantically destructive.
Because javascript has some reflection, and also because of weird scoping rules (with, eval, etc.) you can never be sure where a symbol comes from unless you have access to the exact version of every other script on the page, e.g. jquery, etc)
> If you want your source-code available for download then... put up a download link.
I agree - but there is still a huge difference between deminified and decompiled source readbility - which is all I was saying.
Since we have to have legacy support for javascript approximately forever anyway, I'd say the best way forward is to embed a vm from the statically typed world as a target for static languages and leave js as a cross compilation target for dynamic languages.
To avoid nasty cross vm memory leaks you'd probably want to limit interoperability -- at least at first.
It's also nigh-impossible to design a bytecode which does not significantly restrict (and dictate) the semantics of the VM running it. It mandates a bytecode-based VM, to start with (V8 does not use bytecode).
Really? Remember the CLR and JVM?
But, microbenchmarks, blah blah blah.
Now, besides off context, your comment is wrong in four ways:
1) we are not discussing about a bytecode to implement Javascript, but a bytecode to use in browsers for implementing all sorts of languages.
2) There are other lnguages that have been implemented in CLR/JVM that are faster than Javascript.
3) V8 has been optimized by a special team, for millions of dollars, with speed as the #1 target. When that amount of money and effort, a JS running on JVM/CLR can be fast too.
4) A bytecode does not preclude a JIT. In fact it would be trivial to have V8 run a bytecode instead of raw js, just as Python runs pyc.
* Lots of people are going to be on current and previous versions of IE for years to come, no matter how many hours you put in.
* People enjoy finding clever ways around constraints, and I'm not sure those same man-hours would be available for your alternative tasks.
* IMHO, JS really isn't so bad.
These micro-languages (that compiles to JS) try to solve the same fundamental problems that exist in JavaScript, which mostly are syntactic or semantic in nature. But there are some solutions and implementations that will likely help further the development of ECMAScript, so the man-hours spent on creating them aren't all lost.
Incentives matter.
And you don't need to do better than JS in 1995. You need to do better than JS _today_.
The correct measuring unit for the things you're talking about is man-centuries (and not one, but several), as far as I can see, just for the first item in your list.
People have been making compilers targeting JS for several years now. Do you really think there are 200-300 people doing this full-time?
1. It has full Hindley-Milner type inference
2. It produces readable javascript that is reasonably debuggable
I could imagine using this for real projects in the near future. > It produces readable javascript that is reasonably debuggable
The examples on the page don't seem readable and reasonably debuggable to me. The simple square definition: square x = x * x
Compiles into: var square = function($_a) {
return new $(function() {
var x = $_a;
return _(x) * _(x);
});
};
Which, in turn, has all the "$" and "_" indirections.This is basically why i think that trans-compilation to JS from a semantically very different language is not a good idea, unless a way of debugging _in the source language_ is provided. The success of CoffeeScript, i think, comes from it not differing too much from JS semantically; yes, it adds things like classes or everything-is-an-expression semantics, but the step of trans-compiling those things into JS is pretty trivial.
I hope the advent of source maps will help in the ease of use of these languages.
I am a coffeescripter, and i already have mixed emotions about the extra layer of complexity it puts on my code for others to get up to speed. Taking it further from the actual language (javascript) just adds a layer of obfuscation that does not really help javascript and its community at all (and many of the times your peers). It may make you feel better about what you are doing at the time (e.g. i must have typed vars, or whatever you people say), but its just making you feel better, it still is javascript, and you still have to debug javascript across browsers - that's just that. You still need to know all the javascript, you cant just use X to js and only know X. Only reason i get away with coffeescript is when i know im modern browser world, not old ie and the greater world of browser bugs. Otherwise im writing javascript.
The Fay compiler is written in Haskell,
so you will need the Haskell platform
installed (or at least Cabal).
I don't know if it is a Fay-compatible subset of Haskell, but I would not bet on it :)If the average IQ of the world population is higher, I think Haskell will become a widely-used language. Haskell is a language much more than its syntax, and takes a lot of effort to learn.
It would even be quite cool to make a REPL and development environment, but that's a little far off.
Roy and Elm are new languages that people who follow Haskell are probably familiar with. Comparing to them makes more sense than comparing to LiveScript if your audience is Haskell programmers.
LiveScript is not really anything like Haskell at all except in some entirely superficial ways. Even the syntax isn't all that similar. Essentially, it's a slightly more functional CoffeeScript. While certainly interesting to the same people and for the same reasons as CoffeeScript, it's not very interesting to people who primarily use Haskell.
LiveScript is a good comparison only in the way it transforms and is part of the wave of "compiling to JavaScript". For that reason it might be nice for me to mention it on the page.
Granted that LiveScript isn't Haskell, how are the syntactic features that are derived from Haskell not at all like Haskell?
The vast majority of the syntax seems based on CoffeeScript.
The defining characteristics of Haskell (to me, bear in mind I'm a Haskell noob) are strong, static, inferred types, and an emphasis on pure or near-pure functional programming (limiting side effects as much as possible). The defining characteristics are not a standard library function named "fold" or "takeWhile".
LiveScript has JavaScript semantics, like CoffeeScript. These semantics differ from Haskell in deep and fundamental ways. Yes, it might also encourage functional programming, but so does Scheme and Clojure, both of which are really nothing like Haskell either. I don't think this is controversial.
It borrowed some syntax, but from what I can tell, it's much closer semantically to Scheme.
Technically these are global within the Fay output, but that is all wrapped up in a closure, so it won't interfere with anything outside.
Additionally, _ is not a valid function name in Haskell, and $ (and any other non-letter symbols) are encoded as $123$ where 123 is the unicode point.
So these two symbols are free to use, if that bothered you at all. enumFromTo is defined in the Prelude.
Calling the Fay compiler a "transpiler" would imply that it is a source->source compilation, like CoffeeScript.
From what I can tell, it _actually compiles some of Haskell to JavaScript_, so the term does not really apply.
Besides, what's wrong with JS being web assembly? You like JS? Fine, use JS. Nobody is taking that away from you.
A pattern is a way of deconstructing an object into its constituent parts and bringing some of those into scope.So (Math x y z) is a valid pattern, which would bring these values into scope: x=1, y=2, z=3. In this case I'm bringing only the second argument into scope. In a pattern, _ means "ignore this argument".
Here is a short interactive lesson on pattern matching: http://tryhaskell.org/#19
That certainly seems to describe what's going on here.
On the main wikipedia page, you cut off the full definition: "A compiler is a computer program (or set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language, often having a binary form known as object code). The most common reason for wanting to transform source code is to create an executable program."
Note how it says "the target language, often having a binary form known as object code." and "The most common reason for wanting to transform source code is to create an executable program."
If you then go down into the description, you'll see: "The front end checks whether the program is correctly written in terms of the programming language syntax and semantics. Here legal and illegal programs are recognized. Errors are reported, if any, in a useful way. Type checking is also performed by collecting type information. The frontend then generates an intermediate representation or IR of the source code for processing by the middle-end.
The middle end is where optimization takes place. Typical transformations for optimization are removal of useless or unreachable code, discovery and propagation of constant values, relocation of computation to a less frequently executed place (e.g., out of a loop), or specialization of computation based on the context. The middle-end generates another IR for the following backend. Most optimization efforts are focused on this part.
The back end is responsible for translating the IR from the middle-end into assembly code. The target instruction(s) are chosen for each IR instruction. Register allocation assigns processor registers for the program variables where possible. The backend utilizes the hardware by figuring out how to keep parallel execution units busy, filling delay slots, and so on. Although most algorithms for optimization are in NP, heuristic techniques are well-developed."
So, just stating that it is "a computer program that transforms source code written in a programming language into another computer language" is inadequate. There is more to it than that, and unfortunately so many just don't get it.
Once you recognise the suckyness you can start thinking about ways it might be reduced. You can also start reasoning about whether things that reduce some dimensions of suck are worth the cost of the other dimensions of suck that they increase.
The depths to which JavaScript sucks are well documented & well understood: http://wiki.theory.org/YourLanguageSucks#JavaScript_sucks_be...:
Some might disagree with this assertion. I don't think I'd ever put imperative in the pros column for JS, and in any case its imperative nature doesn't really distinguish it from most popular languages.
Fay will never be used for Node.js. If you're going to write Haskell to run in a multithreaded code environment, you'd simply run it in the superior-in-every-way GHC runtime, which has proper 21st century support for a wide variety of modern concurrency constructs, instead of warmed over event-loop ideas from the 1980s. (Or 1970s.) Haskell : Node :: Node : raw select loop code.
$ fay -autorun examples/console.hs
$ node examples/console.js
Hello, World!
You're free to use it on node if you like.