Given:
case class Person(name: String)
and trying to do:
scala> List(Person("Tom"), Person("Bob")).sorted
results in a complaint about missing Ordering.
<console>:8: error: could not find implicit value for parameter ord: Ordering[Person]
List(Person("Tom"), Person("Bob")).sorted
However this:
case class Person(name: String) extends Ordered[Person] {
def compare(that: Person) = this.name compare that.name }
works fine as expected:
scala> List(Person("Tom"), Person("Bob")).sorted
res12: List[Person] = List(Person(Bob), Person(Tom))
although there's no Ordering or implicits involved.
Question #1: what's going on here? (My money is on something implicit...)
However, given the above and the fact that this:
scala> Person("Tom") > Person("Bob")
res15: Boolean = true
works, and that also this:
scala> List(Some(2), None, Some(1)).sorted
works out of the box:
res13: List[Option[Int]] = List(None, Some(1), Some(2))
I would expect that this:
scala> Some(2) > Some(1)
would also work, however it does not:
<console>:6: error: value > is not a member of Some[Int]
Some(2) > Some(1)
Question #2: why not, and how can I get it to work?
If you install the slightly-too-magical-for-default-scope bonus implicits, you can compare options like so:
scala> import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
scala> def cmpSome[T: Ordering](x: Option[T], y: Option[T]) = x < y
cmpSome: [T](x: Option[T], y: Option[T])(implicit evidence$1: Ordering[T])Boolean
The import gives you an implicit from an Ordering to the class with the infix operations, so that it's enough to have the Ordering without another import.
Concerning your first question: Ordered[T] extends Comparable[T]. The Ordering companion object provides an implicit Ordering[T] for any value that can be converted into a Comparable[T]:
implicit def ordered[A <% Comparable[A]]: Ordering[A]
There is no implicit conversion A : Ordering => Ordered[A] - that's why Some(1) > Some(2) will not work.
It is questionable if it is a good idea to define such a conversion as you may end up wrapping your objects into Ordered instances and then create an Ordering of that again (and so on...). Even worse: you could create two Ordered instances with different Ordering instances in scope which is of course not what you want.
The definition of List's sorted method is:
def sorted [B >: A] (implicit ord: Ordering[B]): List[A]
So yes, implicit things are happening, but many classes in the standard library have implicit objects associated with them without you having to import them first.
The Ordering companion object defines a bunch of implicit orderings. Among these is an OptionOrdering and IntOrdering, which helps explain the ability of a list to call sorted.
To gain the ability to use operators when there is an implicit conversion available, you need to import that object, for example:
def cmpSome(l:Option[Int], r:Option[Int])(implicit ord:Ordering[Option[Int]]) = {
import ord._
l < r
}
scala> cmpSome(Some(0), Some(1))
res2: Boolean = true
To answer your second question, why can't you do this: Some(2) > Some(1)
You can, with an import and working with Option[Int] rather than Some[Int].
# import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
# Some(2) > Some(1) // doesn't work
cmd11.sc:1: value > is not a member of Some[Int]
val res11 = Some(2) > Some(1)
^
Compilation Failed
# (Some(2): Option[Int]) > (Some(1): Option[Int]) // Option[Int] works fine
res11: Boolean = true
# Option(2) > Option(1)
res12: Boolean = true
# (None: Option[Int]) > (Some(1): Option[Int])
res13: Boolean = false
In practise your types will probably be of Option[Int] rather than Some[Int] so it won't be so ugly and you won't need the explicit upcasting.
I assume you understand why sorted does not work when you do not pass in an Ordering and none is available in scope.
As to why the sorted function works when you extend your class from Ordered trait. The answer is that when you extend from Ordered trait, the code type checks as the trait contains function like <,> etc. So there is no need to do implicit conversion and hence no complains about the missing implicit Ordering.
As for your second question, Some(2) > Some(1) will not work because Some does not extend the trait Ordered, neither does there seem to be any implicit function in scope that implicitly converts a Some to something that has the function >
Thanks for a detailed question with examples.
My answer is based what I learnt from a great article here: http://like-a-boss.net/2012/07/30/ordering-and-ordered-in-scala.html
All credit to the author here.
Quoting the article:
Coming back to our Box example - the scala library defines an implicit conversion between Ordered[T] and Ordering[T] and vice-versa.
The companion object of Ordered in https://github.com/scala/scala/blob/2.12.x/src/library/scala/math/Ordered.scala provides the required conversion here:
/** Lens from `Ordering[T]` to `Ordered[T]` */
implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] =
new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
However the reverse conversion isn't defined and I am not sure why?
Related
I want to write a method, which returns None if a collection is empty and Some(collection) in other case.
Best I can get is
implicit class CollectionExtensions[A, Repr](self: TraversableLike[A, Repr]){
def toOption: Option[Repr] = if (self.nonEmpty) Some(self.asInstanceOf[Repr]) else None
}
But casting .asInstanceOf[Repr] seems wrong. What is the correct way?
Here are some other approaches you can use in addition to #dk14 answer:
Use an implicit class for Repr with TraversableOnce[A]. This will also support Iterator, because Iterator extends TraversableOnce, but not TraversableLike.
implicit class CollectionExtensions[A, Repr](val self: Repr with TraversableOnce[A]) extends AnyVal {
def toOption: Option[Repr] = if (self.nonEmpty) Some(self) else None
}
Use an implicit class just for Repr, but request evidence that it's implicitly convertible to Traversable. This approach also supports Arrays and Strings, because they don't extend Traversable at all, but are implicitly convertible to it.
implicit class CollectionExtensions[Repr](val self: Repr) extends AnyVal {
def toOption[A](implicit ev: Repr => TraversableOnce[A]): Option[Repr] = {
val traversable = ev(self)
if (traversable.isEmpty) None else Some(self)
}
}
Both of those approaches preserve the original type:
scala> List(1, 2, 3).toOption
res1: Option[List[Int]] = Some(List(1, 2, 3))
scala> Iterator(1, 2, 3).toOption
res2: Option[Iterator[Int]] = Some(non-empty iterator)
scala> Array.empty[Int].toOption
res3: Option[Array[Int]] = None
scala> Map(1 -> 2).toOption
res4: Option[scala.collection.immutable.Map[Int,Int]] = Some(Map(1 -> 2))
scala> "123".toOption
res5: Option[String] = Some(123)
scala> "".toOption
res6: Option[String] = None
In order to recover original Repr type, you can use self.repr (scaladoc)
implicit class CollectionExtensions[A, Repr](self: TraversableLike[A, Repr]){
def toOption: Option[Repr] = if (self.nonEmpty) Some(self.repr) else None
}
If you would just stick with Option[TraversableLike[A, Repr]] as #chengpohi's answer suggests, operations like map on it (list.toOption.map(_.map(x => x))) would return you Option[Traversable[T]] loosing the original Repr type (like List[Int]). repr helps with that:
def repr: Repr
The collection of type traversable collection underlying this
TraversableLike object. By default this is implemented as the
TraversableLike object itself, but this can be overridden.
However, the funny thing is, if you look at repr's code (here):
def repr: Repr = this.asInstanceOf[Repr]
It does same thing, but at least it wrapped (hidden?) nicely in scala-library and more abstract, so by using it you could account for potential redefinitions.
Also, it worth mentioning that this non-empty-collection approach is popular in scalaz/cats:
scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._
scala> List(1, 2, 3).toNel
res8: Option[scalaz.NonEmptyList[Int]] = Some(NonEmptyList(1, 2, 3))
scala> nil[Int].toNel
res9: Option[scalaz.NonEmptyList[Int]] = None
toNel here means toNonEmptyList, so it's not as abstract as your solution. Cats have OneAnd[A,Repr] and some helpful implicits. See http://typelevel.org/cats/datatypes/oneand.html
This question already has answers here:
How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?
(11 answers)
Closed 6 years ago.
I'm tying to write a generic function that will convert any type to Option[T]
but somehow it's not working as expected
scala> def toOption[T](obj:Any):Option[T] = obj match {
| case obj:T => Some(obj)
| case _ => None
| }
<console>:11: warning: abstract type pattern T is unchecked since it is eliminated by erasure
case obj:T => Some(obj)
^
toOption: [T](obj: Any)Option[T]
here it's seems ok it return the Option[String]
scala> toOption[String]("abc")
res0: Option[String] = Some(abc)
but here it return Some(def) instead of None
scala> toOption[Int]("def")
res1: Option[Int] = Some(def)
i can't seem to figure the appropriate way to create this generic function ,nor to understand why is that happens, I've already read many posts and questions about type erasure in scala but still can't get it, specific explanation would be a great help!
The type T is not available at runtime because Scala uses type erasure for generics like Java does. So your test case obj:T has not the desired effects and the compiler warned you about that fact.
You may use ClassTags to make the type information available at runtime. ClassTag already implements the conversion to Optional in its unapply method:
scala> import scala.reflect.{classTag,ClassTag};
import scala.reflect.{classTag, ClassTag}
scala> def toOption[T: ClassTag](obj: Any): Option[T] = classTag[T].unapply(obj);
toOption: [T](obj: Any)(implicit evidence$1: scala.reflect.ClassTag[T])Option[T]
scala> toOption[Int](1)
res1: Option[Int] = Some(1)
scala> toOption[String](1)
res2: Option[String] = None
scala> toOption[String]("one")
res3: Option[String] = Some(one)
scala> toOption[Int]("one")
res4: Option[Int] = None
But this doesn't work for generic types as you see here:
scala> toOption[List[Int]](List("one", "two"))
res5: Option[List[Int]] = Some(List(one, two))
scala> res5.get
res6: List[Int] = List(one, two)
scala> res6(0) + res6(1)
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
... 29 elided
You might want to have two type arguments of the function - the desired type and the actual type:
def toOption[Desired, Actual](obj:Actual):Option[Desired] = ???
And then, I guess, you want to return Some only if the types match:
def toOption[Desired, Actual](obj:Actual)
(implicit ev: Actual =:= Desired = null):Option[Desired] =
if(ev == null)
None
else
Some(ev(obj))
Here you have two type arguments, that might be inconvenient sometimes, when Scala cannot infer both of the arguments. For the same syntax as you used (giving single type argument), you may use the following trick:
class toOptionImpl[Desired] {
def apply[Desired, Actual](obj:Actual)
(implicit ev: Actual =:= Desired = null):Option[Desired] =
if(ev == null)
None
else
Some(ev(obj))
}
def toOption[Desired] = new toOptionImpl[Desired]
It might be used the same way:
toOption[String]("def") == Some("def")
toOption[Int]("def") == None
(You might also look into Miles Sabin's polymorphic functions https://milessabin.com/blog/2012/04/27/shapeless-polymorphic-function-values-1/, https://milessabin.com/blog/2012/05/10/shapeless-polymorphic-function-values-2/)
This seems like a simple question that I was sure have been asked before, but couldn't find what I was looking for.
How can one write a function that takes a collection as an argument (or anything that can be treated as a collection), perform some operations on it, and return a collection of the same type?
e.g:
scala> def foo[Repr <% Traversable[String]](repr: Repr) = repr.map(_.size)
foo: [Repr](repr: Repr)(implicit evidence$1: Repr => Traversable[String])Traversable[Int]
this works ok on some collections:
scala> foo(Vector("Hello","World"))
res0: Traversable[Int] = Vector(5, 5)
but surprising when I tried on other collections (e.g. Option):
scala> foo(Some("HelloWorld"))
res1: Traversable[Int] = List(10)
a small problem is the return type Traversable, which ideally would be the type of whatever was given to the method. the bigger problem is the actual implementation type: an Option became a List.
it gets even worse, when tried on classes (that behaves like collections) but have no implicit in scope for them. e.g: Try:
scala> import scala.util._
import scala.util._
scala> foo(Success("HelloWorld"))
<console>:12: error: No implicit view available from scala.util.Success[String] => Traversable[String].
foo(Success("HelloWorld"))
^
So, is there a way, to write a generic function, that when given a "collection like" argument, can operate on it's elements and return the correct type?
ideally, I would like to use it on anything (even Future, and Try) , but for my specific usage, I can do with just real collections & Option.
EDIT:
to illustrate a possible solution, (which forces me to copy&paste code, and so, is not what i'm looking for) is to simply write both functions without view bounds:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def foo[Repr <: Traversable[String]](repr: Repr) = repr.map(_.size)
def foo(repr: Option[String]) = repr.map(_.size)
// Exiting paste mode, now interpreting.
foo: [Repr <: Traversable[String]](repr: Repr)Traversable[Int] <and> (repr: Option[String])Option[Int]
foo: [Repr <: Traversable[String]](repr: Repr)Traversable[Int] <and> (repr: Option[String])Option[Int]
scala> foo(Vector("bar"))
res2: Traversable[Int] = Vector(3)
scala> foo(Some("bar"))
res3: Option[Int] = Some(3)
The concept of mapping is represented by functors. One way to easily provide functor implementations for common classes is to use the scalaz library:
import scala.language.higherKinds
import scalaz.Functor
import scalaz.Scalaz._
def foo[El <: String, Coll[_]](repr: Coll[El])(implicit ev: Functor[Coll]) =
repr.map(_.size)
Now, this just works for List, Vector and Future:
scala> foo(Vector("Hello","World"))
res1: scala.collection.immutable.Vector[Int] = Vector(5, 5)
scala> foo(List("Hello","World"))
res2: List[Int] = List(5, 5)
scala> import scala.concurrent.Future
scala> import scala.concurrent.ExecutionContext.Implicits.global
scala> foo(Future("HelloWorld")) andThen PartialFunction(println(_))
Success(10)
Using it with Some is a bit of a problem, because only Option has a Functor implementation, not Some:
scala> foo(Some("HelloWorld"))
<console>:12: error: could not find implicit value for parameter ev: scalaz.Functor[Some]
foo(Some("HelloWorld"))
^
So you have to provide Option instead of Some to foo:
scala> foo(Some("HelloWorld"): Option[String])
res3: Option[Int] = Some(10)
scala> foo(Option("HelloWorld"))
res4: Option[Int] = Some(10)
scala> foo("HelloWorld".some) // This is from scalaz
res5: Option[Int] = Some(10)
And scalaz doesn't have any typeclass implementations for Try, so if you want to use Functor with Try, you'll have to provide the implementation yourself:
import scala.util.Try
import scalaz.Functor
implicit object TryIsFunctor extends Functor[Try] {
def map[A, B](fa: Try[A])(f: A => B): Try[B] = fa map f
}
Then foo will work with Try, but similar to Option, the argument should have the type Try, instead of Success or Failure:
scala> foo(Try("HelloWorld"))
res9: scala.util.Try[Int] = Success(10)
Also, I believe, there are no Functor implementations in scalaz for more general collection types, like Iterable or Seq.
Out of the common higher-order functions Functor only supports map. So to use flatMap and filter you have to provide different typeclasses instead of Functor. For example, scalaz.Monad supports map and flatMap, and scalaz.MonadPlus supports map, flatMap and filter.
And if you don't want to use scalaz, you'd probably have to make something very similar yourself with typeclasses, to get a good result type instead of Traversable. For example, using CanBuildFrom from the standard library.
I do think Kolmar is right about the general problem, but Scala does support duck-typing, so you can do this:
def foo[T[V]](duck: {def map[U](value: String=>U): T[_]}) ={
duck.map(_.size)
}
foo(Vector("bar")).toVector //> res0: Vector[_$2] = List(3)
foo(Some("bar")) //> res1: Option[_$2] = Some(3)
(toVector just to force the eval of the iterator that otherwise results)
Why does each None (of different Option types) evaluate to true?
scala> val x: Option[String] = None
x: Option[String] = None
scala> val y: Option[Int] = None
y: Option[Int] = None
Both x and y are Option's of separate types, yet their None's equal each other.
scala> x == y
res0: Boolean = true
Why?
Without looking at the actual implementation, I would assume that None is actually a case object. Hence, there is exactly one None in your memory. So both are the same thing. And identity obviously implies equality.
As to the question, why you can actually compare the two: This is due to Scala's subtyping: Every Object has an equals method, and this method is what you are using with the == operator.
edit: I found the implementation On github you can see, that None is indeed a case object. There also is no equals() method, so you are using the one which is automatically generated for case classes. Hence the comment below about type erasure also applies to your Some() case.
And 1 == "string" returns false. Standard equality check in Scala is not type safe, i.e:
final def ==(arg0: Any): Boolean
If you want typesafety use === with Equal Typeclass from scalaz.
There are really two questions here:
Why does x == y typecheck in your REPL?
Why do they equal each other?
x == y compiles because == in Scala is not type safe:
scala> "x" == 1
res4: Boolean = false
So why do they equal each other? An Option in Scala is conceptually similar to an Algebraic Data Type in Haskell:
data Maybe a = Nothing | Just a
But if you look at the Option.scala source, you'll see that an Option is defined (simplifying somewhat) as:
sealed abstract class Option[+A] extends Product with Serializable
final case class Some[+A](x: A) extends Option[A]
case object None extends Option[Nothing]
On the Some side, you can see a case class with parameterized type +A - so a someish Option[Int] becomes Some[Int].
However, on the None side, you see an Option[Nothing] object, so a noneish Option[Int] and a noneish Option[String] both become an Option[Nothing] object, and hence equal each other.
As #TravisBrown points out, Scalaz catches this much earlier, at compile time:
scala> import scalaz._
scala> import Scalaz._
scala> val x: Option[String] = None
scala> val y: Option[Int] = None
scala> x === y
<console>:16: error: could not find implicit value for parameter F0: scalaz.Equal[Object]
x === y
scala> val z: Option[String] = None
scala> x === z
res3: Boolean = true
Option is (roughly speaking) implemented like this:
trait Option[+A]
case class Some[A](value: A) extends Option[A]
case object None extends Option[Nothing]
Because None is an object, (a singleton in java terms), there's only one instance of it, and because Nothing is at the very bottom of the type hierarchy, meaning it's a subtype of EVERY type in Scala (even null), the two Nones are effectively the same type
I have the following use case which occurs often in my code:
A Collection[A]
An implicit conversion A to B
and I want to obtain a collection of B. I can use implicitly like the following:
case class Items(underlying:List[B])
import B._
def apply(a:List[A]):Items = {
val listOfB= a.map {implicitly[A=>B]}
Items(listOfB)
}
What is the most elegant way to do that in Scala, maybe with the help of Scalaz of doing the same?
Edit: the goal of my question is to find an idiomatic way, a common approach among libraries/developers. In such a sense developing my own pimp-my-library solution is something I dislike, because other people writing my code would not know the existence of this conversion and would not use it, and they will rewrite their own. I favour using a library approach for this common functions and that's why I am wondering whether in Scalaz it exists such a feature.
It's pretty straightforward if you know the types. First implicit conversion from A to B:
implicit def conversion(a: A): B = //...
then you need implicit conversion from List[S] to List[T] where S and T are arbitrary types for which implicit conversion from S to T exists:
implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] =
input map c
This should then work:
val listOfA: List[A] = //...
val listOfB: List[B] = listOfA
which is resolved by the compiler to:
val listOfB: List[B] = convList(listOfA)(conversion)
where S is A and T is B.
I wouldn't use an implicit conversion here, but a view bound in the class:
case class Foo(x: Int)
case class Bar(y: Int)
implicit def foo2Bar(foo: Foo) = Bar(foo.x)
case class Items[A <% Bar](xs: List[A]) {
def apply(x: Int): Bar = xs(x)
}
You can now create an instance of Items with a list of Foo and internally use them, as if they were Bars.
scala> Items(List(Foo(1)))
res8: Items[Foo] = Items(List(Foo(1)))
scala> res8(0)
res9: Bar = Bar(1)
edit:
Some clarification, on why I would not use an implicit conversion:
Implicit conversions can be dangerous, when they are in scope and accidentally convert things, that they shouldn't convert. I would always convert stuff explicitly or via view bounds, because then I can control it, also implicit conversion may shrink the size of your code, but also makes it harder to understand for others. I would only use implicit conversion for the 'extend my library' pattern.
edit2:
You could however add a method to the collection types, that does this conversion, if such a method is in scope:
trait Convertable[M[A], A] {
def convertTo[B](implicit f: A => B): M[B]
}
implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] {
def convertTo[B](implicit f: A => B) = xs.map(f)
}
scala> implicit def int2String(x: Int) = x.toString
int2String: (x: Int)String
scala> List(1,2,3).convertTo[String]
res0: List[String] = List(1, 2, 3)
Instead of using another implicit conversion here, I would probably use a typeclass instead, but I think you get the basic idea.
Works starting with Scala 2.10:
implicit class ListOf[A](val list: List[A]) {
def of[B](implicit f: A => B): List[B] = list map f
}
implicit def int2String(i: Int) = i.toString
// Usage
List(1,2,3).of[String]
In my code, I'm using a more general version adapted from Tomasz' solution above which handles all Traversable instances
/** Implicit conversion for Traversable instances where the elements are convertable */
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] =
(input map c).asInstanceOf[I[T]]
(This is working for me, although I'm keen to know if any more experienced Scala programmers think this is a bad idea for any reason, apart from the usual caveats about implicit conversions)