Optional field members

Hello,
I wanted to ask whether there is a sane way of getting optional member variables in traits / classes. The following fails:

class foo(var x:Unit)

yields with javap -p foo.class

public class foo {
  private scala.runtime.BoxedUnit x;
  public void x();
  public void x_$eq(scala.runtime.BoxedUnit);
  public foo(scala.runtime.BoxedUnit);
}

This is bad: Not every instance needs an object reference to Unit.

General context: What I want is something like

trait myType[@specialized(Unit, Int) OptionalMetadataT]{
  var payload:OptionalMetadataT
  //more stuff
} 

If I specialize on Int, then I save the box. Yay!

Now, how do I specialize on singletons in a way that doesn’t store a superfluous pointer in every instance?

Or am I supposed to represent Unit as a Boolean (at least cheaper than an object reference, depending on alignment padding)? Or am I supposed to specialize by hand (lots of boilerplate)?

What is the point of a having a Unit on a (mutable) variable?

Specialization is only effective for value types, which won’t use pointers. If you’re referencing singletons, then those are all reference types. Specialization has no meaning in that case.

What is the point of a having a Unit on a (mutable) variable?

For example, you can imagine something like

class Edge[NodeT, @specialized(Unit, Int) PropertyT](var src: NodeT, var dst:NodeT, var property: PropertyT)

Now I can use that class to represent edges in a graph with properties attached to each edge, and can write algorithms that work on that.

Well, most graphs don’t need properties on edges. No biggy, type PropertyT = Unit. Crucially, many algorithms and lots of code is still valuable for the case where PropertyT = Unit.

So I have a conundrum: (1) Write all code twice, once with and once without property handling, or (2) write the code only once, with property handing.

If the properties get specialized to a primitive type with only one value, and zero bytes of unboxed storage size, then this is a zero-cost abstraction.

Function parameters or fields that are statically known to be singletons are a very common pattern in e.g. C++ or julialang (sometimes called phantom values in the julia compiler).

And Unit is treated like a special type by scalac, note like a run-of-the-mill object: It is specialized like a value-type, and gives special signatures (like JVM return type void for the getters).

So I’m wondering what I need to do in order to get rid of this entirely superfluous waste of memory?

I know that java/scala supports template-style code specialization only to a very limited degree (primitives and generic java.lang.Object), but Unit is such a special case.

You can put the property in a trait to make it optional depending on the context.

trait HasProperty[Property] {
  var property: Property
}
class Edge[Node](var src: Node, var dst: Node)
class EdgeWithProperty[
  Node,
  Property
](src: Node,
  dst: Node,
  override var property: Property
) extends Edge[Node, Property](src, dst) with HasProperty[Property]

Although what I would do is

case class Edge[NodeT, PropertyT](var src: NodeT, var dst:NodeT, var property: PropertyT)

object Edge {
  def unit[NodeT](src: NodeT, dst: NodeT): Edge[NodeT, Unit] = Edge(src, dst, ())
}

unless a benchmark really showed me that removing the pointer is a big deal and it’s a common use case.

Beyond that, store the graph with edges and properties their own arrays, and the property array can be null, and then if that’s not good enough I wouldn’t be using the JVM.

1 Like