I've added experimental support for using value types and reference arguments in
Java. The challenge is to do this without having to build a new Java compiler.

Here is a value type I constructed in C# for testing purposes:

publicstruct ValType
{

publicint foo;

public ValType(int f)
{

foo
= f;

}

publicoverridestring ToString()
{

return "ValType:"
+ foo;

}

publicstaticvoid Increment(ref ValType
v) {

v.foo++;

}

}

Here is a Java example that uses value types and calls a method with a reference argument:

import system.DateTime;

class ValTest
{

static DateTime
dt;

publicstaticvoid main(String[]
args) {

ValType
v = new ValType(0);

v.foo
= 42;

System.out.println(v);

ValType[]
av = new ValType[1];

av[0]
= v;

ValType.Increment(av);

System.out.println(av[0]);

dt
= DateTime.get_Now();

DateTime
d = new DateTime(0);

d
= AddDay(d);

System.out.println(d);

System.out.println(dt);

}

privatestatic DateTime
AddDay(DateTime dt) {

return dt.AddDays(1);

}

}

How is this code compiled? Whenever a value type is loaded from a field or array,
instantiated or returned from a method it is boxed. Local variables are references
to boxed instances of the value type. When a boxed value type instance is assigned
to a field, stored in an array or passed to a method, it is unboxed. Referenced method
arguments are exported by NetExp as arrays.

Let's look at a few examples:

ValType
v = new ValType(0);

Is compiled as:

ldc.i4.0

newobjinstance
void ValType::.ctor(int32)

boxValType

stloc.0

The local variable v is of type object and
contains a reference to the boxed value.

v.foo
= 42;

Assigning a field in the boxed value:

ldloc.0

ldc.i4.s42

stloc.1

unboxValType

ldloc.1

stfldint32
ValType::foo

After loading the reference to the boxed value, the constant (42) gets stored
in a temporary local and then reference gets unboxed, this leaves a managed pointer
to the interior of the boxed value on the stack and the stfld instruction
uses this pointer to set the field.

av[0]
= v;

Setting an array element:

ldloc.2

ldc.i4.0

ldloc.0

stloc.3

ldelemaValType

ldloc.3

unboxValType

ldobjValType

stobjValType

The address of element 0 of the array is loaded, v is unboxed and copied into the
array.

ValType.Increment(av);

Calling a method with a reference argument:

ldloc.2

stloc.sV_4

ldloc.sV_4

ldc.i4.0

ldelemaValType

call
void ValType::Increment(valuetype ValType&)

The Java code passes an array and the byte code to CIL compiler takes the address
of the first element of the array and passes that to the method. BTW, if the array is
of length zero, ldelema throws
a System.IndexOutOfRangeException.

Pros and Cons of this Approach

The advantage of enabling value type of reference arguments are that it is easier
to leverage .NET framework code from within Java code (targetted at IKVM.NET) and
it enables me to write more glue code in Java.

The downside is the non-intuitive behavior. Compare these two lines:

v.foo
= 42;

av[0].foo = 42;

The first line does what you'd expect, it assigns 42 to the field foo of the boxed
value type. However, the second line has no effect, because it results in a boxed
copy being loaded from the array, that boxed copy's field foo is assigned the value
42, but it is not copied back into the array. This also applies to fields, only local
variables contain boxed value types and can be manipulated safely.

Finally, a small problem with arrays of value types is that the Java compiler will
happily compile:

Object[]
array = new ValueType[1];

Obviously this isn't legal.

I'd like to get feedback from people who either like or dislike this new
functionality. Of course, any ideas for alternative approaches would be most welcome
too.