Unpack primitive types by default in data

Johan Tibell johan.tibell at gmail.com
Fri Feb 17 19:13:31 CET 2012

On Fri, Feb 17, 2012 at 2:42 AM, Jean-Marie Gaillourdet
<jmg at gaillourdet.net> wrote:
> Actually, there are two types for every primitive type in Java:
> int / java.lang.Integer
> byte / java.lang.Byte
> char / java.lang.Char
> float / java.lang.Float
> double / java.lang.Double
> ...

We have the same split in Haskell, but our spelling is a bit funny:

{-# UNPACK #-} !Int / !Int
{-# UNPACK #-} !Word8 / !Word8

> Starting with Java 5, javac automatically boxes / unboxes between a primitive type and its corresponding reference type. I.e. the programmer still specifies how a value is stored. This autoboxing simply makes them assignment compatible. As far as I understand it, auto boxing was introduced in order to better integrate primitive types with generics, not as an optimization. And I doubt that it is an optimization on average.

Sure, introducing autoboxing isn't an optimization in Java. Java
programmers were manually boxing values before putting them into data
structures before the introduction of autoboxing. What I'm saying is
that if we switch to a scheme were we automatically unpack fields by
default, we get to a situation which operationally is very similar to
the Java one: every time you stick an (automatically unpacked) field
into a polymorphic data structure you get autoboxing, but otherwise
you work with an unpacked field. Here's an example showing the
operational similarities if this proposal was accepted:


    class Vec3 {
        public Vec3(int x, int y, int z) { ... }
        public int x;  // you'd rarely see Integer here!
        public int y;
        public int z;

    Vec3 v = new Vec3(1,2,3);

    // No indirection overheads for many common operations:
    public Vec3 sum(Vec3 v1, Vec3 v2) {
        return new Vec3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);

    // Autoboxing when used with polymorphic data types
    HashMap<String, Integer> m = new HashMap<String, Integer>();
    m.put("key", v.x);  // autoboxing happens here: Int -> Integer


    data Vec3 = Vec3 { x :: !Int, y :: !Int, z :: !Int }  --
represented as Int# Int# Int#

    let v = Vec3 1 2 3

    -- No indirection overheads for many common operations:
    sum :: Vec3 -> Vec3 -> Vec3
    sum (Vec3 x1 y1 z1) (Vec3 x2 y2 z2) = Vec3 (x1+x2) (y1+y2) (z1+z2)

    -- Autoboxing when used with polymorphic data types
    let m = Map.empty
    let m' = Map.insert "key" (x v)  -- reboxing happens here: Int# -> Int

> I think, It might still be a good idea to realize Johann's proposal. I am just cautious whether Java really shows that this is a good idea.

Java doesn't show that boxing is good, but I think it does show that
never using primitive fields is worse that sometimes reboxing.


More information about the Glasgow-haskell-users mailing list