Difference between revisions of "The JavaScript Problem"

From HaskellWiki
Jump to navigation Jump to search
(Removed Lambdascript; it's dead and has been superceded by Haste.)
(→‎GHCJS: Not 'alpha' anymore? GHCJS is in production use (almost all of Obsidian's clients))
 
(41 intermediate revisions by 22 users not shown)
Line 3: Line 3:
 
The JavaScript problem is two-fold and can be described thus:
 
The JavaScript problem is two-fold and can be described thus:
   
  +
# '''JavaScript, the language.''' JavaScript, the language, has some issues that make working with it inconvenient and make developing software harder :
# '''JavaScript sucks.''' The depths to which JavaScript sucks is well-documented and well-understood. Its main faults are: its lack of module system, weak-typing, verbose function syntax¹, late binding², which has led to the creation of various static analysis tools to alleviate this language flaw³, but with limited success⁴ (there is even a static type checker⁵), finicky equality/automatic conversion, <code>this</code> behaviour, and lack of static types. Coffeescript is the most mainstream javascript alternative. Although it makes many aspects of Javascript sane and convenient, it still suffers from weak-typing.
 
#:
 
# '''We need JavaScript.''' Using it for what it is good for, i.e. providing a platform for browser development, but not using the language ''per se'', is therefore desirable, and many are working to achieve this, in varying forms. There various ways to do it, but we ought to opt for compiling an existing language, Haskell, to JavaScript, because we do not have time to learn or teach other people a new language, garner a new library set and a new type checker and all that Haskell implementations provide.
 
   
  +
* lack of module system (only pre-ES6),
== Updating this page ==
 
  +
* weak-typing,
  +
* verbose function syntax<sup>1</sup> (pre-ES6),
  +
* late binding<sup>2</sup>, which has led to the creation of various static analysis tools to alleviate this language flaw<sup>3</sup>, but with limited success<sup>4</sup> (there is even a static type checker<sup>5</sup>),
  +
* finicky equality/automatic conversion,
  +
* <code>this</code> behaviour,
  +
* and lack of static types.
   
  +
# '''We need JavaScript.''' Using it for what it is good for, i.e. providing a platform for browser development, but not using the language ''per se'', is therefore desirable, and many are working to achieve this, in varying forms. There are various ways to do it, but we ought to opt for compiling an existing language, Haskell, to JavaScript, because we do not have time to learn or teach other people a new language, garner a new library set and a new type checker and all that Haskell implementations provide.
Please update and expand this page with the various attacks on this problem and their progress. The question of The JavaScript Problem comes up every so often and this should be the page to link people to.
 
   
== Attacks ==
+
== Mainstream alternatives ==
  +
  +
=== CoffeeScript ===
  +
It makes many aspects of JavaScript sane and convenient, and you get a compilation check that verifies syntax, however it still suffers greatly from weak-typing.
  +
  +
=== TypeScript ===
  +
  +
Structural typing with traditional generics on top of JavaScript.
  +
Of all the alternatives, TypeScript's advantage is that it makes no changes to JavaScript. Existing JavaScript code that passes jshint is valid Typescript code. TypeScript also adds features from the latest JavaScript standards that it can compile down to older versions of JavaScript. TypeScript is by far the easiest JavaScript variant to learn. The downside is that one might desire a better language than just JavaScript + types.
  +
  +
TypeScript defaults to dynamic typing when it can't figure the type out. However, it now has a `noImplicitAny` setting that will give a compilation error if it can't figure out the type.
  +
  +
Structural sub-typing seems a good fit for JavaScript. Typescript did suffer from null acting as a valid value for any type until 2.0, which introduced the `strictNullChecks` compiler option.
  +
  +
== Haskell -> JS ==
   
 
=== UHC ===
 
=== UHC ===
   
Original blog post [https://github.com/atzedijkstra/javascript-runtime-for-UHC here.] Quickstart guide [http://chrisdone.com/posts/2012-01-06-uhc-javascript.html here.] A more in-depth discussion about the current capabilities of the backend [http://www.norm2782.com/improving-uhc-js-report.pdf here.] Blog post of using UHC in a real app [http://alessandrovermeulen.me/2012/01/26/getting-rid-of-javascript-with-haskell/ here.]
+
Original blog post [https://github.com/atzedijkstra/javascript-runtime-for-UHC here.] Quickstart guide [http://chrisdone.com/posts/2012-01-06-uhc-javascript.html here.] A more in-depth discussion about the current capabilities of the backend [http://www.norm2782.com/improving-uhc-js-report.pdf here.] For an example of using the JavaScript compilation for a real app see this [http://alessandrovermeulen.me/2012/01/26/getting-rid-of-javascript-with-haskell/ blog post], there is also a port of wxAsteroids to the browser (see [http://uu-computerscience.github.io/js-asteroids/ github] or a [http://www.rubendegooijer.nl/posts/2013-04-06-haskell-oop.html blog post]).
   
 
* Beta.
 
* Beta.
Line 22: Line 40:
 
* Doesn't produce an explosion of code, seemingly.
 
* Doesn't produce an explosion of code, seemingly.
 
* Fairly substantial JS/DOM/W3C/HTML5 API.
 
* Fairly substantial JS/DOM/W3C/HTML5 API.
  +
* Currently works.
  +
  +
=== Fay ===
  +
  +
Website: https://github.com/faylang/fay/wiki
  +
Discussion on Reddit: [http://www.reddit.com/r/haskell/comments/11yrpi/fay_slides/ Fay slides]. The package is on [http://hackage.haskell.org/package/fay Hackage]. Fetch with Git:
  +
git clone git://github.com/faylang/fay.git
  +
  +
* Compiles a subset of Haskell, needs more
 
* Currently works.
 
* Currently works.
   
 
=== GHCJS ===
 
=== GHCJS ===
   
The Github page is [https://github.com/ghcjs/ghcjs here.]
+
The GitHub page is [https://github.com/ghcjs/ghcjs here.]
   
* Alpha.
 
 
* Works.
 
* Works.
 
* Incomplete.
 
* Incomplete.
Line 34: Line 60:
 
* Compiles most pure Haskell libraries no problem.
 
* Compiles most pure Haskell libraries no problem.
 
* FFI to JS works, and the author, sviperll is a helpful guy.
 
* FFI to JS works, and the author, sviperll is a helpful guy.
  +
  +
==== Libraries ====
  +
  +
* The [https://reflex-frp.org/ reflex] library provides [http://hackage.haskell.org/package/reflex-dom reflex-dom] for building web GUIs using GHCJS. ([https://www.youtube.com/watch?v=mYvkcskJbc4 Presentation], [https://obsidian.systems/reflex-nyhug/#/step-1 Slides])
  +
  +
* The [http://hackage.haskell.org/package/miso miso] library provides an Elm-like interface for building web GUIs using GHCJS. Allows for isomorphic javascript.
  +
  +
==== Apps ====
  +
  +
* [http://markup.rocks markup.rocks] - Pandoc + GHCJS + Reflex. [https://www.reddit.com/r/haskell/comments/35ax22/ive_compiled_pandoc_with_ghcjs_and_built_an/ Reddit Thread], [https://github.com/osener/markup.rocks Source code].
  +
  +
==== Further reading ====
  +
  +
* [http://blog.wuzzeb.org/full-stack-web-haskell/client.html Lenz blog: Chapter 4 - GHCJS and the Client]
  +
  +
=== Haste ===
  +
  +
[http://haste-lang.org Website], [http://hackage.haskell.org/package/haste-compiler Hackage]
  +
  +
* Seamless, type-safe single program framework for client-server communication
  +
* Easy JavaScript interoperability
  +
* Generates small, fast, minifiable code.
  +
* Lightweight concurrency, Cabal integration, FFI and GHC extensions supported.
  +
* Cross platform.
  +
* Works.
   
 
=== [[JMacro]] ===
 
=== [[JMacro]] ===
   
On the Haskell wiki (see above) and on [http://hackage.haskell.org/package/jmacro hackage]
+
On the Haskell wiki (see above) and on [http://hackage.haskell.org/package/jmacro Hackage]
   
* Mature
+
* Mature, Maintained
  +
* Not Haskell but an EDSL _in_ Haskell nonetheless.
* Works
 
  +
* JMacro Panels provides a purely Haskell combinator library that generates dynamically updating html and js with asynchronous client-server communication.
* Complete
 
* Maintained
 
* Not Haskell
 
 
* Syntax is a fusion of Haskell and JavaScript
 
* Syntax is a fusion of Haskell and JavaScript
 
* Untyped, but with syntactic correctness (at least) enforced at compile-time.
 
* Untyped, but with syntactic correctness (at least) enforced at compile-time.
 
* Embeddable through quasi-quoting
 
* Embeddable through quasi-quoting
 
* Support for various forms of code-generation
 
* Support for various forms of code-generation
 
=== Roy ===
 
 
[http://roy.brianmckenna.org/ Roy]: meld JavaScript semantics with functional languages. Experimental, but has many bread-and-butter Haskell features. Probably does not generate efficient code.
 
   
 
=== Others ===
 
=== Others ===
   
* [https://github.com/valderman/haste-compiler#haste Haste], a compiler to generate Javascript code from Haskell.
 
 
* [https://github.com/johang88/haskellinjavascript Haskell interpreter in JS] — An interpreter. Haven't tried but is apparently dead.
 
* [https://github.com/johang88/haskellinjavascript Haskell interpreter in JS] — An interpreter. Haven't tried but is apparently dead.
 
* YHC JS backend — Beta-ish. Apparently works, but I was unable to compile YHC, so haven't tried yet. I would be interested in anyone's experience using it. There's [http://www.haskell.org/haskellwiki/Yhc/Javascript an old wiki page] about Yhc's JavaScript support, but Yhc itself is a dead project.
 
* YHC JS backend — Beta-ish. Apparently works, but I was unable to compile YHC, so haven't tried yet. I would be interested in anyone's experience using it. There's [http://www.haskell.org/haskellwiki/Yhc/Javascript an old wiki page] about Yhc's JavaScript support, but Yhc itself is a dead project.
 
* Emscripten — not Haskell→JS, but compiles LLVM/Clang output to JavaScript. Could possibly be used for GHC→LLVM→JS compiling, which I tried, and works, but would have to also compile the GHC runtime which is not straight-forward (to me) for it to actually run.
 
* Emscripten — not Haskell→JS, but compiles LLVM/Clang output to JavaScript. Could possibly be used for GHC→LLVM→JS compiling, which I tried, and works, but would have to also compile the GHC runtime which is not straight-forward (to me) for it to actually run.
* hjscript — Beta. EDSL, not Haskell→JS. Works. Not ''very'' annoying to program in, but is JS semantics, not Haskell. Hackage package [http://hackage.haskell.org/package/HJScript here.]
+
* HJScript — Beta. EDSL, not Haskell→JS. Works. Not ''very'' annoying to program in, but is JS semantics, not Haskell. Hackage package [http://hackage.haskell.org/package/HJScript here.]
* Some have also tried writing a Haskell→JS compiler to make a more direct JS-aware translation of code (to not have huge code output a la GHCJS, YHC, Emscripten), but ought to prefer to avoid NIH and hack on GHCJS or UHC.
+
* Some have also tried writing a Haskell→JS compiler to make a more direct JS-aware translation of code (to not have huge code output a la GHCJS, YHC, Emscripten).
  +
* I've tried [http://lpaste.net/84342 compiling via JHC and Emscripten] a while ago, which worked, but IIRC the output was rather slow.
  +
* It's also possible to compile Hugs via Emscripten, which works (with minor tweaks), but again, it's too slow.
  +
  +
  +
== FP -> JS ==
  +
  +
=== Ur/Web ===
  +
  +
http://www.impredicative.com/ur/
  +
  +
Perhaps the problem with Ur is that they are selling both a backend and a frontend together. Being a new language, the backend is lacking in libraries to be practical for many tasks. However, there is an RSS reader that is using Ur for the front-end and Haskell for the backend: https://bazqux.com/
  +
  +
=== Opa ===
  +
  +
Similar to Ur/Web, write one language in the front-end and backend: http://opalang.org/ Haven't tried it. No idea what its type-system is like.
  +
  +
=== OCaml ===
  +
  +
The OCaml -> JS compiler is supposed to be good, it is now used at Facebook for an internal in-browser code editor.
  +
http://ocsigen.org/js_of_ocaml/
  +
  +
=== GorillaScript ===
  +
  +
http://ckknight.github.io/gorillascript/
  +
  +
immutable by default, global type inference, macros, what coffeescript should have been. The syntax is similar to coffeescript
  +
  +
=== Roy ===
  +
  +
[http://roy.brianmckenna.org/ Roy]: meld JavaScript semantics with functional languages. Experimental, but has many bread-and-butter Haskell features.
  +
Roy is written in JS.
  +
  +
=== PureScript ===
  +
  +
[http://purescript.org/ PureScript] aims to provide a type system for a fragment of JavaScript. It includes many features which are similar to features of Haskell, such as type classes and RankNTypes, and its syntax mirrors that of Haskell very closely, but it is a fundamentally different language with the execution model of JavaScript. PureScript is written in Haskell. The project has a focus on the generation of efficient, readable JavaScript.
  +
  +
=== Idris ===
  +
  +
Idris is a compiled language with dependent types, implemented in Haskell, with backends for both LLVM and JavaScript. Experimental.
  +
  +
* Full dependent types with dependent pattern matching where clauses, with rule, simple case expressions, pattern matching let and lambda bindings
  +
* Dependent records with projection and update
  +
* Type classes
  +
* Monad comprehensions
  +
* Syntactic conveniences for lists, tuples, dependent pairs do notation and idiom brackets
  +
* Indentation significant syntax
  +
* Extensible syntax
  +
* Tactic based theorem proving (influenced by Coq)
  +
* Cumulative universes
  +
* Totality checking
  +
* Simple foreign function interface (to C)
  +
* Hugs style interactive environment
  +
  +
Links:
  +
* [http://idris-lang.org/ Website idris-lang.org]
  +
* [[Dependent_type|Dependent Type in haskell wiki]]
  +
* [http://en.wikipedia.org/wiki/Dependent_type WP (en) Dependent type] (with Idris listed under language comparison)
  +
  +
  +
=== Elm ===
  +
  +
[http://elm-lang.org/ Elm] is a reactive pure functional programming language implemented in Haskell, which takes heavy inspiration from Haskell's syntax.
  +
It's considered a direct competitor to PureScript, since it's basically a more beginner-friendly yet pared down "Haskell for the web".
  +
Unfortunately, this desire to be beginner-friendly has left Elm without Higher Kinded Types.
  +
It has a simple foreign function interface for JS interop, called "ports".
  +
  +
== Links ==
  +
  +
* [http://www.reddit.com/r/haskell/comments/28o7my/what_is_the_state_of_the_javascript_problem_what/ What is the state of "The JavaScript Problem"? What is the currently preferred way to solve in a real world application?] (reddit, 2014-06-20)
  +
* [https://github.com/yesodweb/yesod/wiki/JavaScript-Options Yesod - JavaScript Options]
  +
* [http://chrisdone.com/tags/javascript Chris Done Blog] - Tag: JavaScript
   
 
== Footnotes ==
 
== Footnotes ==
Line 67: Line 182:
 
# Early binding allows for static verification of the existence of method-signature pairs (e.g. v-tables). Late binding does not give the compiler (or an IDE) enough information for existence verification, it has to be looked up at run-time.
 
# Early binding allows for static verification of the existence of method-signature pairs (e.g. v-tables). Late binding does not give the compiler (or an IDE) enough information for existence verification, it has to be looked up at run-time.
 
# There are several hinting libraries, which developers insist are indispensable tools when developing JavaScript seriously, such as JavaScript lint, JSLint, and JSure.
 
# There are several hinting libraries, which developers insist are indispensable tools when developing JavaScript seriously, such as JavaScript lint, JSLint, and JSure.
# “Any non-trivial analysis is very difficult due to Javascript’s dynamic nature.” — Berke Durak, Ph.D., author of jsure.
+
# “Any non-trivial analysis is very difficult due to JavaScript’s dynamic nature.” — Berke Durak, Ph.D., author of jsure.
 
# Google Inc. thought it necessary to develop a compiler, Google Closure, which does type-checking and limited inference.
 
# Google Inc. thought it necessary to develop a compiler, Google Closure, which does type-checking and limited inference.
   

Latest revision as of 18:02, 26 October 2020

The problem

The JavaScript problem is two-fold and can be described thus:

  1. JavaScript, the language. JavaScript, the language, has some issues that make working with it inconvenient and make developing software harder :
  • lack of module system (only pre-ES6),
  • weak-typing,
  • verbose function syntax1 (pre-ES6),
  • late binding2, which has led to the creation of various static analysis tools to alleviate this language flaw3, but with limited success4 (there is even a static type checker5),
  • finicky equality/automatic conversion,
  • this behaviour,
  • and lack of static types.
  1. We need JavaScript. Using it for what it is good for, i.e. providing a platform for browser development, but not using the language per se, is therefore desirable, and many are working to achieve this, in varying forms. There are various ways to do it, but we ought to opt for compiling an existing language, Haskell, to JavaScript, because we do not have time to learn or teach other people a new language, garner a new library set and a new type checker and all that Haskell implementations provide.

Mainstream alternatives

CoffeeScript

It makes many aspects of JavaScript sane and convenient, and you get a compilation check that verifies syntax, however it still suffers greatly from weak-typing.

TypeScript

Structural typing with traditional generics on top of JavaScript. Of all the alternatives, TypeScript's advantage is that it makes no changes to JavaScript. Existing JavaScript code that passes jshint is valid Typescript code. TypeScript also adds features from the latest JavaScript standards that it can compile down to older versions of JavaScript. TypeScript is by far the easiest JavaScript variant to learn. The downside is that one might desire a better language than just JavaScript + types.

TypeScript defaults to dynamic typing when it can't figure the type out. However, it now has a `noImplicitAny` setting that will give a compilation error if it can't figure out the type.

Structural sub-typing seems a good fit for JavaScript. Typescript did suffer from null acting as a valid value for any type until 2.0, which introduced the `strictNullChecks` compiler option.

Haskell -> JS

UHC

Original blog post here. Quickstart guide here. A more in-depth discussion about the current capabilities of the backend here. For an example of using the JavaScript compilation for a real app see this blog post, there is also a port of wxAsteroids to the browser (see github or a blog post).

  • Beta.
  • Only works for UHC, but promising.
  • UHC compiles enough of Hackage to be very useful.
  • Doesn't produce an explosion of code, seemingly.
  • Fairly substantial JS/DOM/W3C/HTML5 API.
  • Currently works.

Fay

Website: https://github.com/faylang/fay/wiki Discussion on Reddit: Fay slides. The package is on Hackage. Fetch with Git:

 git clone git://github.com/faylang/fay.git
  • Compiles a subset of Haskell, needs more
  • Currently works.

GHCJS

The GitHub page is here.

  • Works.
  • Incomplete.
  • Nicely designed.
  • Compiles most pure Haskell libraries no problem.
  • FFI to JS works, and the author, sviperll is a helpful guy.

Libraries

  • The miso library provides an Elm-like interface for building web GUIs using GHCJS. Allows for isomorphic javascript.

Apps

Further reading

Haste

Website, Hackage

  • Seamless, type-safe single program framework for client-server communication
  • Easy JavaScript interoperability
  • Generates small, fast, minifiable code.
  • Lightweight concurrency, Cabal integration, FFI and GHC extensions supported.
  • Cross platform.
  • Works.

JMacro

On the Haskell wiki (see above) and on Hackage

  • Mature, Maintained
  • Not Haskell but an EDSL _in_ Haskell nonetheless.
  • JMacro Panels provides a purely Haskell combinator library that generates dynamically updating html and js with asynchronous client-server communication.
  • Syntax is a fusion of Haskell and JavaScript
  • Untyped, but with syntactic correctness (at least) enforced at compile-time.
  • Embeddable through quasi-quoting
  • Support for various forms of code-generation

Others

  • Haskell interpreter in JS — An interpreter. Haven't tried but is apparently dead.
  • YHC JS backend — Beta-ish. Apparently works, but I was unable to compile YHC, so haven't tried yet. I would be interested in anyone's experience using it. There's an old wiki page about Yhc's JavaScript support, but Yhc itself is a dead project.
  • Emscripten — not Haskell→JS, but compiles LLVM/Clang output to JavaScript. Could possibly be used for GHC→LLVM→JS compiling, which I tried, and works, but would have to also compile the GHC runtime which is not straight-forward (to me) for it to actually run.
  • HJScript — Beta. EDSL, not Haskell→JS. Works. Not very annoying to program in, but is JS semantics, not Haskell. Hackage package here.
  • Some have also tried writing a Haskell→JS compiler to make a more direct JS-aware translation of code (to not have huge code output a la GHCJS, YHC, Emscripten).
  • I've tried compiling via JHC and Emscripten a while ago, which worked, but IIRC the output was rather slow.
  • It's also possible to compile Hugs via Emscripten, which works (with minor tweaks), but again, it's too slow.


FP -> JS

Ur/Web

http://www.impredicative.com/ur/

Perhaps the problem with Ur is that they are selling both a backend and a frontend together. Being a new language, the backend is lacking in libraries to be practical for many tasks. However, there is an RSS reader that is using Ur for the front-end and Haskell for the backend: https://bazqux.com/

Opa

Similar to Ur/Web, write one language in the front-end and backend: http://opalang.org/ Haven't tried it. No idea what its type-system is like.

OCaml

The OCaml -> JS compiler is supposed to be good, it is now used at Facebook for an internal in-browser code editor. http://ocsigen.org/js_of_ocaml/

GorillaScript

http://ckknight.github.io/gorillascript/

immutable by default, global type inference, macros, what coffeescript should have been. The syntax is similar to coffeescript

Roy

Roy: meld JavaScript semantics with functional languages. Experimental, but has many bread-and-butter Haskell features. Roy is written in JS.

PureScript

PureScript aims to provide a type system for a fragment of JavaScript. It includes many features which are similar to features of Haskell, such as type classes and RankNTypes, and its syntax mirrors that of Haskell very closely, but it is a fundamentally different language with the execution model of JavaScript. PureScript is written in Haskell. The project has a focus on the generation of efficient, readable JavaScript.

Idris

Idris is a compiled language with dependent types, implemented in Haskell, with backends for both LLVM and JavaScript. Experimental.

  • Full dependent types with dependent pattern matching where clauses, with rule, simple case expressions, pattern matching let and lambda bindings
  • Dependent records with projection and update
  • Type classes
  • Monad comprehensions
  • Syntactic conveniences for lists, tuples, dependent pairs do notation and idiom brackets
  • Indentation significant syntax
  • Extensible syntax
  • Tactic based theorem proving (influenced by Coq)
  • Cumulative universes
  • Totality checking
  • Simple foreign function interface (to C)
  • Hugs style interactive environment

Links:


Elm

Elm is a reactive pure functional programming language implemented in Haskell, which takes heavy inspiration from Haskell's syntax. It's considered a direct competitor to PureScript, since it's basically a more beginner-friendly yet pared down "Haskell for the web". Unfortunately, this desire to be beginner-friendly has left Elm without Higher Kinded Types. It has a simple foreign function interface for JS interop, called "ports".

Links

Footnotes

  1. Its support for closures is commonly noted as being one of JavaScript’s redeeming features.
  2. Early binding allows for static verification of the existence of method-signature pairs (e.g. v-tables). Late binding does not give the compiler (or an IDE) enough information for existence verification, it has to be looked up at run-time.
  3. There are several hinting libraries, which developers insist are indispensable tools when developing JavaScript seriously, such as JavaScript lint, JSLint, and JSure.
  4. “Any non-trivial analysis is very difficult due to JavaScript’s dynamic nature.” — Berke Durak, Ph.D., author of jsure.
  5. Google Inc. thought it necessary to develop a compiler, Google Closure, which does type-checking and limited inference.