6 ms·
I think in Java, you would need to do a type-class approach. interface Numeric<T> { T zero(); T add(T a, T b); } static <T> T sum(
by throwaway234232 4y ago
I think in Java, you would need to do a type-class approach.
interface Numeric<T> {
T zero();
T add(T a, T b);
}
static <T> T sum(Numeric<T> n, T[] v) {
T summer = n.zero();
for (int k = 0; k < v.length; k++) {
summer = n.add(summer, v[k]);
}
return summer;
}
- Avlin67 4y agoalso in .Net but then you enter a generic hell and you start thinking vanilla es6 is better
- nine_k 4y agoAFAICT this is basically how numbers work in Haskell, and I see no particular problems with them. You usually don't need too many number types of different nature.
- maxbond 4y agoGenerics 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 can be safely ignored anywhere it isn't used. When this component you're updating is highly connected to other parts of your code, perhaps add another generic parameter to it, it completely explodes and you have to jump all around your codebase adding generics. The kicker is that you may be updating components which are themselves generic and highly connected, setting off secondary explosions. Pretty soon you're throwing that codebase out, starting over, and swearing to yourself that you'll never touch generics again. My advice is to assume generics are a premature abstraction until you've exhausted what you can do with more concrete approaches.
- rowanG077 4y agoThis is not the case with traits/type class approach seen in Rust/Haskell.
- maxbond 4y agoI'm afraid that it most certainly is, as Rust is the only language I have ever used generics in, and I had this problem. Lifetimes suffer from the exact same problem as well, since they're really an exotic form of generic. That said, I will readily admit that it was a lack of skill on my part. From talking to people in the Rust community though, I gather this isn't an uncommon experience.
- hgomersall 4y agoThey're not viral in rust - you can always replace the generic with a concrete type in super types.
- orthoxerox 4y agoRust also has associated types, which are exposed to the implementer, but not to the consumer.
- maxbond 4y agoI 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.
- maxbond 4y agoWell that's rather the point of being generic with any language, isn't it? You can stop being generic when you have sufficient information to stop being generic. If you're writing a library, that can easily bubble up all the way to the top, because you may never have enough information. ETA: I think I was using a definition of viral that wasn't entirely correct. I thought it was a casual term rather than a precise one. But it seems like you're saying something is viral if you _must_ pass it on. In which case I apologize, generics are "semiviral" (I'm trying to introduce this term - if it already exists & isn't this, I apologize) - you don't need to pass them on, there's just a tendency to. The result looks very similar.
- sbelskie 4y agoC# is getting support for generic math in 11 with the addition of static abstract members (including operators) for interfaces.
- enw 4y agoHonestly 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 `<T>` and `Numeric<T>`? 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.
- aw1621107 4y ago> Where is `zero()` defined? It's defined by whatever implements the interface. > Why does a `Numeric` have a function to `add` two numbers? Because Java doesn't have user-defined operator overloading, so if you want to add stuff in a generic fashion you can't rely on `+`. > Shouldn't you add a single number to a numeric? What is the relationship between `<T>` and `Numeric<T>`? I thought `T` was a `Numeric`? `Numeric` doesn't contain data, it just defines operations on numbers. So `Numeric<Integer>` would define operations on `int`s, `Numeric<BigInteger>` would define operations on `BigInteger`s, etc.
- ndriscoll 4y agoThink of `Numeric<T>` as analogous to `Comparator<T>`. T is the type you're doing stuff with, `Comparator<T>` tells sorting algorithms how to compare two Ts, and `Numeric<T>` 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<T>` or `Comparator<T>` 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.
- throwaway234232 4y ago
- kasperni 4y agoType classes are on the roadmap after Valhalla [1]. [1] https://blogs.oracle.com/javamagazine/post/what-are-they-buildingand-why-6-questions-for-the-top-java-architects https://blogs.oracle.com/javamagazine/post/what-are-they-bui...
- throwaway234232 4y agoThis 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.
- 0xmarcin 4y agoThis will work, but will have poor performance due to the way Java generics are implemented. You could use your function with `Integer[]` or `Long[]` arrays but not with `int[]` or `long[]`. `Integer` being a wrapper class around `int` is a regular Java object accessible via reference, hence slow and memory-inefficient. On the other hand C# offers "real" generics and you can use almost exactly the code that you wrote (generic syntax is slightly different).
- red_admiral 4y agoIsn't the java problem that (a) the + operator is only defined for some built-in types, and (b) the int/Integer boxing distinction?
- throwaway234232 4y agoRight, you can't overload the + operator, and primitives can't be used in generics.
- kelseyfrog 4y agoyep, though a monoid isn't strictly necessary - a semigroup is sufficient for this use-case.