
Three Months of Go, from a Haskeller’s perspective (2016) - slikts
https://www.barrucadu.co.uk/posts/etc/2016-08-25-three-months-of-go.html
======
willsewell
I worked with Michael on the same project, after also working with Haskell
previously. On the whole I agree with the pros/cons stated in the article.
Having said that, my conclusion would be a bit different: I would err on the
side of Go for the majority of commercial projects.

The article mentions the impressive worst case pause times of Go's GC. Since
then we have performed some additional benchmarking. The conclusion was: it is
impressive, but there are still a couple of issues that break the sub 1ms
claims. We blogged about this here: [https://making.pusher.com/golangs-real-
time-gc-in-theory-and...](https://making.pusher.com/golangs-real-time-gc-in-
theory-and-practice/). It's hard to guarantee low latency in all cases...

Michael also mentions that there is nothing like ThreadScope, or at least
nothing that's easy to find. The latter is true. There is an impressive
runtime system event visualiser which can be opened with `go tool trace`
[https://golang.org/cmd/trace/](https://golang.org/cmd/trace/). You can see a
screenshot of this in the GC blog post I linked to above. Unfortunately the
only documentation is this Google Doc:
[https://docs.google.com/document/d/1FP5apqzBgr7ahCCgFO-
yoVhk...](https://docs.google.com/document/d/1FP5apqzBgr7ahCCgFO-
yoVhk4YZrNIDNf9RybngBc14/edit) which is tricky to find, and could be more in-
depth.

I'm in the middle of writing a blog post on how to use this too. Watch out for
it on our engineering blog in the next month or two.
[https://making.pusher.com/](https://making.pusher.com/)

------
jwdunne
It is, I think, going to be very difficult to enjoy writing code in a less
powerful language when you are exposed to languages that hold awesome power.

In fact, this has been the basis for much writing on Lisp too. Paul Graham has
written entire essays along the same lines.

If you work in a job that forces the use of a less powerful language than what
you've been exposed to, you can, I think, go through a sort of depression. You
simply long to use the tools that you know hold much more power yet must
resign yourself to the tools you have.

You can overcome the problem by being present in your work. The language might
be ugly. It might be totally underpowered with limited means of abstraction
and a type system that snmacks you and, sometimes, your client over the head.
What you can do is, despite that, commit to writing great software with the
tools you have. Commit to improving your work. Perhaps expand the ecosystem
with tools borne of insights from your adventures with high-powered tools.

You will have a much more enjoyable time in most languages this way. Perhaps
except MUMPS but there might be hope.

~~~
TheCondor
I don't know how to ask this without it sounding offensive, and I don't intend
it that way. But do these "hardcore" haskellers enjoy writing programs at all?
Like are there any well known open source apps that people actually use
written in Haskell? There are tons of hobbiests and it has a following but
what are the examples of its greatness?

I ask as an old SML guy, I like the math theory, I like the promise of better,
more accurate and reliable software, I think you can do some beautiful things
with algebraic types but I've been dumbfounded by the lack of great examples
out there. Ada suffered/suffers the same fate, it has this "academic" pedigree
for robustness but not many examples that you can get your hands on. so much
expressiveness that doesn't seem to result in much expression.

~~~
crimsonalucard
Haskell is actually less expressive. It is a functional abstraction on top of
what is essentially a procedural machine and with all abstractions placed on
top of lower layers you can only lose functionality as you go up rather than
gain. You could say assembly language is the most expressive language out
there.

The great thing about Haskell and other functional programming languages is
that the functional style forces the program to be created in a form that is
modular and elegant. Programs become modular and composable and re-composable
in the functional world because the programmer has No Choice but to build his
programs in an elegant way. It's hard to explain this to a typical programmer
who hasn't dived deep into functional programming but code reuse, modularity
and elegance are significantly higher in functional programming languages than
in procedural.

This elegance, beauty and forced organization comes at a high cost though. And
the cost is thinking in a way that is outside the normal paradigm of what
humans are use to. I know a lot of haskellers think that humans can be taught
to think in both ways equally, I disagree with them and believe that it is far
Easier for a human to think about an algorithm procedurally than it is for him
to think about it functionally.

If you have several tasks to execute, what is your first thought on how to
plan out those tasks? A task list (aka list of functions) or a series of
composed tasks placed in a single sentence (aka expression)? The answer is
obvious: humans think about the list first because procedural programming
comes more naturally.

This I believe is the main reason why Haskell or lisps haven't taken over the
programming world. Functional programming is just HARDER. It takes me 10 times
longer to hack out a simple program in haskell than it does in python because
haskell doesn't allow you to 'hack' together a program. In haskell the
application has to be an elegant diamond or the thing won't even compile!
Python allows me to hack something together quickly which is both a good and a
bad thing because as we all know hacking together software is quick but easily
leads to unmaintainable software.

~~~
ngrilly
I don't understand the downvote. The main argument looks valid:

> If you have several tasks to execute, what is your first thought on how to
> plan out those tasks? A task list (aka list of functions) or a series of
> composed tasks placed in a single sentence (aka expression)? The answer is
> obvious: humans think about the list first because procedural programming
> comes more naturally. This I believe is the main reason why Haskell or lisps
> haven't taken over the programming world.

~~~
willtim
It's overly simplistic. For example, Haskell's do notation allows asynchronous
programming in a linear "task list" (to use your phrase). Yet most popular
imperative programming languages do not; one must instead use callbacks.

As to whether programming with expressions is fundamentally harder, I'm not so
sure. Since Fortran, most languages have supported arithmetic expressions over
primitive numeric types, since they are certainly _not_ easier with an
imperative approach (MOV, MOV, ADD, PUSH). Haskell allows one to easily take
this further using arbitrary objects and algebras, for example, expressions
with drawing primitives, parsing grammars, financial contracts etc. With a
small amount of syntactic sugar, you can even make expressions that look
exactly like imperative programming (Haskell's do notation).

~~~
willtim
Forgot to mention that I didn't downvote either, despite disagreeing with much
of the post.

------
jonnybgood
> Go is just too different to how I think: when I approach a programming
> problem, I first think about the types and abstractions that will be useful;
> I think about statically enforcing behaviour

I see statements like this a lot from Haskellers and I think its overstated.
Anecdotally, after going from Python to spending 3-4 years in Haskell then
going back to a dynamic language (Elixir) I've come to the conclusion that how
you think when programming is very much a learned trait that works for that
language. It's neither good or bad, but it's educational nonetheless. Haskell
and other languages like it forces you to have a very unique mindset that can
overpower previously learned languages not like it. And it's in no way
permanent.

After I stopped using Haskell I was like "ugh, I need types! wth!". I wanted
to go back to Haskell only out of familiarity, but as I continued after a
short while I wasn't even thinking like that anymore. The thought rarely
occurred. I stopped thinking in Haskell and started thinking in Elixir.

~~~
bad_user
I cannot speak for Elixir, but coming from the Erlang world, I'm sure it's a
fine language that has sane defaults, much like Clojure.

However I switched from Python to Scala and besides the performance issues and
the poor handling of async I/O that I had with Python, by far the biggest
problem with Python was all the _insecurity_ while developing with it. It
drove me insane, because we had a production system that always had problems
due to how poorly Python's ecosystem treats errors.

Just to give an example, at that time we were using BeautifulSoup to do HTML
parsing, a library resembling JQuery, except that BeautifulSoup can return
nulls all over the place and no matter how defensive I got in my coding, null
pointer exceptions still happened. And what was the solution for async I/O in
Python? Monkey patching the socket module by means of Gevent or Eventlet of
course, which didn't work for native clients (e.g. MySQL's) and if this wasn't
problematic enough, you had to _guess_ what worked or not and when. The worst
kind of magic possible.

When I switched to Scala, all of these problems vanished. This isn't about
having tests either, because tests only test for the behavior you can foresee,
unless you do property-based testing with auto-generated random data and in
this regard static languages like Scala and Haskell also rule due to the
availability of QuickCheck / ScalaCheck.

You see, my Python codebase got really bad because of fear of refactoring.
Yes, even with plenty of tests and good code coverage. Because actually the
tests themselves became a barrier for refactoring, because in a language like
Python there is no such thing as information hiding and coupled with dynamic
typing, it means that your tests end up tightly coupled with implementation
details, will break on correct refactoring and will be hard to fix.

Nowadays when I'm doing refactoring with Scala, most of the time it simply
works as soon as the compiler is happy. Some people bitch and moan about that
compiler being kind of slow and it is, but the things that it can prove about
your code would require specialized and expensive tools for other languages
and that wouldn't do such a good job.

Going back to dynamic languages, there are also languages like Clojure, which
get by with _sane defaults_. For example in practice Clojure doesn't do OOP-
style dynamic dispatching most of the time and functions are usually multi-
variadic and capable of handling nil values gracefully. This is not enforced
by the language, being simply a hygienic rule accepted by the community.
However, relying on such conventions requires (a) capable developers that (b)
agree on what the best practices should be.

And the issue that people miss when thinking of the merits of such languages
is that _smaller communities are always homogeneous_. So when giving as
example a language like Elixir, if it hasn't drove you insane yet, well, you
have to take into account that Elixir might not be popular enough.

So basically I prefer strong static typing because I'm not smart enough or
wise enough to seek and follow best practices as often as I'd like and because
I don't have much faith that other people in the community can do that either,
especially after that community grows. The biggest irony imo is that Python is
right now the anti-thesis of TOOWTDI.

~~~
rimliu

      > because in a language like Python there is no such thing as
      > information hiding and coupled with dynamic typing, it
      > means that your tests end up tightly coupled with
      > implementation details, will break on correct refactoring
      > and will be hard to fix.
    

Would you mind to provide more details about this point? I thought dynamic
languages make testing easier, because you don't care about the type of the
object as long as it works with the same API (if it quacks…). This also
supposedly makes it way easier to mock objects. Now there you are basically
claiming (unless I misunderstand your claims) the opposite.

~~~
46Bit
"Dynamic languages make testing easier," paints a very broad brush. They have
some very nice benefits, but also a lot of edgecases.

* An argument might be an int when you expected a float. This can be addressed by casting things with `float()` in every entrypoint, but it's more defensive to require a float and error out otherwise. Either way, problems only appear at runtime. * An object might be null and this only gets picked up at runtime - using Rust it's been very nice to have to explicitly say when things can be null.

I've found it can feel like luck when a complex Python program works correctly
for real-world input, but it's also very powerful at getting something done.
Tradeoffs.

~~~
btschaegg
> An object might be null and this only gets picked up at runtime - using Rust
> it's been very nice to have to explicitly say when things can be null.

This point actually frustrates me greatly about C# 7. At some point, there was
talk about non-nullable references being introduced into the language, which
has been put on hold for at least another version. Personally, I think that
feature should have been in the language since version 1. Every runtime error
due to a null reference is one too many.

~~~
DenisM
I have thought about creating a template struct with a single member that
blows up if you try to insert null. Something like this:

    
    
      public struct NotNull<T>
      {
        private readonly T val;
        public T Value { 
          get { return val; } 
        }
        public NotNull(T v)
        {
            if (v==null) 
              throw new Exception(); 
            val = v;
        }
      }
    

However you can still create a class FOO with a member NotNull<T> xxx and xxx
may be entirely uninitialized. It can be then passed from one method to
another until you try to read it, so it basically does not give any
guarantees.

I thinks this is why they pulled non-nullable types from C# - they couldn't
figure out what to do in this case. If I were them I would force the
constructor of FOO to blow up on exit if xxx is not populated. That would help
a little bit. Although it still causes problems if a method is invoked from
the constructor.

So yeah, it's a tough problem. Maybe they could add a check when a field of
type NotNull<T> is read to throw an exception? That way you're still possibly
in trouble when reading a field, but at least you can be confident that if you
receive a method parameter NotNull<T> you know it's not null.

~~~
btschaegg
I also thought about solutions like this for a while, but frankly, every
option sounds like the attempt to fix a leaking dam using duct tape.

Things like this have to be implemented properly. The problem is that this
ties into the core architecture of the platform, not only the language -
references are basically the most important implicit primitive there is in the
CLR (implicit because not even the IL handles them like the other datatypes).

I'm not very informed on the subject, but I suspect that without a proper way
to declare locals and members non-nullable in the CLR, the matter would get
rather complicated - there'd be no possibility to communicate the requirement
through method signatures, for example. And since you could call pretty much
any C# method from other languages, I'd expect various problems there.

Of course, one option would be to only handle the initialization and
assignment checks in the C# compiler (I guess that would be much easier) and
simply generate conditional ArgumentNullExceptions in every method, but I
suspect that this would be a problem for performance reasons.

------
jrobn
I started out liking Go. It looked like a fairly pragmatic language. As I got
deeper into my evaluation project (simple api stuff) it felt more and more
like cutting wood with a dull saw.

I started out liking Haskell too! But has I moved along with my small
evaluation api project it felt more and more like I was trying to cut wood
with gyroscopic laser saw. It worked but it was a lot of fan fair for sawing
some wood.

Picked up erlang/elixir. Looked pretty decent. Felt like cutting wood with a
Japanese pull saw, so I had to use the vise clamps that came with it. It cut
some fucking wood.

~ Ron Swanson out.

~~~
Buttons840
My impression of Elixir and Erlang are that they are the only dynamic
languages I'm aware of that seem to have dynamic typing for solid technical
reasons. Many languages are dynamic just for user experience reasons. But the
way the BEAM VM handles hot code swapping, concurrency, and memory management,
etc, required using a dynamic language. (As far as I'm aware?)

~~~
jrobn
I think it's because of the built-in nature of message passing in the
language. It's just easier to send around messages to processes. Hot code
swapping would be possible with other JITed languages (BEAM isn't a JIT).

Also since erlang has excellent pattern matching (even on binary data!) and a
supervisor system (OTP) errors are easy to recover from. Erlang takes a very
pragmatic approach of building tools that deal with errors by recovering from
them instead of trying to exhaustively trying to prevent them.

------
demarq
I hate to sound like the rust evangelist strike force... I really do. But your
complaints are exactly what it would solve... Sigh I hate to say this I really
do. But here goes...

So have you checked out rust?

~~~
dualogy
How robust/mature is it as of yet? More importantly, how are compile speeds
and how much of a priority are they to the compiler maintainers? I too find it
quite promising in terms of "a language aiming for the benefits of Go with the
expressiveness and added easier correctness of FP".

But "promising" doesn't mean I'd replace the few use-cases where Go currently
shines for me (wouldn't recommend it for any-and-all development at all, but
there are select cases where I currently absolutely wouldn't use anything
else) as these are those few programs where I really want to write (and later,
read) exactly step-by-step "almost machine instructions" and where the only
"expressiveness" needed is already fully afforded by Go and quite well at
that. Dev-related mostly bulk-file-processing-based custom tooling (not bad to
fire off sizable amounts of automatic background transformations from one
weird format to another on file-system events etc.) .... filters through which
to pipe vast/continuous data streams with just-some-processing over it ....
providing out-of-process certain "low-level, must be lightning fast" tasks and
logic with IPC for a higher-level codebase .... it's a great tool for such
cases, especially given how simple the syntax is. Ie. the basics are grasped
very easily very quickly and you don't have to recall "its pattern matching
syntax and quirks, its generics syntax and quirks, its etc etc". =) I'm
perplexed when teams choose to express their entire domain model or startup in
Go, however.. fair game, maybe I'm missing something there

~~~
steveklabnik
> robust/mature

Needs more context. It's more mature for some things than others, like many
young languages.

> how are compile times

Not Go, for sure, but not the worst either.

> how much of a priority are they

Getting them down is a high priority, but has taken some time to make a dent
in. The last few releases have all posted speed ups, and "cargo check" in the
last release helps. Incremental recompilation is coming, you can try its
initial implementation on nightly today. There's a lot more to do, but users
really want improvements, so it is and will continue to be actively worked on.

~~~
dualogy
> Incremental recompilation is coming

Good to hear, when that is in place compile times matter a whole lot less

------
shadowmint
I don't think anything in the 'The Bad' is unfair, and they're certainly not
written from a position of ignorance.

Those are things that suck about go; it's not specifically that they suck
about go when compared to haskell; they just generally suck (particularly the
type system stuff).

However, I don't think that the situation is _so bad_ I would go as far as to
say, "Other than that, I will probably never choose to use Go for anything
ever again..."

I maintain that while go might not give smart programmers the flexibility to
express their FP dreams, it has a grungy practicality both for developing and
maintaining code that is quite effective.

Introducing go and building applications with it in a team is easy because its
quick to pick up for the whole team, regardless of background, its simple to
use and its (relatively) difficult to shoot yourself in the foot in terms of
distributing binaries or developing applications that run at modest scale.

When gogland (the IDE by jetbrains) comes out of EAP, it'll even have a
modestly good professional IDE with integrated debugger (no atom, you don't
count when your debugger never works on any platform).

...but hey, if you don't like it, don't use it.

Haskell is pretty great too.

~~~
pjmlp
The thing with Go, is that it is disappointing what Google is capable of in
terms of language design versus what Apple and Microsoft have done in this
field.

Sure there were languages with such type systems before, and we managed to
deliver our work with them.

However I don't want to work in 2017 as I used to work in the mid-90's, when
templates were an experimental feature in C++, or the only MLs we knew were
Caml Light, Miranda and SML.

The world has moved on.

~~~
dualogy
> is that it is disappointing what Google is capable of

Man, how long will this meme survive? Go only initially _originated_ with some
Google developers, it's not in any way "Google's answer to Apple's and
Microsoft's strategically-important and accordingly-subsidized-and-
evangelized-and-invested-in languages". Just picture a handful of (previously
"accomplished" in the field, as it turns out though) guys thinking "this
company has a wide mess of Python etc scripts that should really be C
programs, except for the problems this would pose"..

~~~
pjmlp
Those developers are being paid by Google and their actions within this
context relate to the public image of their employer.

If Google wouldn't agree with their actions, or did not pay to increase the
team size, they would be developing the language outside Google walls.

~~~
geodel
You may disagree but Google relationship with Go looks lot more distant as
compared to C#-MS, Java-Oracle, Swift-Apple. Here Dart-Google looks more
appropriate. Those Dart people always keep telling us about Adword's usage of
it. Google organizes Dart's conferences whereas for GopherCon doesn't even
have Google as sponsor.

Go looks far more independent from Google in branding, sponsorship and
references from official Google products.

~~~
gbersac
That being said Go is one of the four recomended language in google : java,
c++, python and go.

------
joaodlf
I feel like some of the criticism is unwarranted, specifically:

> The tooling is bad

I feel like the tooling is really impressive, considering the age of the
language. Remember that Haskell is something like 25+ years old. Go has done
quite a bit in short time - I can only hope it will get better too.

> Zero values are almost never what you want

I've always felt the defaults to be spot on. Anyway, it's my responsibility to
initialise these values, even on struct fields.

> A culture of “backwards compatibility at all costs”

I agree the current (package management) landscape is dire, but this should
change, hopefully this year, with godep. As it is now, I have found success
using glide for dependency management, so that's what I would recommend for
now.

Apart from that, I can agree on a lot of things - I'm specifically annoyed by
the whole generics thing, the way I interpret the people involved with the
project is "it would be nice to have, but the implementation is awkward, so we
won't admit to it being nice to have".

~~~
AsyncAwait
> Remember that Haskell is something like 25+ years old.

Yet, I'd argue that tooling is still one of the worst aspects of the language.
The whole cabal/stack thing is a mess.

~~~
pjmlp
Yet, at least we can use proper versions instead of Git urls that are exposed
in source code.

~~~
XorNot
And yet I can be up and running and compiling with Go faster then Haskell
every time, ready to ship production binaries if I want.

With Haskell the process for me has repeatedly been: "okay I'm going to follow
this tutorial...okay I need to install it...okay cabal is complaining about
versions or exceptions....okay let's try stack....okay this example needs some
includes...okay I don't have quite the right ver..."

Then 4 hours later I remember that I can't deploy any of this to my servers,
give up, and go back to waiting for someone to make a sane "get started"
bundle for an FP language.

Haskell's package management might exist - but it sucks, and I'll take go
get/govendor over pretty much anything currently out there.

~~~
eptcyka
>And yet I can be up and running and compiling with Go faster then Haskell
every time, ready to ship production binaries if I want.

You can. Today. But leave that code in a repo for a month, and it will stop
compiling, because some of your dependencies got updated.

~~~
XorNot
Not any of my code (or any of the projects I know) - the solution of the
vendor/ is not "smart" but it's simple and comprehensible. My dependencies are
locked and explicit - if you can clone my repository, then you also get the
dependencies. And no, I really don't care about wasted disk space measured in
megabytes.

------
twblalock
This article's comments on code generation and generics are a good exposition
of what I don't like about Go: it seems internally inconsistent, as though
there is one set of features for the Go development team, and a lesser set for
everyone else.

The nice thing about Haskell and the Lisps is that they are consistently the
same thing all the way down through every layer of abstraction, even at the
bottom. There is no point where you reach the "magic" or "forbidden" layer
where the paradigm changes and it turns into a different language.

The problem with Go is that the code we programmers get to write feels like a
DSL on top of the "real" Go, which uses constructs and "magic" we aren't
allowed to take advantage of.

------
PaulRobinson
TL;DR: "Go isn't like Haskell, and that means it's not as good"

I get that we all have favourite languages, but it is not amazingly helpful to
try and compare them like this, for me. I'm sure if you're a Haskeller and
you're eyeing up Go, being forewarned might be helpful, but here's another
idea:

Don't compare. Just use. Take it at face value. Figure out what becomes easy,
what becomes hard.

I came at Go from 10+ years of professional Ruby development, and it was a
tough punch to the stomach at times. I still think in Ruby more often than I
think in Go. But I know the two aren't really comparable for most things.

~~~
icebraining
I don't understand. How can they not be comparable? They're the same type of
tool, built with the same goal (writing any kind of software). In fact, Go
itself was born because its creators felt the current languages weren't good
at handling the current computing environment - comparisons with other
languages are the at core of its existence. Finally, why even choose Go if
it's not because it has some comparative advantage? Might as well stick with
what we already know.

~~~
cube2222
They're not the same type of tool. Go is mainly aimed at distributed computing
evironments and infrastructural tools. I really don't see a sensible
Consul/Kubernetes/Docker alternative being written in Haskell.

~~~
dalailambda
I don't see why not, Haskell has green threads, channels, and everything that
Go has. The only argument I can see made is that the laziness and current GC
implementation aren't suited, and even then, those problems can be solved with
strictness pragmas, and a different GC respectively.

------
bogomipz
The author states:

>"Strict evaluation is typically better for performance than lazy evaluation
(thunks cause allocation, so you’re gambling that the computation saved
offsets the memory cost), but it does make things less composable. "

Can anyone tell me what a "thunk" is in this context and also why it causes
performance problems? The article linked to in the sentence results in a 404.

~~~
mrkgnao
A thunk is an unevaluated value. Better, it's an unevaluated piece of code
that returns a value when it's required.

For instance, you can write

    
    
        x = [1..]
    

which gives you a list of all the positive integers. Because of laziness
(which thunking enables), this line runs just fine. The compiler allocates a
thunk for x, saying "okay, I know what x is now". But x is never fully
evaluated (because we don't really have enough memory!): it's only evaluated
as far as needed. Indeed, typing

    
    
        head x -- this is 1
    

makes the interpreter print the first element of the list. The rest is still
in a thunk. In memory, we have something like

    
    
         [1,<unevaluated thunk>]
    

Now you can try doing

    
    
        head (tail x) -- this is 2
    

which evaluates the list only as far as the second element. Right now, in
memory, the list looks something like

    
    
         [1,2,<unevaluated thunk>]
    

You can do similar things with basically any other datatype, enabling cool
stuff like [1].

However, having to evaluate (or "force") thunks repeatedly in tight loops can
obviously degrade performance: printing a Haskell list like [1..10] requires
you to evaluate the first element, print it, then force the next thunk to
print the 2, and so on. Comparing this to the equivalent in basically any
other (strict) language, we see that a lot of indirection is removed, because
the endless wrapping/unwrapping is replaced with a simple linked list of 10
elements. (I'm sure GHC is smart enough to optimize the thunking away in this
toy case sufficiently.)

One might also say that a thunk is a "promise" (I'm not familiar with the JS
concept of the same name, which I think is related to async things instead) to
give you a certain value by calculating it only when you need it (if you do at
all: a thunk stays unevaluated when you're done running the program, it's GC'd
away).

[1]: [http://jelv.is/blog/Lazy-Dynamic-Programming/](http://jelv.is/blog/Lazy-
Dynamic-Programming/)

~~~
bogomipz
Thanks for the great explanations. Cheers.

------
krylon
I liked this conclusion: "Go is just too different to how I think"

It is in a way a mirror image of my experience with Go: It is not so much that
Go is a great language, it has its fair share of flaws, _but_ it is quite
compatible with the way I think.

------
amelius
> GHC’s garbage collector is designed for throughput, not latency. It is a
> generational copying collector, which means that pause times are
> proportional to the amount of live data in the heap. To make matters worse,
> it’s also stop-the-world.

This is pretty much unacceptable in today's world of low-latency (web) apps.

How active is GHC's development?

Would it be possible to _efficiently_ run Haskell using Go's runtime
environment, i.e. by changing the compiler backend?

~~~
thesz
If you have not too much data in the heap, you are safe. Even if you have a
lot of data there, you most probably fine too.

As an example, see here: [https://bazqux.com/](https://bazqux.com/) and the
discussion is here:
[https://news.ycombinator.com/item?id=5961570](https://news.ycombinator.com/item?id=5961570)

He was able to survive unexpected slashdot effect from being on the front page
of Hacker news without even noticing it. He told me he went up one evening and
found that there were tens of thousands of new users actively trying his site.
So he added a couple of servers and went to sleep.

GHC development is very active.

And the answer to your last question is No.

~~~
amelius
Okay, but surviving a Slashdot effect is different from having a low-latency
server of course :)

~~~
thesz
He didn't tell me that anyone complained about delays, etc.

I think delays weren't that noticeable then.

------
bboreham
> There is no way to specify a version [of an imported package]

You can do this in your version-control system (e.g. git), via a process
called "vendoring". It's ugly but, using one of the popular tools, quite
workable.

~~~
dualogy
> It's ugly

What do you find ugly about it?

~~~
kuschku
You don’t properly separate and deduplicate dependencies, you can end up with
legal issues (if you ever decide to redistribute your source), etc.

One of the few dependency systems I’ve seen that work well is Gradle with
Maven dependencies, using Java 9’s versioned modules.

Proper versioning, proper dependencies, etc.

------
solidsnack9000
Pulling no punches:

 _Other than that, I will probably never choose to use Go for anything ever
again, unless I’m being paid for it. Go is just too different to how I think:
when I approach a programming problem, I first think about the types and
abstractions that will be useful; I think about statically enforcing
behaviour; and I don’t worry about the cost of intermediary data structures,
because that price is almost never paid in full._

Wow.

~~~
solidsnack9000
The cost profile for data structures is different in Go, though, since it
tries to stack allocate very aggressively. GHC, like Java and many other
classical GC'd languages, tends toward heap allocation.

------
SkyMarshal
Good writeup, but not an unexpected conclusion. I'd be very interested to see
a similar writeup by a Haskeller on Rust, since the two are closer in some
aspects (static enforcement of behavior, strong typing, well designed
concurrency), but different in other key ones (strict vs lazy, GC vs manual,
etc).

------
daxfohl
Haskell always makes me sad. In real-world apps you always need hacks. I do
anyway. In an imperative language I can be proud when my code only has a
couple hacks in it. With Haskell I just end up feeling nasty about my code if
there's even one hack there, and it makes me like coding less. (For toy apps
with no deadline Haskell is great; the above regards Haskell-at-work, as a
freelancer).

~~~
quchen
For me it’s quite the opposite: Haskell allows me to have local hacky sections
that I can then hide in a module that exposes a safe API. Since refactoring is
fairly easy with compiler assistance, I don’t even have to break up my
100-line-long work-in-progress algorithm with temporary names until it works –
and once I have a working solution, converting it to something readable is
mostly manually extracting definitions and giving them useful names.

~~~
daxfohl
That's nice. I haven't used it enough in a hacky way to come up with a list of
good hacking patterns. Like I said, I always feel dirty, like I may as well be
writing C, and then go do something else. Someone needs to write a book "
_REAL_ Real-World Haskell", with effective patterns for that kind of thing.

------
Thaxll
Well the fact that pretty much no one uses Haskell anywhere should give you
some hints about the language iteself.

------
j2kun
> But Go does have generics, for the built-in types. Arrays, channels, maps,
> and slices all have generic type parameters.

Doesn't this mean you could implement a generic tree type if you fix the
underlying data structure to be an array/map? (Not a go programmer yet, but
honestly curious)

~~~
edmccard
>Doesn't this mean you could implement a generic tree type if you fix the
underlying data structure to be an array/map?

Nope. There are only a few functions that accept type parameters, and they
must be called with concrete types, and they only work with certain aggregate
types. For example, "make" can only be used to create slices, maps or
channels, so you could create a slice of 10 bytes with "make([]bytes, 10)" but
you cannot write "make(T)" or even "make([]T, 10)" where T is a type variable,
and you also can't do "make(Tree)" where Tree is, e.g, some struct type.

~~~
woah
I think it's better to not even think of them as "generic functions". Think of
them as language keywords which happen to have the syntax of functions.

------
dorfsmay
I'll argue that Python PEP 8 was probably the precursor to gofmt.

------
pmarreck
TL;DR:

> _I will probably never choose to use Go for anything ever again_

------
luigi23
Offtop: what kind of static website generator did he use? Looks clean, looking
for something similar for my usage.

~~~
niel
The author's site appears to be built using Hakyll
[https://jaspervdj.be/hakyll/](https://jaspervdj.be/hakyll/), which is a
Haskell static site generator. You can find the source for this particular
site on Github:
[https://github.com/barrucadu/barrucadu.co.uk](https://github.com/barrucadu/barrucadu.co.uk)

The "clean look" you refer to is mostly thanks to custom CSS though - nothing
specifically related to Hakyll.

If you're thinking about building a similarly- _styled_ blog or personal site,
you could start by studying the styles this author used on their site:
[https://github.com/barrucadu/barrucadu.co.uk/tree/master/css](https://github.com/barrucadu/barrucadu.co.uk/tree/master/css)

------
gothrowaway
When I look at a programming language, I look at the community and how it gets
stuff done and projects that are noteworthy.

Something about Haskell strikes me as different. Despite the buzz about it, I
don't see many projects for it other than shellcheck, pandoc and xmonad, and
for two of those, there's better solutions around (sphinx, awesome/i3).

The other thing is the general flow I've see with Haskell programmers, many
really tie down their identity do it. They see programming as a crossword
puzzle for them to solve in short term, not as something other programmers
have to read later on. They're not very empathetic to the idea the runways
dwindling and you have to ship sooner rather than later.

In addition, I found that the Scala / Haskell developers I knew took golang to
be quite the nuisance. They find gophers pesky. I think the reason why is
years of Haskell teaches them to overengineer and complicate things
needlessly. It's frustrating because they're not aware of it themselves and
take offense, even blame you when you point it out to them.

Maybe I've just been unlucky. In 10 years, I've never had people who
consistently failed to ship, been mean and arrogant as scala / haskell
programmers. They take the slight criticism as an assault on their identity.

~~~
59nadir
> Despite the buzz about it, I don't see many projects for it other than
> shellcheck, pandoc and xmonad, and for two of those, there's better
> solutions around (sphinx, awesome/i3)

I tried awesome for two weeks and had one crash. I've run XMonad for 5+ years
and had no crashes. Just because they are supposed to accomplish the same
things does not mean that they're equal. One is better and it's because of the
choice of language.

It's very hard to take your post seriously when you include something like
this in it and you don't bother to qualify it even in the slightest.

~~~
gothrowaway
> One is better and it's because of the choice of language. > It's very hard
> to take your post seriously when you include something like this in it and
> you don't bother to qualify it even in the slightest.

I looked in your history and yup, you are partial to Haskell. Why do you feel
a need to immediately judge. Why did you say "hard to take seriously". Why
didn't you just ask politely for more details? In my opinion, you already had
your mind made up. Just like the blog poster did.

> I tried awesome for two weeks and had one crash. I've run XMonad for 5+
> years and had no crashes.

That's your personal anecdote. There's no evidence that the language could
have prevented the crash.

And that doesn't make the window manager "better", which is subjective. What
are more people using? Awesome and i3. Primarily because they don't want to
deal with Haskell when they could be doing lua or a simple config.

~~~
59nadir
> I looked in your history and yup, you are partial to Haskell.

It's convenient that you have no post history to go through, since you decided
that the nonsense you're posting shouldn't be tied to your real account.

Your bias is astounding, yet you go for the "your mind was already made up"
card. I like Haskell but by no means am I tied to any single language and I'm
not the one making posts about how all the users of a language seem to have
undesirable traits.

Even better, you then criticize using "personal anecdotes", when that's
exactly what you did in order to condemn the users of two languages. You half-
dampen it by saying "Maybe I'm just unlucky", but the entire point of your
post is "these two communities suck".

> That's your personal anecdote. There's no evidence that the language could
> have prevented the crash.

Any ML-family compiler will catch more crap at compile time than any C
compiler. Adding lua on top will not solve any of that. None of that is
opinion. It's just how the languages are designed and how they use types.
Adding automatic memory management to that makes the gap even wider and in
short, that stops the vast majority of crashes that you can get.

C + lua is great for lots of things, but everything is a tradeoff and here the
tradeoff is that you're very likely to get crashes. Good intentions alone
can't prevent segfaults and most C software is proof of that.

~~~
gothrowaway
If it were node.js, I highly doubt I'd have a person coming out of the
woodwork with cleverly placed quotes as if it's a legal threat.

Then blaming me for being biased as if you don't already have a conclusion
derived. This is the behavior I experienced - to me, this feels like
projection and trying to bully me into silencing what I truly witnessed. It
really bothers me and makes me uncomfortable.

I'm just stating my experiences. You wanna know why I use a throwaway? Because
people bully and bludgeon anyone who doesn't praise Haskell and / or Scala.
And it's been unique to those language communities.

At the end of the day, your reaction is predictable. I'm not reading too
deeply into what you say because, like my prior experiences, I think you have
your mind up, and in spite or proof given, you're going to be on the defense /
offense.

> Any ML-family compiler will catch more crap at compile time than any C
> compiler...

None of these things about language mattered since awesome and i3 had language
as an _afterthought_ and focused on experience. xmonad literally has haskell
mentioned as a feature, the token battlestation pic (which is pretty cool)
even has a haskell book next to it. Xmonad even uses haskell for the
configuration of it.

Look, not trying to take a jab at hobbyists. It's just I'm saying, in my
experience, I found Haskell and scala "hobbyists" to be quite mean and it hurt
my feelings alot, especially when I dropped, far more politely than when they
ever spoke to me, the news they're not focused on business goals and work
product and just refactoring stuff over and over. They kind of failed at
bringing product vision to light, even basic things like defining requirements
felt beneath them. Again, maybe I've just been unlucky.

~~~
nv-vn
>You're proving my point. If it were node.js, I highly doubt I'd have a person
coming out of the woodwork with cleverly placed quotes as if it's a legal
threat.

The irony is that you came out to defend Go from any sort of criticism without
any direct argument as to why Haskell is bad. Your post talks about the people
who use it and criticizes them for criticizing other programmers, yet that
reflects perfectly on what you are doing. And yes, I am also defending Haskell
when I see your comment. I'm sure Node.js programmers would defend Node.js.
Programmers care about their language choice as much as they care about their
text editor/IDE choice, and it's something that we all love to argue about.

>At the end of the day, your reaction is predictable. I'm not reading too
deeply into what you say because, like my prior experiences, I think you have
your mind up, and in spite or proof given, you're going to be on the defense /
offense.

So you haven't made up your mind already by criticizing Haskell before even
evaluating it as a language? It's not making up your mind on it when you based
all your judgements from personal anecdotes of Haskell and Scala programmers
you've met before?

>xmonad literally has haskell mentioned as a feature

AwesomeWM lists Lua as a feature [1]. Maybe Haskell programmers care about
that a bit more strongly, but both groups use their configuration language as
a feature. Hyper lists JS/HTML/CSS as a feature as well [2]. Although I would
argue the real argument between Haskell and other languages is safety -- just
like Rust or Ada programmers would list those languages as a safety feature,
Haskell programmers are inclined to do the same. It's pretty similar to saying
"code has been tested extensively by our quality assurance team" or something
"code has been formally verified," etc.

[1] [https://awesomewm.org/](https://awesomewm.org/) [2]
[https://hyper.is/](https://hyper.is/)

~~~
gothrowaway
It's my experience and opinion.

Also, I looked through your history, you're a Haskell programmer. Due to the
context of my thread, I'd appreciate it if you disclosed your relation so
others know.

> AwesomeWM lists Lua as a feature

It's a scripting language on top of that's used for configuration.

> It's pretty similar to saying "code has been tested extensively by our
> quality assurance team" or something "code has been formally verified,"

The problem is Haskell developers aren't really getting enough shipped,
especially relative to the advocacy I see of it. So how much does code
correctness matter?

Look, let's say I want play FreeCiv. It being programmed in C vs Haskell vs
Erlang doesn't mean much to me.

But imagine if FreeCiv lacked basic functionality or code documentation, and
when people mentioned these things they'd get jumped by people who advocate it
being programmed in an esoteric language who look down on those who program C
as unsafe, inefficient, etc.

> So you haven't made up your mind already by criticizing Haskell before even
> evaluating it as a language? It's not making up your mind on it when you
> based all your judgements from personal anecdotes of Haskell and Scala
> programmers you've met before?

Hugo vs Pandoc

Awesome/i3 vs xmonad

You want to know why these solutions got more popular than the their Haskell
predecessors? They had devops like documentation and tooling down. They picked
languages that were easier to read so the community could participate. The
discussion was about how to ship features by a version release, not how to
force the language to get a purely internal technical working.

Users can't see the internals, so they don't care. They want something that's
there for them on time and reliably. In all these years to this day, there's
been more advocating Haskell philosophically on forums than there's been real
discussion about getting stuff shipped. Try saying that for
node/go/ruby/python.

~~~
nv-vn
I am not a Haskell programmer, in fact I am not very fond of the language and
have only ever used it for a single project. I find the language interesting,
but I disagree with many of the fundamental design decisions and it is never
my first choice for a project.

------
fpoling
The author mentioned that code generation "introduces additional, non-standart
syntax". One can say exactly the same about generics.

Most useful typesystems with generics are Turing-complete. Essentially they
introduce own language for types with often very weired rules and syntax that
one has to master on top of the basic language. With code generation I can
program my types using the same language I use for code with less things to
learn.

~~~
bad_user
> _One can say exactly the same about generics_

No, it's the same language with a bigger vocabulary and grammar, on which
everybody agrees.

And generics can be quite sane, as exemplified by the languages in the ML
family, which have been around for decades.

Java also didn't have generics. They added them eventually, much later in
version 5, but then due to backwards compatibility concerns they added them
with invariance at the declaration site and complex wildcard rules at use
site.

So the irony of this situation is that Go will add generics, it's inevitable
for a (quasi) static language once it grows in usage and ecosystem. But when
they'll do add those generics, they'll be broken due to backwards
compatibility concerns, becoming yet another counter example for generics,
picked up by the next Go / Java that will reinvent the wheels again.

~~~
fpoling
The ugliness of Java generics comes from type erasing. It allowed to stay
compatible with JVM. Go has no such restrictions and I do not see why a truly
minimal generics in a style of Virgil cannot be added to Go at some point.

~~~
bad_user
No, type erasure is actually an (unplanned) feature, because it didn't cripple
the runtime for other languages.

On this one people miss the forest from the trees. dotNET type reification is
about introducing runtime meta-data and checks, which you only need when your
type system is not strong / expressive enough, which makes you want to do
`isInstanceOf` checks. Well, guess what, needing to check that an instance is
a List<int> is a failure of the language ;-)

This issue is also mixed with specialization for primitives. But that's
actually unrelated because you don't need reification to do specialization.
And actually you don't need runtime support either, as specialization can be
compile time.

Also, in actual practice with Java, type reification is only a small usability
issue. The real clusterfuck have been those wildcards for expressing use-site
variance.

> _It allowed to stay compatible with JVM. Go has no such restrictions_

That's circular logic, given the JVM release cycle is tightly linked to Java
the language and has had evolved in response to new features of Java.

No, the actual reason was to preserve compatibility with older code that
weren't using generics (e.g. List vs List<int>) without forking the standard
library in pre- and post-generics functionality (like .NET has done).

Go will have exactly the exact same problem.

~~~
kuschku
Luckily, Java’s generics are actually changing with Java 10 towards a more
powerful system even.

It’s disappointing how Go, in every way, is just Java 2 with a handful of
additional libraries.

Simply using Java 2, adding some libs, and compiling with GCJ would net the
exact same binaries, with far less work.

------
blacksoil
I think comparing Go and Haskell are like comparing two incomparable different
species -- a fish vs. a cat.

Why? Because Haskell is an interpreted language while Go is a compiled one.
Interpreted language doesn't care much about performance as it isn't designed
for that purpose, while in the other hand, compiled language does. As a
result, interpreted language tends to be more 'elegant' and has lots of
convenient features at the cost of performance. A concrete example is when you
talk about preventing unacceptable data type in Haskell. They could make it so
in Go, but the performance cost would be undesirable.

IIRC, I read that they designed Go to be practical instead of 'elegant', the
reason is so that people can learn it easily, making it a good alternative for
other compiled languages like C++ whose learning curve is hugeeee and ugly!

~~~
theseoafs
Haskell is a compiled language.

~~~
the_why_of_y
There is no such thing as a "compiled language" or an "interpreted language",
as this is a property of language implementations: interpreters (GHCi, Hugs)
and compilers (GHC, JHC).

