Reputation: 831
In ruby it is possible to do it like so:
first ||= number
and first will get the value of number only if it is nil
How to do similar thing in scala?
So far I've come up with this and it doesn't look as nice as in ruby.
var first: Option[Int] = None
...
first = if (first == None) Option(number) else first
// or
first = Some(first.getOrElse(number))
Upvotes: 4
Views: 622
Reputation: 67280
I don't know why other poster deleted his answer, but I would go for the approach also suggested in the comments:
first = first orElse Some(number)
Upvotes: 3
Reputation: 16412
This is not the best practice or anything, but here is something similar you can do:
scala> implicit class RubyFriend[T](val value: Option[T]) extends AnyVal {
| def ||=(alt: T): Option[T] = value orElse Some(alt)
| }
defined class RubyFriend
scala> var something: Option[Int] = None
something: Option[Int] = None
scala> something = something ||= 5
something: Option[Int] = Some(5)
scala> something ||= 4
res11: Option[Int] = Some(5)
scala> (None: Option[Int]) ||= 3
res12: Option[Int] = Some(3)
We create an implicit conversion from Option
to RubyFriend
which has ||=
method. It's a pimp my library pattern. The only difference that it can't really assign to the original variable because in Scala assignment can't be overloaded as far as I know.
Overall try to avoid vars in Scala.
Here is another attempt to make it even more Ruby like:
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> implicit class RubyFriend[T](var value: Option[T]) {
| def ||=(alt: T): Unit = value = value orElse Some(alt)
| }
defined class RubyFriend
scala> implicit def ruby2Option[T](smth: RubyFriend[T]): Option[T] = smth.value
ruby2Option: [T](smth: RubyFriend[T])Option[T]
scala> var ropt: RubyFriend[Int] = None
ropt: RubyFriend[Int] = RubyFriend@2d483fef
scala> ropt.value
res0: Option[Int] = None
scala> val opt: Option[Int] = ropt
opt: Option[Int] = None
scala> ropt ||= 6
scala> ropt.value
res2: Option[Int] = Some(6)
scala> val opt: Option[Int] = ropt
opt: Option[Int] = Some(6)
scala> ropt ||= 7
scala> ropt.value
res4: Option[Int] = Some(6)
This makes a wrapper class around Option
and implicitly converts back and forth. At the same time an optional value is presented as mutable field (yikes).
These both examples are just to show what's possible in Scala not really a good way of doing it :).
A "refinement" of the first example as suggested by @senia:
scala> implicit class RubyFriend[T](val value: Option[T]) extends AnyVal {
| def ||(alt: T): Option[T] = value orElse Some(alt)
| }
defined class RubyFriend
scala> var something: Option[Int] = None
something: Option[Int] = None
scala> something ||= 5
scala> something
res1: Option[Int] = Some(5)
scala> something ||= 6
scala> something
res3: Option[Int] = Some(5)
Upvotes: 3
Reputation: 38045
There is a scalaz
operator for this:
import scalaz._, Scalaz._
none[Int] <+> 1.some
// Some(1)
2.some <+> 1.some
// Some(2)
You could use a <+>= b
instead of a = a <+> b
:
var i = none[Int] // i == None
i <+>= 1.some // i == Some(1)
i <+>= 2.some // i == Some(1)
See also Plus[F[_]] in scalaz cheatsheet.
For Option
plus
is implemented as orElse
.
For collections (List
, Vector
, Stream
, etc) Plus
is implemented as append
:
Vector(1, 2) <+> Vector(3, 4)
// Vector(1, 2, 3, 4)
I can't find a method to combine Option[T]
and T
in the way you want, but you could write such method like this:
implicit class PlusT[T, M[_]: Plus : Applicative](m: M[T]) {
def ?+?(t: T) = m <+> t.point[M]
}
none[Int] ?+? 1
// Some(1)
2.some ?+? 1
// Some(2)
var i = none[Int] // i == None
i ?+?= 1 // i == Some(1)
i ?+?= 2 // i == Some(1)
You could rename this method to ||
and use it like ||=
just like in Ruby
, but this name can confuse other developers - there is already method ||
for Boolean
.
Upvotes: 5