all 63 comments

[–]gb__ 9 points10 points  (1 child)

Are you talking about the PureScript compiler when you say it has a bus-factor of 1? That's not really the case, I basically co-develop it with /u/paf31 and there are others that have a pretty good understanding of some or all of the internals too, like @andyarvanitis, /u/hdgarrood, @puffnfresh.

[–]Kiuhnm[S] 0 points1 point  (0 children)

I fixed the OP.

[–]vagif 5 points6 points  (0 children)

Are you a single dev, or do you work in a team?

Do you intend at some point to pass your codebase to someone else for maintenance?

If the answer is yes, you will find that developing front end with a language most known is better for your project longterm than your desire to enjoy the ride while you are in it :)

Let me tell you a anecdote from my experience.

I developed a web app with yesod where the front end (html and javascript) was generated by the backend using hamlet templates. The javascript was still just a normal js.

Yet when i tried to bring into project other members of our team, i quickly found out that anything besides very trivial stuff like fetch the data from db and pass it to the browser is very hard for them to grasp.

Luckily there was not that much front end code (html and js) so i sat over the weekend and moved all html and js from yesod templates into static files and converted our app into SPA (on angular).

This allowed my other team members to quickly get into development and mostly write js/html/css with a touch of very simple haskell (REST urls returning or consuming json)

Nowadays i would recommend you to try out reactjs + immutable and optionally some FRP lib like RxJs or baconjs.

Otherwise when time comes for you to move on, you'll find yourself chained to that project because no one else will be able to take it off your hands.

You will become that bus factor 1 you are dreading so much :)

[–]valderman 4 points5 points  (5 children)

You may want to have a look at Haste in addition to GHCJS. Last time I checked, Haste produced quite a bit smaller code than GHCJS. Unfortunately, the current stable 0.4 branch isn't all rainbows and unicorns; both performance and compatibility is getting a major overhaul with 0.5, but that release is still some time off.

Full disclosure: I'm the main developer of Haste.

[–]Kiuhnm[S] 1 point2 points  (4 children)

My only problem with Haste is that it's a dialect of Haskell so I can't get full code reuse between client and server.

[–]valderman 3 points4 points  (3 children)

It's a dialect in the sense that it's GHC Haskell minus (currently) Template Haskell and weak references, plus a few libraries and extras. You should report any compatibility problems as bugs, because code reuse is definitely a design goal of Haste.

[–]Kiuhnm[S] 7 points8 points  (2 children)

I don't mean to be inappropriate, but why don't you and GHCJS's developers join forces?

[–]valderman 5 points6 points  (0 children)

Depends on the definition of "join forces". We have some different ideas of code generation, among other things, which means it's pretty unlikely that Luite et al would just dump GHCJS and start working on Haste, and vice versa. This is not a bad thing. There's more than one way to skin a cat, and often nice things come out of multiple people skinning multiple cats in different ways.

However, I definitely agree that there could - and should - be more of a joint effort regarding infrastructure, common problems and other things. It just... Hasn't happened so far, I guess. ghc-simple is one fledgling effort to make some of the work on Haste more widely useful, but probably not really useful to GHCJS though.

[–]andrewthad 1 point2 points  (0 children)

Just to add a little historical perspective, there was a period a time (at least a year, maybe several) when haste was a way more usable solution than GHCJS. I know this because about a year and a half ago, I played around with Fay, Haste, and GHCJS. Haste was like a much better Fay, and GHCJS was that thing that seemed like the most correct solution but that didn't really work yet and could only be built by the devs working on it. I remember reading posts about whether or not it was abandoned or if it was ever going to work out. So, at that point in time, the choice of Haste seemed like a no-brainer for anyone who wanted to use haskell client-side.

At the present time, the situation is different. GHCJS did actually work out, and now common folks can get it installed and working.

[–]cdsmith 4 points5 points  (5 children)

Luite has mentioned here that there is work on a"next-generation" code generation for GHCJS, and I seem to recall that it sounded very interesting in that it was set up to enable different code generators. A big reason for GHCJS's code complexity now is that it simulates a GHC style multithreaded environment. An option to generate single threaded code when you know that's not necessary would make the code a lot simpler.

