1. 34
  1.  

  2. 33

    My programming background for the past five years curiously involves both Scala and Go, so I feel like I can weigh on this.

    I worked in Go for 3-4 years, and I really hope I don’t have to work with it again. The language might be simple and ascetic, but I found its simplicity to be unrefined rather than elegant. Its developers worked hard on making it so simple, but it resulted in a language that is really annoying.

    Scala is a very rich language, which can lead to problems, but this is more of a cultural thing. Nothing stops you from declaring any Scalaz-influenced monadic wankery verboten, something which I’ve enforced in leading Scala teams where I work. So unless your organization keeps its feature checklist in order, you might have funny encounters when moving people across teams and projects. In Go’s defence, this is its singular feat: I can understand any large Go codebase I find on e.g. Github in a matter of minutes.

    When it comes to the main point of the article, I feel like it’s a giant misunderstanding. Sounds like the author benefited more from splitting their monolith into a bunch of microservices, so I doubt the move from Scala to Go had any effect: a Scala monolith will be slow to compile, and it will be slow on plenty of other languages — even Go, though in Go it will be faster than in a lot of languages.

    The poor IDE support is nonsense: IDEA, Eclipse and NetBeans support is top notch for Scala, Ensime lags behind (it’s an Emacs plugin!). Some inane highlighting features exist, sure, but this is a given with a language that allows for custom DSLs.

    Saying “Scala is difficult” and then presenting scalaz as the principal argument is like saying “static typing is difficult because Haskell”. Reductio ad absurdum.

    I fail to see any of the benefits in the conclusions to be relevant.

    • Tiny container sizes. 20MB vs 300MB. That’s just one order of magnitude. Who cares?
    • Low-memory footprint. Since when does this matter in web servers? The JVM is extremely performant and the G1 self-tuning garbage collector is excellent, it may occupy a lot of memory, but in web servers I find performance to be more important than memory footprint.
    • Fast startup times. Since when does this matter in web servers? If you think fault tolerance and restarts, I think this is much easier to manage in the application level (e.g. actors and supervision trees).

    Granted, I wouldn’t write command line tools in Scala (this is where I’d use Go!), but for servers, data analysis and stream processing I’d choose it any day over a number of languages (even Haskell, because of the ecosystem).

    1. 8

      Great detailed reply.

      I worked in Go for 3-4 years, and I really hope I don’t have to work with it again.

      I don’t want to derail the discussion here, but am curious for a bit more about why you don’t like Go. I’m aware of many criticisms of the language, but am always interested to hear the opinions of those who have used it in anger not just those who’ve looked at the language spec and spotted some omissions.

      1. 37

        There were lots of things I liked and lots of things I disliked. Ultimately, there were more of the latter and less of the former.

        Off the top of my head…

        Things I liked:

        • Fast compilation and unit test times. A largeish codebase I worked on with 100k+ SLOC compiled in seconds. I wrote an Emacs plugin for running unit tests and it was easy to develop for.
        • Static binaries with decent C/C++ interop with SWIG.
        • Universal coding styles via gofmt so every codebase looks the same.
        • The structural type system is nice. I could decompose ReaderWriterSubscriber into its constituent parts (so a function that operates on Reader works on that), this is not possible with Java-style inheritance, but is possible in other languages like Rust, Scala, Haskell (due to traits and type classes) and OCaml (with modules).
        • Cross compilation worked surprisingly well.
        • The standard library contained some nice things, like a HTTP server.
        • For command line tools it is still my language of choice.

        Things I did not like:

        • Package management without vendoring was a mess. If you didn’t use it, a simple Github repo rename could have borked your codebase. If you used a custom solution, e.g., dumping package sources into your repo under vendor/ or using git submodules, you risked repo bloat.
        • The type system lacks generics and higher order functions like map. If you wanted generics, your recommended solution was to either use a void pointer (interface{}) or code generation tools (!).
        • Due to the former, you had to write a Sort interface for everything you wanted to sort.
        • Error handling was needlessly verbose and the lack of generics prevented a Option[A] or Either[A, B] type, leaving you with a complicated ad-hoc Either replacement using multiple return values.
        • The verbosity was fixable with command line tools that would automatically insert appropriate return values for functions returning an error type, but they didn’t work half the time.
        • If you cut corners with error handling you ran into the funny situation where your code might have broken and you never knew about it, defer file.Close(), you fix this by checking for the error defer func() { if err := Boom(); err != nil { ... } }, this resulted in code smell. The usage of defer became an anti-pattern because of this.
        • interface{} is just a void pointer and if you wanted do something elegant with it you had to use reflection which was slow.
        • panic never really worked as an exception handler, it just crashed your program in funny ways and implementing fault tolerance like in Erlang using it, which was probably its original intent (?), was impossible.
        • The database/sql plugin was very opinionated and most implementations were slow. It tried to abstract over different dialects that used a specific implementation underneath, but the implementations differed in crucial parts, e.g., parameter interpolation was different between PostgreSQL and SQLite and MySQL.

          So, people did away with it, but this resulted in multiple different SQL implementations for which you couldn’t write universal SQL queries anymore (think local integration tests with SQLite and using Postgres in production), resulting in excess work or in-memory replacements that didn’t exist (compare to H2 in Java land).

        • Parallelism and concurrency were so-and-so. On the surface, green threads (goroutines) were a nice idea, but ultimately I prefer an execution model where you can choose the implementation yourself. Scala futures support custom thread pools so you could control the concurrency model, for Java Pulsar fibers provided a native thread for every fiber. M:N concurrency is hard to reason about and impossible to escape.
        • The GC is still a stop-the-world GC, although improving, it was quick but unpredictable and resulted in pauses. The JVM G1 GC is much more predictable and tuneable, though of course the JVM has 20 years of engineering behind it.
        • The only other thread communication model alternative to CSP, i.e., channels, was mutexes. There is no support for the actor model. Channels sometimes had unpredictable performance and code that used them was prone to race conditions.
        • Little availability of reactive streaming capabilities due to the limitation of the type system or the lack of higher-order functions.
        • No support for immutability or anything that resembles functional programming. You couldn’t create interesting abstractions that pushed side-effects to the edge of your system, where as in Scala or Haskell I can write complex database or IO logic that doesn’t know what the DB/IO system underneath even looks like.
        • Its hash map lacked many things, like getting the set of its keys, and they were verbose.
        • The brouhaha about type aliases and the dumb reason they were needed in the first place: you couldn’t modify an external type, because the structural type system was designed unintuitively around it.
        • It is under the control of Google, not an independent foundation (under which Scala moved officially last year).
        1. 3

          The only other thread communication model alternative to CSP, i.e., channels, was mutexes. There is no support for the actor model.

          The actor model is trivially implemented with goroutines and channels.

          type Actor struct {
              splines map[string]int
              actionc chan func()
              quitc   chan chan struct{}
          }
          
          func (a *Actor) loop() {
              for {
                  select {
                  case f := <-a.actionc:
                      f() // can also model a state machine with retvals here
                  case q := <-a.quitc:
                      close(q)
                      return
                  }
              }
          }
          
          func (a *Actor) Reticulate() error {
              errc := make(chan error)
              a.actionc <- func() {
                  // guaranteed isolation in the function body
                  a.splines["maxis"]++
                  errc <- nil
              }
              return <-errc    
          }
          
          func (a *Actor) Stop() {
              q := make(chan struct{})
              a.quitc <- q
              <-q
          }
          
          1. 2

            Just curious about what things you would like to express in the actor model but can’t do with CSP? I thought they were pretty similar but I haven’t grokked all the details. What is the main difference between the two models?

            I guess Go has shared mutable data structures but by convention only one goroutine is supposed to modify them at any time. Though I think that is more of a Go thing than a CSP thing?

            And it has first class channels which I think is a good thing. I think that Erlang doesn’t have first class channels, but only processes named by a PID.

            Which languages use the actor model? I guess Scala does, and Erlang.

            1. 6

              It’s not that you can’t, but bidirectional communication is much more easier in the actor model. I mean, replying to a message is dead easy: sender() ! "hi" and asking for a reply is just target ? "hello". Channels are blocking by default. The actor model has caveats w.r.t. state and identity, I had an idea how to implement actors in a somewhat purely functional actors in Scala.

              Akka isn’t the end-all of Scala concurrency, though these days I’d rather use some Rx-based solution (Monix, scalaz-streams, fs2, Akka Streams)

              Actors are available for Java (Pulsar), Elixir (via Erlang) and lately Rust.

              1. 1

                Channels are a coordination mechanism among goroutines within an OS process. Channels can be used as part of an implementation of locsl or distributed actors or other N-way communications, but cannot be faulted for not being a total solution to that objective.

              2. 2

                Go tries really hard to not have thread IDs, which makes it hard to do Erlang-style process monitors since there isn’t an explicit thing to monitor.

                1. 1

                  Process monitoring has by far the most value across distributed processes. Goroutines have nothing to do with distributed programs. Code in a goroutines will either return errors as results or will panic. Process monitoring in Go would entail monitoring at the level of the OS process.

                  1. 2

                    That’s not really true. Even within a single address space (the common use case of Erlang), automatic restart/cascading of errors means easier and more robust error handling. The Go equivalent would be if you had a goroutine in charge of handling a database connection and it crashed. A reasonable behavior would be to try to restart the process a few times, and if that fails kill the server that was depending on it. Process monitors mean you can automate this, and neither component needs to worry about its lifetime or its dependents'.

                    1. 1

                      If you want to implement restarting and cascading goroutines, Go simply provides the mechanisms to do so. There’s no reason to make that part of the core libraries. I prefer having the basic mechanisms out of the box and allowing folks to define above that the mechanisms thev determine are appropriaten for their situation. If experience exposes some widely applicable solutions, they can always be added to the core release as desired.

                      1. 1

                        What mechanisms? if you do go Server() there’s no way to tell whether it’s running or crashed. That’s what thread ID’s would provide, except they barely exist and don’t allow that kind of querying.

                        1. 1

                          Use defer to close a channel, unlock a mutex, tell a wait group its done, etc.

                          1. 2

                            For failure notifications you can have something in the called thread, sure. What do you do when you want to kill a thread tree? Example, if the web server thread fails I’d like to restart it along with its DB caching thread. Or I have a connection handler with a watchdog on it that gets killed and restarted if it’s wedged for over a second. How do you send a kill signal relying only on in-band code?

                            1. 3

                              I’ve run into this kind of Lobsters thread too often.

                              You can’t do X. Here’s how to do X. Sure, but you can’t do XY. Here’s how to do XY. Sure, but you can’t do XYZ. Here’s how to do XYZ. Sure, but…

                              So I’ll cut to the chase… there’s no way to do this but using your language and your favorite language mechanism. I concede and will save us both the time of arguing past each other.

                              1. 1

                                The question that started this was “what can actors do that CSP can’t”, so I think it’s an entirely fair point that CSP’s representation of unreliable restartable services is incomplete at best. You really do need a first-class representation of threads as well as channels in order to get everything right, which was the point I was going for.

                                1. 1

                                  Process monitoring is not part of the actor model per se. So it’s no less reasonable for me to argue for CSP based on Go’s sync package.

                                  I TRULY am done with this thread. Happy programming. I mean that sincerely.

          2. 1

            When it comes to the main point of the article, I feel like it’s a giant misunderstanding. Sounds like the author benefited more from splitting their monolith into a bunch of microservices, so I doubt the move from Scala to Go had any effect: a Scala monolith will be slow to compile, and it will be slow on plenty of other languages — even Go, though in Go it will be faster than in a lot of languages.

            This, so much this.

            In the Ruby world, this has also been a common pattern: many companies completely rearchitected their monolith, thus ditching Rails and moving parts to other programming languages in the process, after reaching a breaking point (and a certain point of success).

            I think this is more testament to their ability to adept and make the right calls at the right time then a “we picked the wrong tech back then” thing.

          3. 8

            I’m not a fan of Go, but I’ve found Scala to be a massive disappointment. I had a lot of enthusiasm for it in the early 2010s, but then I encountered Scala codebases written by average/business-grade developers and, umm… found myself very unimpressed. Scala doesn’t prevent them from abusing null and writing VisitorFactory code, and in general it doesn’t correct for the mediocrity that lives within the Java culture.

            It’s not just the long compile speeds. That wouldn’t be a deal breaker with a more modular architecture, but business programming is all about the multi-developer monoliths (read: massive highly-visible projects with names like “Medusa” that get Senior Architects and Software Manager IV’s promoted). With Scala, you have different people programming different dialects with a wide variety of skill levels, and things don’t come together well.

            If you fired all the business-grade programmers and replaced them with genuine, research- or at least industry-grade, engineers, then you might have something. However, most of the research-grade engineers I know are comfortable with Haskell and see no value in being on the JVM.

            These days, my go-to languages are C, Python, and Haskell. C wins for predictable performance and the ability to micromanage memory, and because it doesn’t require a bulky runtime. Haskell wins when you want to get highly correct code within a reasonable time frame. (You can achieve that kind of reliability in C, but it takes longer.) Python’s great for exploratory data science and it’s what a lot of mathematicians these days are using.

            I don’t see the value that Java brings to the table, these days, and hence I’m disappointed in Scala.

            As for Go, I haven’t used it much. I found myself unimpressed when I last tried it out, but that was 5 years ago.

            1. 4

              I think this is Scala’s only real problem: you have to make sure what you described doesn’t happen. The positive side is that this leads to increased code review and discussion about programming practices.

              So, you need some people in your organization that make sure the business-graduates don’t use stupid patterns they learnt in school and that the Haskell-influenced propellerheads don’t go crazy on free monads and category theory. It’s an interesting job, to say the least.

              Haskell, on the other hand, doesn’t really let you write stupid factory-pattern stuff, but it requires great programmers that know what they’re doing. Harder to hire for.

              If executed properly, Scala hits that sweet spot of not-quite-Haskell but not-quite-Java either. Then again, so does Rust!

              1. 6

                Haskell-influenced propellerheads don’t go crazy on free monads and category theory

                I find this comment disheartening.

                You imply Haskell’s abstractive capabilities are irrelevant to deal with common problems that arise in large applications. First, you should realize one of the explicit goals of Haskell is to excel in the development of large applications that change over time. Sound familiar?

                Second, you call out free monads as an example of a problem. Now, I could have a skewed sample, but many business codebases I’ve worked with have problems with heavy coupling of side effects and business logic that grinds maintenance to a halt. Free monads offer a way out of that that is conceptually elegant, amenable to testing, and not terribly difficult to grok once you try it out. Why discredit such a powerful tool?

                it requires great programmers that know what they’re doing. Harder to hire for.

                I’m trying not to parse this as “we can’t hire only junior devs.” The pool is smaller but the average quality is likely higher. Probably don’t need as many developers as you would otherwise.

                1. 4

                  I rip on Free a lot*, but if you have a non-trivial model that requires interleaving of effects and dependence on the result of an effectful computation then it’s pretty hard to beat for cleaning up the mess.

                  • I just think Haskellers and Scalazis resort to it too soon.
                  1. 4

                    Second, you call out free monads as an example of a problem. Now, I could have a skewed sample, but many business codebases I’ve worked with have problems with heavy coupling of side effects and business logic that grinds maintenance to a halt. Free monads offer a way out of that that is conceptually elegant, amenable to testing, and not terribly difficult to grok once you try it out. Why discredit such a powerful tool?

                    Ah, don’t take me wrong, I said “don’t go crazy on free monads”, where I mean that it’s possible to overuse them. It’s entirely possible to use Free monads in a manner that’s friendly and intuitive, c.f. doobie in Scala. In fact, there’s a lot of Free monads in the code base I’m currently working on, and I just introduced a junior dev to the concept today!

                    I’m not here to shit on Haskell, we run a few Haskell apps in production, but we’re probably three guys who know Haskell out of maybe two or three hundred. So the interesting stuff can stay interesting but Scala stuff can go as far as Free monads in elegance for the other developers' sake.

                    That said, Free monads are at the intuitive part of the spectrum, more esoteric although unrelated stuff like profunctors, cofunctors, strengths are very interesting and probably very insightful tools yet completely academical and frankly will probably never be used on a wider scale, tools which are closer to what I was aiming at.

                  2. 2

                    I think this is Scala’s only real problem: you have to make sure what you described doesn’t happen.

                    The problem is that you don’t live in a vacuum. Unless you plan to use no external Scala code, you might need to wade through Java-in-Scala or Haskell-in-Scala code in any case, without an option to change it.

                    1. 3

                      I think this is Scala’s only real problem: you have to make sure what you described doesn’t happen.

                      Fair enough, but here’s the issue: the entire selling point in JVM compatibility is corporate compliance. If you’re a consultant planning to hand off your work and who’ll collect $200+ per hour if there are follow-ups, then that’s fine. But let’s keep in mind that the selling point of Scala over Haskell is something that is at odds with technical excellence: interoperability with the standard, corporate way of doing things: hiring mediocre programmers, slapping junk together in Java, using “Agile Scrum” to micromanage them, and hoping to be promoted away from the time-bomb before the technical debt reaches catastrophic levels and someone loses money or face.

                      the Haskell-influenced propellerheads don’t go crazy on free monads and category theory

                      There’s nothing wrong with those concepts. They don’t work in Scala because Scala is limited. Ed Kmett did a better job of addressing this than I will, so I leave you this link. Now, you might not use free monads in high performance code, but the concept of the free monad has a certain conceptual beauty that helps you understand exactly what computation is… and when you get to the point of designing systems, that matters.

                      Haskell, on the other hand, doesn’t really let you write stupid factory-pattern stuff, but it requires great programmers that know what they’re doing. Harder to hire for.

                      I think that you’re unknowingly re-transmitting corporate indoctrination. Any programmer who deserves to be called that can learn Haskell. It’s not that hard. To me, the “hard to hire” argument (and, yes, non-technical managers love to make that argument) says two things: (1) we don’t invest in our people, and God forbid they learn (!!) on the job, and (2) I’m intimidated by people smarter than me, or just too stingy to be willing to pay them.

                      The sorts of managers who want programmers to be fungible are a cancer and we should drive them out, not enable them.

                      Programming is the sort of thing that should be done right or not at all. If Haskell shuts down the mediocre ticket-jockeys for whom Scrum is designed, then great.

                      1. 2

                        If executed properly, Scala hits that sweet spot of not-quite-Haskell but not-quite-Java either. Then again, so does Rust!

                        No and no. Rust does what it’s s'posed to, but it’s nothing like Haskell. Scala is not in a sweet spot of any sort.

                        1. 4

                          The more I use Scala I actually agree that it’s in a certain kind of sweet spot. Modular architecture is sort-of available using Scala’s interpretation of parts of OO. At its core this is actually pretty nice although the Scala implementation, for purposes of Java compat, is super super crufty.

                          This kind of thing is maybe going to get easier to do in Haskell with Backpack, but I’m not holding my breath.

                          But yeah, Rust is just doing it’s own thing. It kind of wants to be Haskell somedays, but you can’t even say it’s walking a parallel course. Where it’s going there is no map. Maybe ATS?

                          1. 1

                            A sweet spot quite separate of what makes Haskell nice - I can believe that if it didn’t have so much cruft and bad design lurking about. Cf. https://lobste.rs/c/5tlscr

                            Co-opting the ostensible benefits of Haskell for Scala is what I am protesting.

                            1. 1

                              Fair fair fair enough!

                          2. 4

                            You are significantly underrating JVM library compatibility.

                            1. 3

                              These days, there’s very little that you can find in the JVM world that isn’t done better in some other language. The core numeric libraries are written in C and Fortran. If you need mature garbage collection (i.e. not just reference counting) Haskell has that.

                              Interoperating with hundreds of thousands or millions of lines of legacy, corporate Java code is an important category of work, I guess, but I wouldn’t touch that kind of work at a rate below $500 per hour and there aren’t a lot of people paying that… so it’s not on my radar.

                              I do like Clojure for the design of the language itself, but the JVM aspect is incidental as far as I’m concerned. It was a necessary compromise to get it off the ground and, as far as I’m concerned, Rich Hickey did a much better job of defending the language from JVM ickiness than the other mainstream JVM languages did.

                              1. 1

                                That doesn’t have anything to do with PL design sweet spots.

                                1. 1

                                  you didn’t say ‘PL design’ sweet spots. And even if you did, any discussion of PL design without discussion of the ecosystem is, as they say, ah, ‘purely academic’.

                                  1. 1

                                    I wasn’t talking about PL design though, but of a usability perspective. The JVM is an asset when you need to develop enterprise grade software… fortunately.

                                    Rust gives you a lot of functional programming, Scala even more, and Haskell the most (and Idris/PureScript/Agda even more and so on).

                                    1. 5

                                      Sweet spots are sort of the opposite of a consistent gradient and this ain’t the latter.

                                      Please stop co-opting Haskell to push bad tools. Describe how it’s nice on its own merits and the facts of the design.

                                      1. 1

                                        Many of Scala’s selling points - HKT, pattern matching, do-style monadic notation - are things that first saw mainstream exposure in Haskell, or that many programmers will think of as “Haskell things”. Language is a tool for communication, and describing Scala as Haskell-like is a pretty good summary (in terms of conciseness/accuracy - sacrificing some accuracy for conciseness is the nature of a summary) of its advantages.

                                        1. 0

                                          https://www.reddit.com/r/haskell/comments/1pjjy5/odersky_the_trouble_with_types_strange_loop_2013/cd3bgcu/

                                          It’s not a language that hangs well together or does well the things Haskell does well. Having the ability to encode some of the same things Haskell can takes Scala further away from it’s sweet spot. Anything Odersky hasn’t bothered to bless ends up being gnarly.

                                          Further, you’re trying to do increasingly complicated things with a language that doesn’t have a real notion of soundness, a profoundly buggy implementation, and an implementor hostile to your intentions.

                                          Stop co-opting Haskell to push your bad language and its bad implementation.

                                          1. 1

                                            Some of those are real issues (some of which have been addressed since that post was made), sure. But most o them are relatively small edges, and fundamentally the entirety of that list represents a much smaller gap between Haskell and Scala than between Haskell and any other mainstream language - hell, a smaller gap than the gap between HKT and no HKT alone.

                                            Haskell has if anything more soundness issues (half the prelude is partial). I haven’t experienced any implementation bugginess. The language is bigger than Odersky at this point; if there are issues that the official implementation refuses to fix then the typelevel fork will. I’m not trying to co-opt Haskell (and frankly Haskell’s reputation is not one I’d want), I’m trying to communicate about languages in general terms. I don’t know why you’re being so angry and unpleasant.

                                            1. -1

                                              Stop projecting an angry tone where there isn’t one. It’s a dishonest and dirty debate tactic.

                                              I’m asking you to stop co-opting the work of others. That’s all. Either you can do that, or you can’t.

                                              If in future I think you’re doing it, I’ll let you know in the same polite-and-to-the-point wording I’ve used so far. If you think you’re innocent of this, then you have nothing to fear! You still have plenty of fellow Scala users that do it and I will continue to push back on it.

                                            2. 1

                                              The future version of Scala is sound, though it will be some years when this completely compatible. There’s already a compiler available.

                                              I don’t think any serious Scala programmer wants to co-opt Haskell to push a Scala agenda. If anything, those who understand the language and want to push it forward do so because it explicitly isn’t Haskell.

                                              1. 2

                                                I don’t think any serious Scala programmer wants to co-opt Haskell to push a Scala agenda

                                                I see it all the time, so I’m going to disagree here. A common angle is, “Scala gets you the benefits of Haskell, but it’s on the JVM.”

                                                If you sincerely believe this, our priors are too far apart to have a useful conversation. Cheers!

                                                1. 1

                                                  Well yeah, I believe we’ll both agree on which is the superior language, but what I meant is that the serious Scala devs (one Kmett used to be) have, after actually understanding the language, its merits and faults, either moved to Haskell because they were disappointed, or stayed behind because they saw something worth using.

                                                  The “It’s like Haskell on the JVM” claim, while extant, and is fairly rare among professional and experienced Scala developers.

                                                  Those experienced devs, those that develop libraries such as cats, have long since stopped developing them out of a desire to create a Haskell on the JVM. That attempt kind of went badly. It’s no longer about taking feature X from Haskell and trying to shoehorn it into Scala – it might work but the result either looks ugly or is unusable.

                                                  I do know where you’re coming from: some five years ago that movement was in full steam, people were taking and co-opting Haskell things left and right, and it created a damn mess that took several years to resolve.

                                                  Ultimately, the hardcore devs realized Scala isn’t Haskell, it will never be, and it will have to take its own path going forward (see e.g. projects like fs2 and doobie], since aping Haskell leads to an ugly and unusable language.

                                                  The language designers saw this, and understood that for Scala to not die a horrid death under its complexity, they had to come up with a language founded on a new calculus based on dependent object types. Wherever that’ll go I think it will be interesting.

                                                  That said, as a colleague of mine said, with whom I work on Haskell projects, Scala is a language that “has monads in a way our CTO doesn’t laugh at me”.

                              2. 1

                                Haskell’s laziness is, I think, incompatible with having as good a story as Scala on predictable, consistent, reasonable (in the sense of being able to reason about it) performance. All the answers to the space leak problem are kind of ad-hoc “you can usually fix it in practice” which makes me nervous even if it works (and the kind of work where listening to nervous feelings isn’t important is the kind of work where there’s little reason to pick Haskell over Python). The tooling situation in terms of IDEs/profilers/instrumentation/… doesn’t sound like it’s as good as Scala (maybe good versions of these tools exist for Haskell, but if so you don’t hear about them; asking about Haskell IDEs you mostly hear a lot of sour-grapesy “good programmers don’t need IDEs” talk (which I know is wrong, or at the very least not true for my own development style, because there are Scala programmers who say the same kind of thing and I have experience of writing Scala in that kind of environment)). The packaging ecosystem especially sounds like it’s in a lot worse state than the Maven ecosystem (it sounds like Stack maybe gets things right but the wholesale migration to it hasn’t happened yet?). And the fact that Haskell has a much worse compile-to-JS story concerns me, not because I have a pressing need to compile to JS but because it suggests the language internals are in pretty poor shape if it was so much harder to implement for Haskell than it has been for Scala. The same goes for the poor development story on Windows.