News for hackers. Stuff that matters.
Re:Three Months of Go from a Haskeller’s perspective (2016) by Philip-J-Fry on Wednesday November 04, 2020 @03:02AM (#24987183)
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 glaringly obvious reasons.

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.

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

Re:Three Months of Go from a Haskeller’s perspective (2016) by np_tedious on Wednesday November 04, 2020 @04:11AM (#24987491)
Every isolated Go piece is pretty readable. The problem is that getting most things done requires enough code that it's a lot of work to take it all in. Run all the for loops in your head. Etc. Higher level (and esp FP) languages like Haskell or Scala will be the opposite. That bunch of function compositions may take a little bit of work to digest, but once you understand it you understand a lot.

When people disagree on readability its often bc they mean two different things. We would benefit from different terms for readable-in-the-small and readable-in-the-large.

Re:Three Months of Go from a Haskeller’s perspective (2016) by nahname on Wednesday November 04, 2020 @08:35AM (#24988856)
It is a lot like reading levels. Go feels like a grade 5 reading level. This means most people can read it. It also means complex concepts take a lot longer to explain because you have to avoid all sophistication.
Re:Three Months of Go from a Haskeller’s perspective (2016) by panpanna on Wednesday November 04, 2020 @11:22AM (#24990389)
Counterpoint: I find the go standard libraries (which are quite extensive) incredibly readable.
Re:Three Months of Go from a Haskeller’s perspective (2016) by LandR on Wednesday November 04, 2020 @03:58AM (#24987430)
> Go is incredibly readable I find.

I'm the opposite, I don't find it readable at all.

I find Go too verbose to be readable.

Re:Three Months of Go from a Haskeller’s perspective (2016) by kevincox on Wednesday November 04, 2020 @10:04AM (#24989638)
Exactly this. I find that each line of go is readable. However actually trying to figure out what the code is trying to accomplish becomes a chore because I can't keep all of the lines in my head.

Maybe it is because what I am used to but I find I am often "pattern matching" loops into `map`s `filter`s and similar in my head. Of course doing this, and making sure that I didn't miss a side effect or condition that makes it not-quite-a-map takes a lot more brainpower than just seeing `slice.map(|path| path.basename())`.

Re:Three Months of Go from a Haskeller’s perspective (2016) by eru on Wednesday November 04, 2020 @04:36AM (#24987612)
> 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.

I'm not sure what those glaringly obvious reasons are. In Erlang, you just send a copy of the whole struct. Not some kind of references or pointers.

See eg https://play.golang.org/p/P3qUtFenp2q

But as I am saying, if you want to send pointers (or references) over a channel, they should support marking things as immutable.

> 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.

Go doesn't force you to handle errors at all. The compiler will happily mix up the branches of your `if` that checks for errors, or let you get away without checking anything at all.

My suggestion would be eg algebraic data types. Especially sum-types. Or in more C inspired terms: tagged unions plus pattern matching. Or 'an enum with parameters'.

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

In a language without any checking at all like JavaScript, human authors and reviewers have to make sure that you don't accidentally eg add a string to an int. Or otherwise, have to make sure that at least you have enough test coverage.

In Go, the compiler can yell at you when you are trying to add an int to a string.

In OCaml or Haskel or Rust (or any language with algebraic data types), the compiler can make sure that you check your errors. So in eg Haskell syntax that looks like this:

    case someFunctionThatMightGoWrong(someParameter) of
        Error errorDetails -> handleErrors(errorDetails)
        Success someValue -> doSomethingSensible(someValue)
Crucially, `someValue` is only in scope in the branch where we match the right pattern. So you can't accidentally go on computing with that variable in the wrong branch.

Does this make sense? If not, I can try to explain in some other way.

Re:Three Months of Go from a Haskeller’s perspective (2016) by bankisan on Wednesday November 04, 2020 @08:44AM (#24988937)
Regarding the example in your first point, you are still sending a reference `m` of the map. If you wanted to send an immutable type, you could declare the channel to only accept struct values (and not pointers to structs) and you'll get your desired behavior.

Here's a playground for reference:

https://play.golang.org/p/U2tYZVTtUf-

Re:Three Months of Go from a Haskeller’s perspective (2016) by simiones on Wednesday November 04, 2020 @09:54AM (#24989553)
Given that there is no way to make a non-pointer map in Go, there is no workaround for the example they gave.

The broader point is that there is no way in Go to ensure that data passed over a channel will not be modified concurrently without modifying the type of the data specifically for the channel use case.

A deep_copy() primitive would fix this.

Re:Three Months of Go from a Haskeller’s perspective (2016) by bankisan on Wednesday November 04, 2020 @10:29AM (#24989854)
Right, but they mentioned sending immutable structs which is why I gave the struct example. But you're right that every declared map is a just a pointer.

With respect to your second point, I see what you mean but I still don't think that's a negative of Go. You can pass in copied values without having to have a deep_copy() primitive (loop map values and copy to new map, dereferencing a pointer, etc.). Like other parts of Go, if you want to make your data immutable there is no syntactic sugar. You have to explicitly write it out.

Re:Three Months of Go from a Haskeller’s perspective (2016) by simiones on Monday November 09, 2020 @08:56AM (#25034824)
> With respect to your second point, I see what you mean but I still don't think that's a negative of Go.

It is a negative of Go, because Go pushes you into the pit of failure by its design: it is much, much harder to do the right thing (send deep copies of objects over channels) than it is to do the wrong things (send pointers or shallow copies over channels).

Re:Three Months of Go from a Haskeller’s perspective (2016) by eru on Thursday November 05, 2020 @03:11AM (#24996488)
You'd have to roll your own deep_copy by hand (or code generation) for every single data type.
Re:Three Months of Go from a Haskeller’s perspective (2016) by eru on Thursday November 05, 2020 @03:11AM (#24996481)
Yes, either a deep_copy() or a way to declare things immutable. (Or both.)
Re:Three Months of Go from a Haskeller’s perspective (2016) by curryst on Wednesday November 04, 2020 @07:51PM (#24994653)
> 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) by eru on Thursday November 05, 2020 @03:09AM (#24996472)
> 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.

Not quite. I am suggesting a tagged union. Not a runtime type check.

You'd check the tag.

Some language only support the runtime type-checked version of union types. That's a bit silly. For example, it makes it much harder to write a function that may either error out itself, or produce an error message as its bona fide value.

Re:Three Months of Go from a Haskeller’s perspective (2016) by simiones on Wednesday November 04, 2020 @09:48AM (#24989500)
I think even more than the lack of generics, Go is difficult to read because it forces you to mix the error path with the success path in every function which can possibly fail, often making you bubble errors up the call stack manually.
Re:Three Months of Go from a Haskeller’s perspective (2016) by eru on Thursday November 05, 2020 @03:13AM (#24996496)
Well, the onerous error handling is a symptom of the lack of generics.

Go has no facilities to would allow you to abstract away the repetitive parts of error handling.