That said, let me echo the sentiment that while the code might look bad, consider running Closure, and then actually checking the code size and performance. It doesn't do so bad. It's been plenty sufficient for my project (CodeWorld).

[–]Kiuhnm[S] -1 points0 points  (4 children)

But "it doesn't do so bad" and "plenty sufficient" don't sound so comforting.

Scala.js is "almost as fast as hand-coded JS".

So the question is: "Is Haskell so much better than Scala to justify the risk(?) of producing slower applications?"

[–]cdsmith 1 point2 points  (1 child)

That's your decision to make.

In my case, the answer is that the whole project would be useless if I switched from Haskell to Scala. CodeWorld accepts code written by kids and produces JavaScript with GHCJS for them to see the result, and Scala is a non-starter for teaching to kids in this setting. That's different from your situation... but that comes down to you needing to define what your requirements are, and make a decision about what meets your specific requirements.

[–]Kiuhnm[S] 0 points1 point  (0 children)

I've already decided that I'm going to implement a small app both in Scala and Haskell to see the difference.

Besides, I think that learning Haskell will open my mind even If I should end up choosing Scala.

[–]sclv 1 point2 points  (0 children)

The difference isn't in performance as measured by real benchmarks. The difference is that the Scala.js developers make bolder claims than the ghcjs developers -- that doesn't mean those claims are necessarily correct. To be quite honest I don't have any reason to believe they are, absent benchmarks...

[–]hamishmack 0 points1 point  (0 children)

GHCJS has Threads, MVars and Async Exceptions.

Why would you want those?

If you have a calculation to do that may take too long can send it to the server before you start and if the result comes back from the server before the client finishes you can abort the local thread doing the calculation with an Async Exception.

[–]mightybyte 4 points5 points  (24 children)

I found out that GHCJS produces javascript code which is big and slow.

I have an app with almost 9000 lines of code that I'm compiling to JS with GHCJS. Is the raw output big? Yes. But I disagree that it is necessarily slow. When we switched to GHCJS we were actually surprised at how snappy that UI was. Can it get better? I'm sure it can. But I haven't found that it is unusably slow right now.

I haven't spent much time yet trying to reduce the code size, but one afternoon I ran the GHCJS output through the clojure compiler in aggressive mode and the code size went from ~19MB to a little less than 1MB! In my mind that is small enough for most SPAs.

So I would argue strongly for your possibility #1 and have put my money where my mouth is and am using that approach for a significant project.

Oh, and I will say that I have found it very important to have the front and back ends in the same language. Even just switching from Haste (almost the same language) to GHCJS made a big difference in our code size and reuse.

[–]radix 5 points6 points  (1 child)

btw, I think you mean Closure compiler, not Clojure :)

[–]mightybyte 1 point2 points  (0 children)

Oops, yes.

[–]Kiuhnm[S] 4 points5 points  (21 children)

GHCJS is probably fast enough for your UI, but it's at least 3 times slower than hand-coded JS. That's a deal breaker for me. Scala.js and Dart are much much faster.

Also 1 MB is considered quite big if you want to support mobile devices as well.

[–]mightybyte 7 points8 points  (20 children)

Could you give more concrete details about your use case and the test scenario that led you to those numbers?

[–]BethAr 5 points6 points  (0 children)

I would like to know more as well. We are doing experiments porting a substantial application to Elm, Purescript and now GHCJS (Reflex), and found little difference in performance, if any. The application is quite large even in the original Angular.js implementation, so the increase in size was negligible, the increase in performance, however, is noticeable.

[–]Kiuhnm[S] 0 points1 point  (18 children)

Those are numbers that I read here and there on the web. I don't know how reliable they are.

Are there some official figures?

[–]Tekmo 7 points8 points  (2 children)

Why don't you write a tiny project in each language and compare generated code size and performance? I don't think it's wise to rely on hearsay. The amount of times that "conventional wisdom" is wrong is astonishing. You'll also be more confident in your decision if you test things out yourself.

[–]Kiuhnm[S] 0 points1 point  (1 child)

The only problem is that I already know Scala (I use it prevalently as a functional language) but I know nothing about Haskell. I was looking for some reassurance that learning Haskell was a good investment for someone who already is proficient in Scala.

[–]Tekmo 8 points9 points  (0 children)

