Introduce intermediate interface for integer numbers

It’d be useful to have an intermediate interface that integer number types could implement, like Int, Long and BigInteger. On the dual side, a common interface for floating point number types would also be useful, for Float, Double, BigDecimal, etc.

This would allow the compiler to make my life easier when I need an arbitrary length for a number, but I want a specific category.

Now I’m forced to overload some declarations, like

val Int.pennies: Pounds get() = Pounds(this.toBigInteger())
val Long.pennies: Pounds get() = Pounds(this.toBigInteger())
val BigInteger.pennies: Pounds get() = Pounds(pennies = this)

and it’d be great to be able to write instead

val IntegerNumber.pennies: Pounds = Pounds(this)

There are many more use cases for both integer number and floating point numbers.

1 Like

Probably you are talking about the shape classes.

Theoretically, they could be implemented as extensions for Long.Companion types.

I mean, potentially yes, but not necessarily. The issue with shape classes is that they’re not types, and as such they’re like pattern matching for generics, which is a great idea, but only half the deal. Here it’d be great to be able to accept a number without a floating part as a type, and have the compiler help you with that.

If this improvement is not deemed worthy enough of an ad-hoc solution, an alternative general way of solving this would be introducing union and intersection types.

So in this case I’d be able to write:

val Int|Long|BigInteger.pounds: Pounds get() = Pounds(this)

class Pounds(val amount: Int|Long|BigInteger)

or better, also with importable type aliases:

typealias IntegerNumber = Int|Long|BigInteger

val IntegerNumber.pounds: Pounds get() = Pounds(this)

class Pounds(val amount: IntegerNumber)

These 2 features, union & intersection types and importable type aliases would be a killer together, and can be used in so many ways. Also play great with dynamic casting, like:

val something: Float|Boolean|Double

if (something !is Boolean) {
   println(something.toBigDecimal())
} else {
  println(!something)
}