News for hackers. Stuff that matters.
Re:Go 1.18 by yashap on Wednesday March 16, 2022 @12:18AM (#30695274)
I’m a big fan of Go adding generics, but I can see some of what people are worried about. I don’t think it’s “business logic that would benefit from being made generic”, it’s that generics allow people to write new data structures that aren’t currently reasonable to write in Go. For example:

- Sets

- Trees/graphs

- Stacks/queues

- List-like data structures with different performance characteristics than slices

- Monadic data structures you find in functional languages, like Option (for dealing with the lack of a value), Either (one of two possible values), Future (basically either a success or an error, computed asynchronously), etc.

I’m sure we’ll see popular libraries providing all of the above, and more. Generics will make for a wider variety of programming styles in Go, which has downsides as well as upsides.

Go will likely get a bit more functional/declarative/high-level, a bit less imperative/procedural/low-level. It’s not about to become Haskell or Scala, but maybe a bit more like TypeScript or statically typed Python, a bit less like C.

Re:Go 1.18 by bobbylarrybobby on Wednesday March 16, 2022 @01:12AM (#30695545)
Why would anyone be worried about being able to write code that more closely matches the problem domain?
Re:Go 1.18 by rob74 on Wednesday March 16, 2022 @01:43AM (#30695715)
Spending lots of effort designing your type system to match your problem domain (or rather, what you think is your problem domain) is a pitfall which was made less likely by "classic" Go because the available types were very straightforward. Which also made it easier to refactor your code when you inevitably realized your initial approach didn't match the problem domain that well after all (or the problem domain changed, as it tends to do when you maintain an application over several years). And I totally understand that people are worried having generics will change this.
Re:Go 1.18 by jeltz on Wednesday March 16, 2022 @06:03AM (#30696997)
Because generics rarely help with that. I love generics for writing libraries and for giving me libraries which are easy to use but my business logic is almost never generic. Most problem domains I have worked in have not been very generic.
Re:Go 1.18 by baby on Wednesday March 16, 2022 @04:56AM (#30696646)
Readability, complexity, security
Re:Go 1.18 by manigandham on Wednesday March 16, 2022 @01:26AM (#30695615)
Why are new data structures worrying?
Re:Go 1.18 by yashap on Wednesday March 16, 2022 @01:55AM (#30695772)
The downside is they’ll make Go code less uniform. Do you represent nullability with a nil-able pointer, or an option monad? To transform a list, do you loop over a slice, or map/flatMap/filter over a more functional data structure? etc.

Pre-generics, Go has been a very limited language. On the downside it’s verbose and error-prone, on the upside it’s very uniform. I think generics will make it less verbose and error-prone, but also less uniform - stylistic differences from programmer to programmer will be greater, similar to other high level languages.

Re:Go 1.18 by zozbot234 on Wednesday March 16, 2022 @03:49AM (#30696315)
> Pre-generics, Go has been a very limited language. On the downside it’s verbose and error-prone, on the upside it’s very uniform.

Except that this kind of uniformity inherently tends to disappear in larger projects, to be replaced by increased complexity. Java was also designed to be a "simple" language, one trivially understandable by hordes of low-skilled code monkeys, and yet look at the added layers of complexity in many Java enterprise frameworks. More full-featured languages, when properly designed (especially, avoiding the feeping creaturitis of something like Scala), make it easier not harder to manage inherent complexity at a larger and larger scale of development. But Go is now basically stuck with its constrained feature set, and Go developers cannot easily avail themselves of these tools. This is why so many devs criticize this particular design goal; it's pretty much incoherent.

Re:Go 1.18 by baby on Wednesday March 16, 2022 @04:59AM (#30696666)
I’ve audited a bunch of complex codebases in Golang that were very readable. Surprisingly readable actually
Re:Go 1.18 by dividedbyzero on Wednesday March 16, 2022 @05:58AM (#30696976)
In my experience, that happens when people consciously manage the way they use their language, or have the trained instinct to do so unconsciously. At a certain scale choice of language doesn't really influence this all that much (as long as the language isn't Perl I guess, I've never seen that done cleanly.)

I've worked on really neat big Scala codebases and really terrible big Go codebases – a determined developer can make a mess regardless of language, and for some cases it's actually easier to end up in that place with Go than with a more expressive language with a more comprehensive stdlib. Go isn't well-equipped for a number of things, and if you have to do those a lot, generated code and workarounds like the pseudo-sets people build from maps really become liabilities.

From what I've seen as far as complex codebases are concerned, I'd say Go can be very readable for small-ish programs that lend themselves well to Go's opinionated standard library and way of doing things, but I'd definitely want to use something more expressive at scale or for anything that doesn't fit into Go's limitations well.

Re:Go 1.18 by baby on Thursday March 17, 2022 @12:53AM (#30707793)
I couldn't disagree more. Everything I've read in Java was a huge messy pile of spaghetti code. C++ and C can definitely become unreadable very quickly. Rust, on the other hand, I find harder to mess, although there are still lots of ways to do it. And then there's Golang, I've read so much Golang code that I'm surprised when I run into something that isn't readable. Happened to me once, obviously the code had been written by Java developers (factories lol)
Re:Go 1.18 by ezst on Wednesday March 16, 2022 @06:50AM (#30697270)
> when properly designed (especially, avoiding the feeping creaturitis of something like Scala)

What I find interesting here is that Scala has the reputation of being a complex language, while its syntax and grammar are among the simplest and most straightforward there is: https://images.app.goo.gl/K1NTGUP4G9T6wfY48

I believe that this is what "scalable" means in the eyes of its creator: it offers very powerful abstractions to be adequate for mundane tasks (e.g. file-level scripting) up to complex systems and problem spaces.

Yes, as a consequence, people have created libraries and codebases with Scala that are inadequately complex and abstract for the problem at hand, but that's not something one should blame on the language but on the project/company culture. Same is true for any language: C++ templates can be abused in ludicrous ways, some of Java's design patterns make you wish inheritance would be forbidden, python's module imports potentially overwriting globals and other footguns.

No language can be dumbed-down so much that the resulting codebase becomes immune to some amount of "abstraction management", not go, not even python. Once this is understood and accepted, it becomes obvious that it's not worthy to castrate a language on the basis of "simplicity", because eventually this complexity will be warranted at a point in the future or for some aspect of the project.

I think the go designers did the right thing here, I don't think this will bring dramatic changes in how the language is used, and will actually help with "managing abstraction" where it's due.

Here's more on that: https://www.lihaoyi.com/post/StrategicScalaStylePrincipleofL...

Re:Go 1.18 by lifty on Wednesday March 16, 2022 @06:03AM (#30696995)
Java code got complex after adding generics, not before. In a big Go codebase, even if it’s complex, the styling and patterns are the same, so it’s easier to follow. That might change to some degree with the addition of generics.
Re:Go 1.18 by ezst on Wednesday March 16, 2022 @07:01AM (#30697351)
That's not true. Java was notorious for AbstractFactoryProducerArtifactFactory and awful inheritance-based patterns long before that.

You can't dumb down a language and expect the complexity of the problem space to go away (developers will have to cope with it one way or another), and you can't expect the programming language alone to be the sole judge of what's an acceptable level of abstraction (or architects would have been made redundant by now).

Re:Go 1.18 by baby on Wednesday March 16, 2022 @04:58AM (#30696654)
Wish I could upvote this comment more. This is the best summarized take on the introduction of generic in Go. It’s exciting, but frightening at the same time. Will this destroy the simplicity and the readability of Golang?
Re:Go 1.18 by rob74 on Wednesday March 16, 2022 @01:46AM (#30695725)
Because they add cognitive load, make it harder to read a piece of code and understand what it is doing (and therefore can hide errors) etc. etc.
Re:Go 1.18 by torginus on Wednesday March 16, 2022 @06:04AM (#30697001)
I'm kind of not sure what's necessary that wasn't there before. Go has:

- List

- Array

- Dictionary

- Set (map with empty value)

- Stack (easily emulated with list)

- Queue (channel)

Other than the ones mentioned before, the only ones I've ever used were a priority queue and sorted map (AVL-tree), and even those were rare. Other than these I used others that were so application-specific, that it made no sense to be generic. Based on this there's no strong case for why generics have to be in the language. Not hating, but I'm not convinced either way.

Re:Go 1.18 by _wldu on Wednesday March 16, 2022 @01:37AM (#30695681)
Go has maps already. A set is just a map where the key and value are the same thing.
Re:Go 1.18 by yashap on Wednesday March 16, 2022 @01:47AM (#30695735)
Sets tend to have methods like difference, union and intersection - with a map[T]bool, if you want to find the difference, union or intersection of 2 sets, you have to do all of that with much more verbose (and error prone) loops. Also, the type being a set carries a semantic meaning, with a map[T]bool it’s not obvious from the type alone that we only care about the keys, not the values.
Re:Go 1.18 by thegeekpirate on Wednesday March 16, 2022 @03:36AM (#30696228)
> with a map[T]bool

This takes up unnecessary space—use map[T]struct{} instead, which also explains to anyone reading the code that the value isn't used.

Re:Go 1.18 by randomswede on Wednesday March 16, 2022 @04:50AM (#30696621)
There is a slight difference between the two. With a map[†]bool, you can do something like:

if myset[thing] { ... }

With a map[T]struct(), you end up with:

if _, ok := myset[thing]; ok { ... }

Sometimes, the saving in space is TOTALLY worth the extra verbosity. Sometimes, the slight clarity from "non-existent keys return the zero value" wins.

Re:Go 1.18 by thegeekpirate on Wednesday March 16, 2022 @05:58AM (#30696975)
You've also opened yourself up to bugs by allowing the map values to be "false".

Using a "set's" value in an if statement doesn't make sense either, compared to

    if _, exists := something[item]; exists { ... }
which is explicit regarding what's actually going on.

As Rob said, "Clear is better than clever." https://www.youtube.com/watch?v=PAAkCSZUG1c&t=875s

I also don't want to be hunting down whoever creates a map[T]bool and doesn't leave a comment explaining it's a set ;)

Hopefully we won't have to worry about it for much longer regardless, since I imagine we'll be using proper sets (with methods) some point in the near future.

Re:Go 1.18 by randomswede on Thursday March 17, 2022 @05:05AM (#30709069)
I would say that "exists in the set" is determined only and exactly by "mySet[thing]" returning true, not that there happens to be a key in the map.

But, that's one of those "requires extensive documentation" (and ideally, wrapping in a custom type and provide methods for checking and manipulating the set(s)).

Re:Go 1.18 by yencabulator on Friday March 18, 2022 @03:59PM (#30726813)
Now every range over your set is likely to be a bug. `map[T]bool` is simply a bad design to use.
Re:Go 1.18 by randomswede on Monday March 21, 2022 @09:37AM (#30753955)
How? Why? If you use the map[T]bool, you obviously need to pay attention to the bool value, even in a range. Whereas in map[T]struct{} you don't need to pay attention to the values.

In either way, even with that type of data type underlying a set, I would (probably) provide a functional API to interact with it.

Re:Go 1.18 by yencabulator on Tuesday March 22, 2022 @11:19AM (#30767138)

    m["x"] = foo()
    for k := range {
        // if foo returned false, this is buggy
    }
Re:Go 1.18 by randomswede on Wednesday March 23, 2022 @05:11AM (#30776534)
Yes, as I said, if you use a map[T]bool, you need to use something like:

for k, v := range m { if v { } }

But it also allows you to use "if m[key] { ... }". It is literally a trade-off for what convenience you want. And in both cases, you should (probably) wrap an abstraction around the raw map.

Re:Go 1.18 by morelisp on Wednesday March 16, 2022 @05:52AM (#30696938)
Well, now there's no excuse for not having `myset.Contains(thing)` (though there really wasn't before either) which is even clearer.
Re:Go 1.18 by glenjamin on Wednesday March 16, 2022 @06:47AM (#30697258)
And now with generics we have a way to make this decision/optimisation once, and have everyone else benefit from it without having to be aware of the details!
Re:Go 1.18 by papageek on Wednesday March 16, 2022 @01:01PM (#30701305)
I wish this had been map[T]_ vs empty struct.
Re:Go 1.18 by fileeditview on Wednesday March 16, 2022 @03:39AM (#30696247)
You can also use a map[T]struct{}. I like bool better because of the default value behavior but struct{} is very clear and does not take extra memory.