To relax the overloaded meaning of _ just a bit, it would make sense to at some point in the future disallow assignments such as val x: String = _ andvar x: String = _.
In some cases the assignment promotes mistakes, like with var perhaps: Option[String] = _, while non-reference types should be initialized with a meaningful value. var counter: Int = _ is just as long as var counter: Int = 0 but the latter just makes more sense.
.NET has a good answer for this, that Scala use for inspiration. default
Scala could have
case class Default[A](value: A)
object Predef {
def default[A](implicit instance: Default[A]): A = instance.value
}
object Int {
val default: Default[Int] = Default(0)
}
object AnyRef {
val default: Default[AnyRef] = Default(null)
}
And _ would just be the same as default. Scalac would be able to remove calls to default when the JVM would already initialize a value to the correct value, e.g. for references or values. For more complicated types, you could have
Sure, you can implement that today. Something like
trait Default[A] {
def value: A
}
// Predef.scala
@inline implicit def default[A](implicit d: Default[A]): A = d.value // transparent/opaque or whatever it's called in Scala 3
implicit object IntDefault extends Default[Int] {
val value: Int = 0
}
implicit def AnyRefDefault[A <: AnyRef] = new Default[A] {
val value: A = null.asInstanceOf[A]
}
// Elsewhere.scala
var x = default[Int] // 0: Int
var y = default[String] // null: String
Point being, it doesn’t make much sense to build up the type hierarchy only to let _ be hardwired to default[T] in this specific scenario (and have a several meanings in other places).
The examples don’t account for the change in semantics, as underscore really means the default and is not an assignment. That’s why I would prefer “self-assignment” as an idiom, if I were to use it, because it explicitly means “whatever value it has”. Maybe default initializers could be specified to be ordered before other constructor statements.
scala 2.13.0-M4> class C { var c: Int = _ }
defined class C
scala 2.13.0-M4> new C().c
res0: Int = 0
scala 2.13.0-M4> class C { c = 42 ; var c: Int = _ }
^
warning: Reference to uninitialized variable c
defined class C
scala 2.13.0-M4> new C().c
res1: Int = 42
scala 2.13.0-M4> class C { c = 42 ; var c: Int = 0 }
^
warning: Reference to uninitialized variable c
defined class C
scala 2.13.0-M4> new C().c
res2: Int = 0
scala 2.13.0-M4> class C { c = 42 ; var c: Int = c }
^
warning: variable c in class C does nothing other than call itself recursively
^
warning: Reference to uninitialized variable c
defined class C
scala 2.13.0-M4> new C().c
res3: Int = 42
I found that scalaz has a Default, although it’s only for testing.
@som-snytt That’s interesting about the semantics of _ and the ordering of assignment and declaration in the constructor.
For now anyway, if someone wants fancier notion of default, it’s certainly possible now, and it’s not difficult. It’s perfectly good to not have it baked into the language.
I don’t think default values for types are sound. Surely what we need is to be able to annotate operations (methods) as monoids, and give the operation an identity value.
I just don’t think this relatively uncommon case deserves special syntax. I’ve seen people often argue that _ has too many meanings today; this would reduce that count by 1.
Yeah, agreed. This isn’t used much that I’ve seen; it’s another overload of _; it causes more than its fair share of confusion among newbies; and it can easily introduce bugs if you don’t know what you’re doing. I think it’s one of those places where the language got a little too “clever”, and would benefit from dropping it.
Using underscore as a default initializer is an anti-pattern. If the type is known to be AnyRef or some AnyVal subtype, we can just put the desired value directly; if not, it won’t work anyway.
I guess it was invented to support things like this:
class VaribleBox[T] {
var value:T = _
}
new VaribleBox[Int].value //0
new VaribleBox[String].value //null
maybe something like this would be enough:
//instead of this
val c:T = _
//we could chose one of those
val c:T = Any.default[T] // don't like this one. Name default could be misleading
val c:T = Any.emptyOf[T]
val c:T = Any.emptyValue[T]
val c:T = Null.valueFor[T]
I guess this could be introduced even in 2.13 and old notation could be simply deprecated. This is rather not popular feature.
Default/Empty typeclass
proposal to add Default or Empty typeclass or method somwhere in standard library seams to satisfy all users needs, but it needs to be carefully implemented.
assume that there should be implicit val default ....
This is to limited i guess! This pollutes user-space to much and does not give any flexibility! Default/Empty typeclass if introduced should give something more than simple null!
It could be implemented as something that provides instances for simple types
trait Default[T] {def get():T }
object Default {
def apply[T](a:T) = new Default[T] { def get():T = a }
implicit val intDefault = apply(0)
implicit val doubleDefault = apply(0)
implicit val stringDefault = apply("")
...
}
and’ll generate instances for anything that have default constructor or apply() method on companion object (this cannot be representet typesafely in current scala as i know).
For types that has nothing like that it’ll just not compile. Not sure now where it could be needed (and this is sign that probably we should ignore this idea).
Okay, now I have to chime in. I consider it critical that we be able to get a default value for a type parameter in a way that is accessible for fairly novice coders. I don’t care exactly what it is. I’m fine with var default: A = _ or null.instanceOf[A], or something else that takes about that much code. The reason is that there are data structures that are taught in early semesters of CS that really benefit from having a default value. The most obvious example is the sentinel node in a doubly-linked list. Any proposal that makes this more difficult would have a negative impact on the teachability of Scala in early CS courses.
As long as that doesn’t change, I’m good. I don’t really care exactly how I get a default value for a type parameter as long as there is always a simple way to do it that I can explain fairly easily to students.
I really don’t see the need for the language to change. If you want different behavior than _, what are you wanting that can’t be had from a library? I really recommend that anyone who is serious about getting an alternative to _ first use a library. I published mine to Maven Central and you’re free to fork it and play with it.