Live data from Hacker News

Go generics are not bad

lemire.me

211–220 of 305 posts

Re: Go generics are not bad

#211
post #85

I think in Java, you would need to do a type-class approach. interface Numeric { T zero(); T add(T a, T b); } static T sum(Numeric n, T[] v) { T summer = n.zero(); for (int k = 0; k

Honestly I have no idea what's going on with this code. Where is `zero()` defined? Why does a `Numeric` have a function to `add` two numbers? Shouldn't you add a single number to a numeric? What is the relationship between ` ` and `Numeric `? I thought `T` was a `Numeric`? Edit: Upon closer inspection, I kind of get what's going on. But it's really cryptic for something that should be simple to express.

Think of `Numeric` as analogous to `Comparator`. T is the type you're doing stuff with, `Comparator` tells sorting algorithms how to compare two Ts, and `Numeric` tells mathematical algorithms how to add two T's, and what a "zero" value for T should be.

There are probably other reasons to do this that I'm forgetting, but off the top of my head,

1. You can implement `Numeric` or `Comparator` for types `T` that come from a library that you can't change (so can't make T implement an interface that the library author didn't implement), or where you don't want to introduce a dependency (you could have a type class `JsonDecoder[T]` that comes from a library, and you don't want the library with your T to introduce a dependency on the json library).

2. You can have more than 1 implementation for a given T. For JSON decoders/validators, you might provide a decoder which bails out on the first error, or one which tries to continue reading fields so it can return all errors (field X was a string, expected number. Field Y was expected to be >= 1024, etc.). For comparators, you might have a `.reversed` function to easily make a comparator that sorts in reverse order. etc.

Re: Go generics are not bad

#212

Earlier quoted context omitted.

> Write a server that does communication or emulate select in Go in other languages. I just did that - I've been working on a very similar thing to goduplicator (a mirroring proxy), however with an additional requirement that it must not add latency to the primary communication path, e.g must connect mirrors asynchronously and buffer data instead of waiting for a slow mirror. I chose Rust and the resulting code has b…

Well, for latency you do have to deal with the GC very carefully, but the investment/ratio in Go is very good. It is just not for absolutely every use case, like everything else in your toolbox.

Investment ratio in Go is only good because of how little you have to invest. In Rust the required investment is bigger, but you get a lot more in return. Not sure about which ratio is really better.

GC is only a minor reason I chose Rust over Go for a networking related project. Despite having a GC, Go definitely feels more low-level and less structured than Rust, and leads to code that is longer and harder to reason about.

It is very similar to how a language with only a goto instruction to do control flow would be definitely simpler/smaller than a language that supports functions, loops and conditions, but the actual programs written in it would be brittle and harder to understand.

Re: Go generics are not bad

#213

I think in Java, you would need to do a type-class approach. interface Numeric { T zero(); T add(T a, T b); } static T sum(Numeric n, T[] v) { T summer = n.zero(); for (int k = 0; k

Isn't the java problem that (a) the + operator is only defined for some built-in types, and (b) the int/Integer boxing distinction?

Right, you can't overload the + operator, and primitives can't be used in generics.

Re: Go generics are not bad

#214
post #174
post #88

Earlier quoted context omitted.

Generics are great when you need them, but they will cut you badly if you misuse them. Generics are viral. When you make something generic, you often have to make the things that touch or contain it generic, too. Generics also create tight coupling. When you change the definition of a generic interface/class, you'll need to update your usage across the codebase. As opposed to, say, adding a new field to a class, that…

All of the things you said apply equally well to function parameters.

That's an interesting point. From a strictly theoretical perspective you're right. I think it's that generics are more abstract and have a higher blast radius. Eg, you add an argument to a method, you need to update usage of that method. You add a generic to a class, you need to update everywhere that class is used.

The fact that arguments are less abstract also I believe tends to prevent them from bubbling all the way to the top. Generics can often only be populated at the top-level usage. Function arguments I find don't usually bubble up that far.

Re: Go generics are not bad

#215
post #88

Earlier quoted context omitted.

Generics are great when you need them, but they will cut you badly if you misuse them. Generics are viral. When you make something generic, you often have to make the things that touch or contain it generic, too. Generics also create tight coupling. When you change the definition of a generic interface/class, you'll need to update your usage across the codebase. As opposed to, say, adding a new field to a class, that…

Please show code then I dont remember misusing C# generics even once and I struggle to see example of such a case

This is a reasonable request, but I don't really want to write a code example, that feels like a lot of work and I have 0 investment in changing anyone's mind about this (I didn't really expect this to be controversial - I was just sharing my experiences and expanding on Avlin67's comment about "generic hell"), but if you had a question I'd be happy to answer it.

Re: Go generics are not bad

#216

Earlier quoted context omitted.

They're not viral in rust - you can always replace the generic with a concrete type in super types.

Rust also has associated types, which are exposed to the implementer, but not to the consumer.

I mean, generics and associated types aren't equivalent, but they also are often exposed to the consumer. Eg, if you're accepting an Iterator, you'll want to populate the Item associated type.

Re: Go generics are not bad

#217

I think in Java, you would need to do a type-class approach. interface Numeric { T zero(); T add(T a, T b); } static T sum(Numeric n, T[] v) { T summer = n.zero(); for (int k = 0; k

Type classes are on the roadmap after Valhalla [1]. [1] https://blogs.oracle.com/javamagazine/post/what-are-they-bui...

This is good news.

My wishlist for Java is for null to be illegal for all types unless they are encoded as nullable such as `T?`.

Until then, I just use Kotlin and/or Scala when I require JVM.

Re: Go generics are not bad

#218
post #85

I think in Java, you would need to do a type-class approach. interface Numeric { T zero(); T add(T a, T b); } static T sum(Numeric n, T[] v) { T summer = n.zero(); for (int k = 0; k

Honestly I have no idea what's going on with this code. Where is `zero()` defined? Why does a `Numeric` have a function to `add` two numbers? Shouldn't you add a single number to a numeric? What is the relationship between ` ` and `Numeric `? I thought `T` was a `Numeric`? Edit: Upon closer inspection, I kind of get what's going on. But it's really cryptic for something that should be simple to express.

I think this may be good reference material: http://learnyouahaskell.com/types-and-typeclasses

Basically I'm encoding this approach in Java.

Re: Go generics are not bad

#219
post #88

Earlier quoted context omitted.

Generics are great when you need them, but they will cut you badly if you misuse them. Generics are viral. When you make something generic, you often have to make the things that touch or contain it generic, too. Generics also create tight coupling. When you change the definition of a generic interface/class, you'll need to update your usage across the codebase. As opposed to, say, adding a new field to a class, that…

>Generics are viral. When you make something generic, you often have to make the things that touch or contain it generic, too Do you have an example of that? Can't you always "typedef" any particular generic type as a concrete type and work with that going forward? >Generics also create tight coupling. When you change the definition of a generic interface/class, you'll need to update your usage across the codebase. A…

I mentioned in a sibling comment, I just don't wanna write an example, sorry.

You can't typedef, or populate the generic in any way, until you've reached a point in your code where you have sufficient information to know what to populate it with. This can often be further from the point of the initial change than you might like, as I described. (ETA: I didn't realize viral implied that you can _never_ concretize, I only meant there's a tendency to pass it up the chain.)

Changing public APIs will cause secondary changes. Generics are coupled more tightly than some other kinds of changes. For example adding a parameter to a method in an interface does force you to update all those implementations, and then all the usages of those implementations, which is a lot of work and could potentially trigger a similar situation. But generally it doesn't bubble up as high. Because generics are more abstract, it's more difficult to populate that parameter - you're more likely to need to pass the buck by being generic over that yourself, which causes you to update more usages, etc.

Re: Go generics are not bad

#220

Earlier quoted context omitted.

There’s a whole lot wrong about this comment, but the most obvious is the claim that Go lacks a new keyword. Firstly, Go has a new keyword and secondly who makes a big deal about whether or not a language has a new keyword?

I believe what the commenter is complaining about is that you can't specify default values through a constructor that is invoked with the new keyword. I personally don't see this as a huge concern, since you can just make a constructor function, but it's definitely a valid concern because you could still allow people to shoot themselves in the foot when using a struct literal. Go's paradigm of making the zero-value s…

Sure, allowing struct initialization without explicitly setting fields is a foot gun. Ideally Go wouldn’t assign meaning to zero values and instead require each field to be explicitly initialized a la Rust. This is one of the things Go got wrong and Rust got right.
Post reply on HN