Live data from Hacker News

Three Months of Go from a Haskeller’s perspective (2016)

memo.barrucadu.co.uk

141–150 of 162 posts

Re: Three Months of Go from a Haskeller’s perspective (2016)

#141

Earlier quoted context omitted.

Definitely! I couldn't get my head around why people like untyped languages, but I keep an open mind on it. I won't close off that they could be better, if the right patterns/practices are used (whatever they are!)

> I couldn't get my head around why people like untyped languages What do you mean exactly with "liking" untyped languages? I personally program mainly in both a ("cognitively demanding") typed and an untyped languages, and they have different use cases. For relatively small programs, untyped languages are much faster to develop. A program I wrote yesterday in a few hours would have taken 2 to 4 times as much in a ty…

Is that true? A simple program that isn't going to see long term use means I don't have to worry about anything but the happy path, either typed or untyped. And something where I have to nail down the edge cases is easier in a typed language.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#142
post #97
post #10

Apparently, the author of this blog post had a change of heart: https://memo.barrucadu.co.uk/blub-crisis.html > I have realised in recent conversations about programming languages, and in reflection of my very negative and kind of arrogant blog post about Go, that I have become trapped by the Blub Paradox. I have become dismissive of non-Haskell languages. I think in Haskell. Languages less powerful than Haskell are…

Such a weird thing to frame this in terms of the Blub Paradox. Regardless of what you think about the paradox, this is what it states: > But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn’t realize he’s looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as…

The Blub Paradox is flat-out wrong. To see why, just look at Haskell and Lisp.

When a Lisp user looks at Haskell, they are sure they're looking down, because Haskell doesn't have macros. But when a Haskell type (pun intended) looks at Lisp, they are also sure that they're looking down, because Lisp doesn't have a decent (Hindley-Milner) type system.

This situation - two languages, each sure that they're above the other - shows the problem. You cannot rank languages on a one-dimensional axis called power.

Another way of getting there is to ask: Power? Power for what? For writing programs. What kind of programs? General programs? I've never written a general program in my life. I've written a bunch of specific ones, though. What I care about is power to write this program - the one I'm currently trying to write. (Why do I care about a language's power to write a program that I'm not trying to write?)

Instead, think in terms of yak shaving. What are the yak shaving aspects of the program I'm trying to write? Think of that as a vector in a multi-dimensional space. Think of languages as branches on a tree. Which branch extends farthest in the direction of the yak-shaving vector? Use that language.

But you have to have kind of an expanded idea of what "yak shaving" means. In particular, if you pick a "non standard" language, training your team becomes part of the yak shaving.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#143
post #49
post #7

I've been using generics with go2go and am looking forward to replacing generated code when they are officially released.

Serious question, I've been toying about with Go but aside from having to recently write a tree for myself, what are you using generics for? One of the things I really lean into with go is that your program tightly fits your problem. Where's your generic limitation?

Really late but... I use them to avoid type assertions. Most recently I need to operate on channels of all types.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#144
post #30

> In Go, you import packages by URL. If the URL points to, say, GitHub, then go get downloads HEAD of master and uses that. There is no way to specify a version, unless you have separate URLs for each version of your library. Go modules has solved this problem. I find that in practice Go modules work very well. Certainly better than the alternatives and I've been through most of them. Incrementing the major version o…

