Reputation: 3758
According to the docs, None
object is intended to "represent non-existent values". As far as I've seen it's mostly used as an empty Option
. But do you think it's a good idea to use it for other purposes. For example, in my library I want to have an universal "Empty" object which could be assigned for various missing values, where I would just implicitly convert the "Empty" value to my types as needed:
// In library:
trait A {
implicit def noneToT1(none: Option[Nothing]): T1 = defaultT1
implicit def noneToT2(none: Option[Nothing]): T2 = defaultT2
def f1: T1
def f2: T2
}
// In the code that uses the library
class EmptyA extends A {
def f1 = None
def f2 = None
}
One reason for not (mis)using None
in this fashion is that the user would expect that f1
and f2
return Option[T1]
and Option[T2]
respectively. And they don't. Off course, I could have def f1: Option[T1]
, but in this case the values are not actually optional, they just can have some default empty value, or a real value, I just want to create the default values "under the hood" and have some uniform way of saying "default" or "empty" through the entire library. So the question is, should I use None
to express this "defaultness" or go for some custom type? Right now I'm using my own object Empty
, but it feels a bit superfluous.
EDIT: To ilustrate my question I'll add the code I am using right now:
// In library:
trait Empty
object Empty extends Empty
trait A {
implicit def emptyToT1(none: Empty): T1 = defaultT1
implicit def emptyToT2(none: Empty): T2 = defaultT2
def f1: T1
def f2: T2
}
// In the code that uses the library
class EmptyA extends A {
def f1 = Empty
def f2 = Empty
}
class HalfFullA extends A {
def f1 = Empty
def f2 = someValue2
}
class FullA extends A {
def f1 = someValue1
def f2 = someValue2
}
My question is quite simple: is it a good idea to use scala's None
instead of my Empty
?
Upvotes: 4
Views: 1542
Reputation: 4485
If you can't or don't want to define the default value using inheritance, I suggest to keep the new object. Reusing None
for something else than the Some
counterpart seems wrong and doesn't really save you much.
Upvotes: 1
Reputation: 29163
I would just use typeclasses for this:
trait WithDefault[T] {
def default: T
}
object WithDefault {
// if T1 is an existing class
implicit val t1Default = new WithDefault[T1] {def default = defaultT1}
}
//if T2 is your own class:
class T2 ...
object T2 {
implicit val withDefault = new WithDefault[T2] {def default = defaultT2}
}
then somewhere convenient:
def default[T : WithDefault] = implicitly[WithDefault[T]].default
and use:
class EmptyA {
def f1 = default[T1]
def f2 = default[T2]
}
Update: To accomudate Vilius, one can try this:
def default = new WithDefault[Nothing]{def default = error("no default")}
implicit def toDefault[U, T](dummy: WithDefault[U])(implicit withDefault: WithDefault[T]): T = withDefault.default
class EmptyA {
def f1: T1 = default
def f2: T2 = default
}
This has the benefit over the OP's original attempt in that each new class can define its own default (and others in WithDefault), rather than have everything in a trait A
.
However, this doesn't work. See https://issues.scala-lang.org/browse/SI-2046
To work around this:
trait A {
def f1: T1
def f2: T2
implicit def toT1Default(dummy: WithDefault[Nothing]) = toDefault[T1](dummy)
implicit def toT2Default(dummy: WithDefault[Nothing]) = toDefault[T2](dummy)
}
class EmptyA extends A {
def f1 = default
def f2 = default
}
Upvotes: 7
Reputation: 23056
I think you should go for something much simpler. For instance, starting with your example and deleting extraneous stuff we very quickly get to,
trait A {
def noT1 = defaultT1
def noT2 = defaultT2
def f1: T1
def f2: T2
}
class EmptyA extends A {
def f1 = noT1
def f2 = noT2
}
I really don't see that the addition of Options or implicits to this would add any value, at least not unless there's some other unstated context for the question.
Upvotes: 3