Skip to content

Get rid of = _ in variable definitions #11225

Closed
@odersky

Description

@odersky

An obscure use of _ occurs in var definitions:

var x: T = _

It defines a concrete variable x without an initial value, or rather the default initial value that the JVM assigns to object fields. It can only be used in a class or object, not to initialize a local variable. It is essential in situations like this:

new AbstractIterator[A] {
    private[this] var hd: A = _
    private[this] var hdDefined: Boolean = false
    ...
}

Here we cannot initialize hd with a value since its type is parametric, and we do not know a value for A. The logic in AbstractIterator makes sure that hd is read only after it is assigned by checking hdDefined before reading hd.

So the idiom is rare but essential where it is needed. But can we find a less obscure notation that does not add another overload to _?

One possibility would be to define somewhere an abstraction like this:

def defaultValue[T]: T = ...

defaultValue can be expressed in terms of _:

def defaultValue[T]: T = 
  object helper { var x: T = _  }
  helper.x

It can also be a compiler-intrinsic, and then it could replace = _ in variable definitions.

But I am a bit reluctant to do that, for fear that then defaultValue will be also used in situations where it is not appropriate. The big problem with defaultValue is that it returns null for all class types including boxed numeric types. That's very confusing! We do not want to give this a more prominent status than what we have. The situation would get worse with explicit nulls. In that case, we would have:

def defaultValue[T]: T | Null

But then

var x: T = defaultValue

would be ill-typed. It would have to be:

var x: T | Null = defaultValue

This is safe, but it defeats the purpose. What should happen for

var x: T = _

is that the programmer or the init-checker proves that x will be initialized with something else before it is first referenced. That's the intended meaning.

So, maybe a better choice is to re-use compiletime.erasedValue for this?

var x: T = erasedValue

This means there is no initial value at runtime (the value is erased), so there is no initial assignment. That can be allowed for objects and classes since objects are bulk-initialized (but the init checker should check that such variables are not referenced before being assigned to). It could be allowed in the future also for local variables if we can prove that the variable is initialized by assignment before use. Everywhere else erasedValue is illegal, by the current rules.

Admittedly, erasedValue is also obscure. However

  • The whole thing is an obscure use case
  • erasedValue can be looked up, unlike _
  • erasedValue does not add to the confusion relative to the other uses of _.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions