Summary
Erik Engbrecht discusses a new numeric library for Scala that provides typesafe, mathematically correct number types that also perform well.
Advertisement
While Java has several numeric libraries that Scala code can easily invoke, Erik Engbrecht felt that a Scala-specific numeric library could provide a more type-safe environment for working with all sorts of number types. In a recent blog post, Typesafe Ranged Integers in Scala, Engbrecht discusses the beginnings of such a library, which he is contributing to the open-source Scalax project:
My goal is to create an extensible, type-safe library that provides numeric types that are easy to use and more closely resemble their mathematical foundations than the primitive operations on which they are built. My initial focus has been on building a working rational numbers implementation with unlimited precision integers.
In the post, Engbrecht explains the problems of representing integer types in standard Scala code, and how his numeric library provides a more type-safe integer representation that accounts for over- and underflow of values:
The standard Java/Scala integer type is a 32-bit twos-complement signed integer. That means it can representing numbers between 2147483647 and -2147483648 inclusive. Often times this is plenty range, so what we really want is for exceptions to be thrown when underflow and overflow... Between the usage of an object instead of a primitive and all this extra work for range checking, this class is probably at least an order-of-magnitude slower that using primitive Ints.
The way it works [in this new library]... is that it converts the 32-bit integers into 64-bit integers prior to calculations, performs the calculations, then checks the result to ensure that it is within range. If it is within range, then the result is converted back into a 32-bit integer and returned... In order to [consider bounded ranges], we simply create an object that extends Int32 and overrides its minimum and maximum value...
Engbrecht illustrates the use of this library with several examples.
What do you think of type-safe integer representations in Scala?
The thing that's great about this beyond it's obvious utility is that it's a really concrete and understandable example of the power of Scala to Java developers.
One thing I'm wondering is whether this could be morphed into a type that allows unbounded values but uses native ints internally unless and until their range is exhausted.
I think you could get the benefits of something like BigInteger with only a little more overhead than using ints for most cases. And to the developer, they get all the normal operators they expect to have for numbers.
BigInteger actually makes a fair amount of effort to use primitive operations wherever possible. You can't eliminate the object wrapper and the overflow detection, and both add a fair amount of overhead. From the research I've done over the past couple days, even using hardware overflow detection adds a significant amount of overhead.
That being said, a lot of interesting things don't simply involve primitive integers. For example, I think BigDecimal is rather awful. But in my system you can make all of that awfulness go away. It's still a lot slower than native floating point calculations, but IMHO doubles are a very leaky abstraction for reals.
Another interesting thing you can do is make the number types take advantage of multiple cores. A lot of calculations are fairly trivially parallelizable. You can also do things like lazy evaluation, reordering of operations, memoization, etc.
Anyway, I'm hoping that this will be: 1. A very useful, practical library 2. A good demonstration of advanced Scala concepts 3. Something that is almost as simple to use for application programmers as dynamically typed libraries in Python or mathematical languages like Maple and Mathematica.
What I meant by limiting the overhead is that you could have a type that was backed by the Int32 type until it overflowed and then was replaced with a more generic type. This would be seamless to the user. You are clearly right that the object overhead and the overflow detection overhead can not be eliminated. What I am getting at is that you could create a type that would be a hedge for processes that probably don't need more than 32 bit ints but can't rule it out.