Numeric

Joe Darcy joe.darcy at oracle.com
Sun Sep 16 22:45:50 PDT 2012


On 9/14/2012 4:28 AM, Doug Lea wrote:
>
> Picking this up from a set of exchanges on old
> lambda-lib list, and first recycling initial rationale:
>
> The main reason for primitive specializations for bulk ops
> is to avoid boxing inside inner loops. Unless optimized away
> (which in practice is almost always too hard for compilers/JITs),
> not only is it slow to begin with, it doesn't get much
> faster under parallelism because it spews garbage and
> disrupts memory locality.
>
> The inner loop case is the most glaring problem, but the same
> issues arise during any combination/reduction/collection
> steps among a set of subtasks. As in
>   r = combine(leftTask.join(), rightTask.join());
> As well as client access of results, as in:
>   r = p.invoke(...)
> Depending on all sorts of things, these cases can be
> as numerous and problematic as the inner-loop case.
> Wishing that they weren't as problematic isn't a good solution.
>
> Long-term, we need primitive specialization of generics.  But shorter
> term, there's an intermediate solution that reduces both boxing and
> combinatorial explosions of special forms. The tradeoff is to accept
> some virtualness, plus a bit of tedium on the part of components
> implementing it:
>
> /**
>  * Interface defining access methods for classes that provide numeric
>  * results. A {@code Numeric} is not itself an instance of {@link
>  * java.lang.Number}, but provides numeric methods to access its
>  * primary result or property; normally via the method corresponding
>  * to the listed {@code PreferredType} parameter. However, any
>  * implementation of this interface must define the non-preferred
>  * methods as well (typically by casting the results of the
>  * preferred form).
>  */
> public interface Numeric<PreferredType extends Number> {
>     long getLong();
>     int getInt();
>     short getShort();
>     byte getByte();
>     double getDouble();
>     float getFloat();
> }
>
> So for example, someone could define
>   class MyFutureDouble implements Future<Double>, Numeric<Double>;
> which could then be used as
>   f = new MyFutureDouble();
>   // .. async process f ...
>   double d = f.getDouble();
>
> This is a slightly odd interface because the PreferredType parameter
> exists just to communicate the preferred extraction method to
> client programmers. Looking ahead though, it might also serve as a
> heuristic guide for future efforts on automated generics specialization.
>
> The required tedium is that any class implementing Numeric
> will need to boringly implement five of the methods in terms
> of the one version corresponding to the preferred type. For

One quick observation on this API, the bound "PreferredType extends 
Number" does not limit the preferred value to one of the boxed 
primitives java.lang.{Integer, Long, Double, ...} since even in the JDK 
there are other classes which extend java.lang.Number, for example 
BigDecimal and AtomicInteger.  The Number type as it stands basically 
means "is convertible to a primitive" and capturing that capability 
would have been more appropriately modeled as an interface than an 
abstract class.

Unfortunately, I don't see a way to model "A Number subclass limited to 
these six choices" in the type system without adding a new type for that 
purpose:

public abstract class NumericBox extends Number {
     protected NumericBox() {...} // Don't allow instantiation outside 
of java.lang
}

and changing the wrapper classes in java.lang to extend NumericBox 
(probably with a better name) rather than Number.

-Joe



More information about the lambda-libs-spec-observers mailing list