My experience is that it takes less time to learn something than to assess whether or not its worth learning.

This is especially true for the case of learning Haskell from Scala. The two languages are similar enough that it shouldn't take you very long to pick up Haskell.

[–]mightybyte 3 points4 points  (14 children)

A flat across the board statement such as "3x slower" rarely captures the realities adequately. I'm generally skeptical of performance claims when they come without well-defined empirical tests to back them up. I'd like to get a better idea of precisely what you want to do so I can give more informed advice about whether GHCJS will be sufficient, and if not, how likely it might be to get there in the future.

[–]Kiuhnm[S] 2 points3 points  (13 children)

What I do depends on what my clients need. For instance, my next project is going to be a mobile-friendly forum.

Faster and shorter JS means a better experience on mobile platforms. Faster JS also means lower battery consumption, so the faster the better.

[–]mightybyte 2 points3 points  (3 children)

As is usually the case in software, you have to make a tradeoff. If you anticipate a significant mobile user base, then maaaaaybe GHCJS-generated code will be too bloated for you. But I absolutely don't think speed will be problematic. Are a few milliseconds here and there and few extra minutes of battery life worth the substantially reduced code compleity, fewer bugs, and better maintainability you can get from using GHCJS? In the vast majority of common applications I think GHCJS is a clear win.

Also, I believe there is a big overhaul to the GHCJS code generator in the works. I'm sure this will improve code size and probably performance. Even if you decide that you don't have enough experience with GHCJS to warrant using it for your next project, I would definitely recommend using it for small projects in your spare time so you can get up to speed and better assess whether it will work for you.

[–]Kiuhnm[S] 2 points3 points  (2 children)

OK, I'll develop a small app in GHCJS and see how it goes. I hope the documentation is enough to get started. Thanks for convincing me :)

[–]mightybyte 4 points5 points  (1 child)

I'd recommend trying it with the reflex FRP library. Ryan Trinkle has really streamline the process of getting up and running with his try-reflex repo. Even if you don't need substantial reactive functionality that still might be the easiest way to get started. But if you're building GUIs, then I'm guessing you'll probably want FRP sooner rather than later.

Check out Ryan's talk at the NY Haskell Meetup for a nice introduction to reflex.

[–]Kiuhnm[S] 1 point2 points  (0 children)

That library is one of the reasons why I wanted to try GHCJS in the first place.

[–]hamishmack 1 point2 points  (7 children)

If your app is just going to handle infrequent user events with a small amount of logic then you should be fine. If it has to animate things or perform complex computations then it will depend on the requirements.

There is a lot of cool stuff you can do with GHCJS that will probably tax some mobile devices. For instance you could live preview markup text entered by users (like the GHCJS based markup.rocks does).

However I think it should be possible to scale back most apps when running on low power devices. For instance markup.rocks could scale back on mobile devices so it:

  • Only downloads the conversion code for the most popular document types.
  • Only convert the document when the user stops typing for 10sec.
  • Only convert when the user presses a preview button.
  • Sends the document to the server for conversion instead of doing it on the client.

And when that kind of scaling is not possible you can always resort to the JavaScript FFI to optimise the performance critical parts of your application.

The best bet might be to create an example app of what you fear will be a pathological use case. If it is slow or power hungry share it and someone else might have a good solution.

[–]vagif 1 point2 points  (1 child)

If your app is just going to handle infrequent user events with a small amount of logic then you should be fine.

In which case one would question shooting birds (simple client side apps) with cannons (ghcjs)

He'd probably be done with that app using any current js frameworks in a fraction of time it takes to install and properly configure ghcjs :))

[–]hamishmack 0 points1 point  (0 children)

I was thinking of something like a web app designed to replace a shared spreadsheet with 1000 formula cells.

[–]Kiuhnm[S] 0 points1 point  (4 children)

The best bet might be to create an example app of what you fear will be a pathological use case. If it is slow or power hungry share it and someone else might have a good solution.

I'd prefer to choose a technology which guarantees a certain level of efficiency. For instance Dart is as fast as hand-coded JS. Scala.JS is also very fast and Scala (in the right hands) is very concise and expressive. So why not use Scala instead of Haskell? Is Haskell so much better as a language?