I don't believe the problem is fully solved yet with modules (there's still the V1/V2 problem), but it's a step in the right direction. I've been using modules in my current project (new codebase) since the start of the year and so far have run into no problems whatsoever when it comes to modules. Mind you, a big plus, I think, is that Go doesn't have the ridiculous library ecosystem that others I've worked with (JS/…

> Mind you, a big plus, I think, is that Go doesn't have the ridiculous library ecosystem that others I've worked with (JS/Node, Java) have; I only use a handful of libraries at the moment (for REST api, .env file handling, database interaction and logging, and some additional ones for development like mocking, neat diffs for tests, and code generation (xsd & swagger to code).

I think this is a great selling point. Probably due to the stdlib being so extensive.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#145
post #86
post #67

Earlier quoted context omitted.

Prototyping or gluing components together is definitely faster without static typing.

I think this is a fault of language ergonomics rather than static typing. If you are gluing components together, then surely the components have a common interface that uses compatible types. And surely you need to tell the runtime what those types are in some way, even if that is simply by writing them to return appropriate values. In theory, a statically typed language with ideal ergonomics would make that as easy…

> If you are gluing components together, then surely the components have a common interface that uses compatible types

This is not guaranteed; for example, the representation of a JSON object is trivial in dynamically typed languages, because there are no type bounds.

Ease of metaprogramming is another. Possibly also debugging - I don't get powerful REPLs in the statically typed languages I've used, as much as those in the the dynamically typed language I use.

Concepts like these don't represent best practices for sure at large scale, but they do make things easier at least at small scale, and they don't need to be necessarily supported.

Taken to the extreme, Perl variable autoinitialization and context sensitivity are very convenient for 3-statement programs, but they'd be horror above that. It doesn't make sense for any language to try to support that.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#146
post #121

Other comments have claimed that Go is intended for teams, but my personal experience shows that Go code is easier to maintain than Haskell code, even for a single developer. Though I've coded with Haskell for many years, I never reached an expert level. So, when I went back to an application after 6 month of break, my Haskell skills were rusty, and I struggled to understand what I had written. What's that pragma `Mu…

I think comparing Go to Haskell at all is slightly bizarre, really. When I think Haskell, enterprise maintainability coding isn't exactly what comes to mind. I really don't like Go, but I won't deny that it basically does what it's supposed to do.

> When I think Haskell, enterprise maintainability coding isn't exactly what comes to mind.

One day hopefully

Re: Three Months of Go from a Haskeller’s perspective (2016)

#147
post #106

Earlier quoted context omitted.

I agree that being able to reason about mutability and other effects is useful. However, that doesn’t necessarily imply an all-or-nothing approach where either you’re in a pure function or you can do anything with anything. In a sibling comment, gwd mentioned const in C, which is one example of something in between. Rust’s ownership semantics and borrow checker are another.

> However, that doesn’t necessarily imply an all-or-nothing approach where either you’re in a pure function or you can do anything with anything. To elaborate this point I'd say that the most important practical use of all that "monad mumbo-jumbo" in Haskell is that you can tag your functions with what they can and can't do and then the type system tracks this for you: -- pure function f1 :: Text -> Int -- can fail f…

The trick seems to be how to implement this kind of idea in a composable way, so we can still have a clear, modular design and write generic, reusable code even in the presence of several different types of effect. IMHO, the research into type and effect systems in recent years has been promising, but also shows that this is not an easy problem to solve. I’m hoping that in a few more years we might see a new generation of programming languages that incorporate this kind of “effect safety” as easily and naturally as many developers use const and qualifiers and resource management idioms today.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#148
post #28

Earlier quoted context omitted.

Go impedes its own readability by encourage or even requiring such huge volumes of code. (And Go ain't very good at concurrency. At least they should have let you mark values as immutable, or communicated entirely via copying like Erlang.) Yes, tuples are a really weird thing with Go. If they had completely left them, that would be bad but sort of defendable. But instead they give you a half-baked implementation of s…

Go is incredibly readable I find. Yes, you tend to find yourself writing a lot of code because of the lack of generics, but that is being fixed as we speak. Generics has a draft and it looks nice from a Go developers perspective. And Go let's you communicate by copying. That's what a Channel is. Pass a struct and that is copied. Pass a pointer and the pointer is copied. The thing it points to isn't copied for glaring…

> And Go let's you communicate by copying. That's what a Channel is. Pass a struct and that is copied. Pass a pointer and the pointer is copied. The thing it points to isn't copied for glaringly obvious reasons.

Copying large structs is not ideal, but passing a pointer to the channel means the other side of the channel can mutate that data. If Go had immutable types, you could pass a constant pointer, allowing the other end of the channel to read from the pointer but not modify it.

> And what would you suggest is a good alternative for returning multiple parameters. Currently this basically forces you to handle any possible errors and results in software you can very easily reason about.

What he's talking about is returning a union type. You have a single return value, it's type is either a valid result (i.e. a string) or an error. The compiler expects you to do runtime type checks (basically) to assert whether your return value is actually a value or not.

The explicit return values get clunky in some situations. If I have a function that processes an array of items, where each item can fail individually, in Go the cleanest way to handle that is to make a struct that holds a pointer to a value (so you can check if it's nil) and an error. And you return an array of those structs. In languages with Options, you can simply return an Option object, and let the upstream caller figure out what to do if it's an error.

Javascript/Typescript Promises are a similar, though less featureful, implementation of the same kind of idea.

Not sure what you mean about human reviewers needing to check errors.

Re: Three Months of Go from a Haskeller’s perspective (2016)

#149
post #23

Earlier quoted context omitted.

> The problem with "Make it an error to not initialise a struct field" is you lose source compatibility when adding new struct fields. If you allow the struct definition to specify a default value then the struct author can set default in the cases where there is a sensible default, and leave it compile-time incompatible in the cases where there really is no good default and the person doing the upgrade needs to make…

That is already possible by exposing a `New` function and making the struct itself unexposed; are you suggesting syntax should be added to provide default values to struct fields? Because there is high resistance (which I agree with btw) to adding additional syntax and constructs to the language.

> That is already possible by exposing a `New` function and making the struct itself unexposed;

I thought Go didn't allow functions with default argument values either?

Re: Three Months of Go from a Haskeller’s perspective (2016)

#150
post #81

Earlier quoted context omitted.

I've never written Haskell or another pure functional language more than a couple of lines, but the more I write code the more convinced I become that the ability to reason about mutability and side effects is a major force multiplier in writing robust software.

I tend to agree, but, even then, one doesn't necessarily have to take things quite as far as Haskell does. In Rust, for example, mutable data is allowed, but, when the owner of mutable data shares a reference to it, it gets to decide whether the borrower is also allowed to mutate the data. This doesn't eliminate the more challenging things you can do with shared mutable variables, but it does mean that enabling them…

It's worth noting that Haskell allows mutable variables in IO actions - a type used to model computations that are not referentially transparent. It's just that using this facility is not super ergonomic.
Post reply on HN