Hacker News new | ask | show | jobs
by enw 1446 days ago
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 `<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.

3 comments

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

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

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

Basically I'm encoding this approach in Java.