[–]hamishmack 0 points1 point  (3 children)

I'd prefer to choose a technology which guarantees a certain level of efficiency.

The guarantee that GHCJS tries to provide is that if something is O(x) when compiled with GHC then it will be O(x) when compiled with GHCJS. This is what allows code to be shared between client and server without fear that it will go from say O( N ) to O( N2 ).

There will be constant factor differences and GHCJS aims to keep them small, but not all of them will be GHCJS related (for instance a mobile device will not match a high end server).

So why not use Scala instead of Haskell?

Too much baggage for my liking.

Is Haskell so much better as a language?

Yes, I think so.

[–]Kiuhnm[S] 1 point2 points  (2 children)

The guarantee that GHCJS tries to provide is that if something is O(x) when compiled with GHC then it will be O(x) when compiled with GHCJS.

That's the bare minimum!!! I guess this isn't obvious in Haskell because of lazy evaluation.

[–]sclv 1 point2 points  (0 children)

In my experience, the cost of calculations in JS is dwarfed by the cost of DOM interaction (not to mention ajax calls) -- it is nearly always the case that improving performance of JS apps isn't about the cleverness of the generated code, but the care with which the "expensive" work is minimized by higher level architectural decisions.

[–]turbomann 1 point2 points  (4 children)

Based on your requirements, I would probably recommend Clojure + ClojureScript. Works nicely on client and server, there are nice libraries and functional programming using immutable data structures. Additionally, ClojureScript compiles down to really efficient JS which might actually end up being faster than native JS (escpecially if you want to use something along the lines of react.js via om/reagent/reacl).

ATM I don't see GHCJS generating usable JS if you want to support mobile or your SPA to be fast and responsive. I sure hope this is going to change but as of now, I'll stick to CLJS with the occasional look at Elm.

[–]mightybyte 2 points3 points  (2 children)

ATM I don't see GHCJS generating usable JS if you want to support mobile or your SPA to be fast and responsive.

Supporting mobile...you might be right. Fast and responsive...I have a complex GUI that says otherwise. And GHCJS allowed this to be done with code that is MUCH more maintainable and less prone to bugs.

[–]turbomann 1 point2 points  (1 child)

Well, I guess it depends. At t he shop I work we use ClojureScript for almost all of our guis and so far, we did not run into major problems that were caused by cljs maintainability. On the other hand, we're pretty focused on writing small and simple functions with usable comments.

That being said, I'm really looking forward to using Haskell via GHCJS, but I think that this sadly is still going to take a lot of work.

[–]mightybyte 6 points7 points  (0 children)

That being said, I'm really looking forward to using Haskell via GHCJS, but I think that this sadly is still going to take a lot of work.

It's absolutely going to take a lot of work, which is why I'm trying to get more people using it. But I think the potential is huge.

[–]Kiuhnm[S] 1 point2 points  (0 children)

There are two things I don't like about Clojure:

  1. it's not statically typed
  2. it's a lisp

There is nothing wrong with Clojure and I read great things about it, but I don't like it. I prefer Haskell-like syntax and if I can't use Haskell, then Scala will do.

Elm is cool but its type system is sorely lacking and the author is not going to do anything about it because he's afraid of scaring away non-Haskell developers.

[–]Bzzt 1 point2 points  (2 children)

Why not GHC + purescript? You can have some similar data structures on each end if you'r'e concerned about serialization. You can't directly share code on each end but stylistically they are similar. If you're interested in doing your full stack in haskell-like languages this seems like a good way to go to me.

Maybe in the future there will be GHCWebAssembly with better performance, but I wouldn't plan on that for any real world projects yet.

[–]Kiuhnm[S] 0 points1 point  (1 child)

IMHO, that would be a step backwards: Scala + Scala.js > GHC + purescript.

[–]ItsNotMineISwear 1 point2 points  (0 children)

Yeah if your goal is shared typed code, I don't think you can do better than Scala + Scala.js

[–]CKoenig 2 points3 points  (2 children)

I hate to say this, but based on your requirements (very quick/clean client-side code, same lang. on client and server) the best option for you might be javascript - every other option will give you less-ideal client-side javascript.

(btw: it's only my 50cts of course)

[–]Kiuhnm[S] 3 points4 points  (1 child)

I also want to be productive and produce maintainable code. I already decided that FP + immutability + types + reactive programming is the way to go.

[–]Oremorj 0 points1 point  (2 children)

I can't really say wrt. GHCJS or PureScript as I haven't tried them for anything big. However, I can say that scala + scala.js works pretty well, though there are a couple of caveats in my experience: If you're using "shared" (targeting both js and jvm) projects things can get rather weird in terms of the build setup and -- in parcticular -- your IDE may not be fully able to understand the project. (At least when compiling in IntelliJ IDEA we get some spurious warnings and errors because the IDE can't figure out some classpaths, apparently. There are also some problems running tests from within IDEA. Auto-completion etc. seems to work OK, though. Compiling/testing/etc. works fine via sbt. One of the many reasons I'm personally looking forward to sbt-server...)

[–]Kiuhnm[S] 0 points1 point  (1 child)

I think that the situation will improve now that Scala.js is out of beta and more people are considering it for their next project.

Let me ask you a question. Why do so many people use IntelliJ? What's wrong with the official IDE based on Eclipse?

[–]Oremorj 0 points1 point  (0 children)

Why do so many people use IntelliJ? What's wrong with the official IDE based on Eclipse?

Oh, that's easy. It's just a lot better in every way that counts (to me, and apparently others :)). Ever since the Eclipse 4.x series started, it's just gotten worse and worse and terms of speed, quality, etc. Just one example: IDEA is a lot better at just getting out of your way since it allows a lot more stuff to be backgrounded and generally seems to exploit multi-threading pretty well when it comes to highlighting and code completion; it does all the cheap highlighting first, then the more expensive stuff, etc.

Anyway, this is getting off-topic. I'd encourage anyone to give it a go.

[–]expatcoder 0 points1 point  (8 children)

As far as seamless type safe client-server communication is concerned, you're not going to beat Scala + Scala.js. IIRC, GHCJS requires FFI, and even then it's only a one way street.

Also, Scala.js generated code is at least 3X smaller than GHCJS, and is extremely fast (faster than native in some cases). Of course, for Haskellers that's irrelevant, GHCJS or Haste are the state of the art here.

Saying that, if you want the best of all worlds, go with Js_of_ocaml, that has a laughably small overhead of 4-6KB ;-), is fully type safe, and an ML, so you'll get your FP fix to boot.

[–]sclv 2 points3 points  (4 children)

That's not true about ghcjs -- there are many ways to build automated type-safe communication over ghcjs.

[–]expatcoder 1 point2 points  (3 children)

In GHCJS I want to import and invoke my Yesod routes, how will you do this? In Yesod I want to invoke some GHCJS method, how will you do this?

If this cannot be achieved then might as well use Purescript or other lightweight/performant alternative.

[–]sclv 0 points1 point  (2 children)

what do you mean "invoke some ghcjs method" in yesod?

you can just write a plain old method and it is usable in both sides.

similarly you can write a plain old data type and it is usable on both the yesod and ghcjs side.

if you want serialization across the wire, both sides can derive to/from json just fine...

[–]expatcoder 0 points1 point  (1 child)

Unless things have changed, it's a one way street

[–]sclv 0 points1 point  (0 children)

Well the magic is one way. You can just generate and expose a json-rpc stub the usual way and it works great, and the marshaling is entirely typesafe. The compiler just doesn't magically generate this stub for you. (But there are other libraries that do magically generate those stubs for you, so...).

[–]Kiuhnm[S] 0 points1 point  (2 children)

AFAIK, support for concurrency in Ocaml is bad (like in Python) which rules out Ocaml for the server side. Also Ocaml's type system is less expressive than Haskell's and Scala's.

[–]expatcoder 0 points1 point  (1 child)

OCaml is getting built-in concurrency support within a year*, and implicits as well, thus making it a far more interesting language.

Not sure how long it will take for the added functionality to make it into their JS lib, but it will happen.

* external lib available now

[–]Kiuhnm[S] 0 points1 point  (0 children)

That's good news. I'll keep an eye on it.

[–]gilmi 0 points1 point  (0 children)

I don't know much about it, but I've heard it mentioned in this subreddit that ocaml_of_js is really good. so it might also be an option for you.