Consider this piece of code
def foo(b: Int) = ???
val a = 3
foo(a)
It works fine of course, but let's say that later I decided that foo should support an empty input, so I change it's signature to
def foo(b: Option[Int]) = ???
Now foo(a) won't compile, because a isn't an Option[Int], it's an Int. So you have to say a = Some(3) or foo(Some(a)), which seems redundant to me.
My question is, why doesn't the language have an implicit conversion from T to Some[T] (and vice versa)?
Is it a good idea to implement one yourself?
Related
I'm trying to do some implicit magic in my code but the issue is very simple and I have extracted it out here. It seems a bit strange since from what I've read the following should work.
implicit class Foo(value: Double) {
def twice = 2*value
}
2.0.twice
implicit def strToDouble(x: String) = Try(x.toDouble) match {
case Success(d) => d
case Failure(_) => 0.0
}
strToDouble("2.0").twice
val a: Double = "2.0"
val b: Double = "equals 0.0"
"2.0".twice
I get a compile error
value twice is not a member of String
[error] "2.0".twice
I get you compiler, twice is defined for Doubles, not Strings. But I did tell you how to go from Strings to Doubles, and there is no ambiguity here (as far as I can tell), so shouldn't you be able to note that "2.0".twice can be done by doing strToDouble("2.0").twice?
Am I missing something here? Or is this an optimisation so that the compiler doesn't try out all the possible permutations of implicits (which would grow super-exponentially, I think as a factorial). I suppose I'm looking for a confirmation or rejection of this really.
Thanks
If you want extension method to be applicable even after implicit conversion, you can fix the definition of implicit class
implicit class Foo[A](value: A)(implicit ev: A => Double) {
def twice: Double = 2 * value
}
implicit def strToDouble(x: String): Double = ???
2.0.twice //compiles
"2.0".twice //compiles
I get you compiler, twice is defined for Doubles, not Strings. But I
did tell you how to go from Strings to Doubles, and there is no
ambiguity here (as far as I can tell), so shouldn't you be able to
note that "2.0".twice can be done by doing strToDouble("2.0").twice?
According to specification implicit conversions are applicable in three cases only
Why can't the compiler select the correct String.contains method when using this lambda shorthand?
https://scala-lang.org/files/archive/spec/2.13/07-implicits.html#views
The conversion of 2.0.twice to Foo(2.0).twice is the 2nd case and the conversion of "2.0" to strToDouble("2.0") is the 1st case. As you can see there is no item that they can be applied together. So if you want them to be applicable together you should specify that explicitly like I showed above.
Similarly if you defined conversions from A to B and from B to C this doesn't mean you have a conversion from A to C
case class A(i: Int)
case class B(i: Int)
case class C(i: Int)
implicit def aToB(a: A): B = B(a.i)
implicit def bToC(b: B): C = C(b.i)
A(1): B // compiles
B(1): C // compiles
// A(1): C //doesn't compile
I'm in the following situation. I would like a function to only be able to run in a given context. At the same time I would love to be able to compose these functions using the andThen syntax (It would just look much better in this case).
So here is a small example for a worksheet. I would love to be able to do it the second way.
implicit val iInt: Int = 2
def a(a: String)(implicit ctx: Int): String = a
def b(b: String)(implicit ctx: Int): String = b
val works = b(a("foo"))
val fails = a("foo") andThen b
The general question would probably be. How does one compose curried functions? But if somebody can meet the requirements described in the first paragraph I would also be interested.
This line works as you want with your definitions of a and b:
val worksToo = (a _ andThen b) ("foo")
a and b are transformed to functions (because there are not), then chained.
On many occasions I use parameters in form of the Option with None as default - like this:
def foo(bar:Option[String] = None)
This gets handy and allows me to easily omit nulls. However, if I do this, I need to change every invocation of the method to
foo(Some("bar"))
instead of simply
foo("bar")
This, however, looks a bit redundant, because it is obvious, that when I specify a value it is a full option. I'm pretty sure I can try to write some implicit converters to do such wrapping for me - unfortunately, I have no idea how.
Bonus - is this a sane thing to do? Is there any other way of dealing with a problem of "nullable" parameters?
I'll give you some options (pun intended).
Don't use an optional parameter, and instead use Option.apply. This is useful for when the parameter isn't necessarily optional, but you want to deal with possible null values being passed.
def foo(bar: String): ?? = Option(bar)... // operate on the Option[String]
The advantage of this is that Option.apply automatically converts null to None for you, so there's absolutely no need to use if/else.
Use an overload for non-optional parameters. This is more so for when the parameter is truly optional, but gives you the convenience of passing Option wrapped or unwrapped. It won't be possible to pass null here without knowing the type first, however.
def foo(bar: String): ?? = foo(Option(bar))
def foo(bar: Option[String]): ?? = ???
Example:
def foo(bar: String): Option[String] = foo(Option(bar))
def foo(bar: Option[String]): Option[String] = bar.map(_ + "aaa")
scala> foo("bbb")
res7: Option[String] = Some(bbbaaa)
scala> foo(null: String) // The String ascription is necessary here.
res9: Option[String] = None
scala> val str: String = null
scala> foo(str) // No ascription necessary, since we know the type.
res10: Option[String] = None
Implicitly convert anything to Option.
implicit def any2Opt[A](value: A): Option[A] = Option(value)
And keep the current definintion of
def foo(bar: Option[String]): ?? = ???
Implicitly converting to Option, however can result in some unexpected results, so be wary.
You can write the desired generic implicit as
implicit def wrapToOption[T](x: T) = Option[T](x)
Then you can do
def foo(bar: Option[String] = None) = println(bar)
foo("bar") //> Some(bar)
foo() //> None
def fooBar(bar: Option[Int] = None) = println(bar)
fooBar(2) //> Some(2)
About it being sane thing to do, I will say no(personal opinion). Implicits are notoriously hard to debug. A logic gone wrong in the implicits can make your life hell.
Also, each new addition to the team will have to taught about all these "magics" happening behind the scenes.
It is a perfectly reasonable approach to set the type of your parameters to Option[_], if they really can be optional. However, I do not recommend using implicits to convert directly to Option[_].
You can make the syntax a little easier on the eye by including Scalaz and using some:
foo("hello".some)
If you don't want to bring in Scalaz just for that it's very easy to write your own implicit to do so. This implicit is better because you explicitly call the some method to "trigger" the implicit, as opposed to a "magical" conversion.
Another alternative, if you often call a function with parameters set to Some[_] is to overload it (again, I'm not a fan of overloading either):
def foo(x: Option[String] = None, y: Option[Int] = None, z: Option[String] = None) { /* do stuff */ }
def foo(x: String, y: Int, z: Option[String] = None) = foo(x.some, y.some, z)
On a final note, I don't think there is anything wrong with wrapping your arguments in Some if the function clearly defines them as optional. I wouldn't worry to much about this syntax.
you can define an implicit converter as :
implicit def conv(str: String): Option[String] = {
if (str == null) None else Some(str)
}
def foo(bar: Option[String] = None) = {
bar
}
Output:
scala> foo("xyz")
res55: Option[String] = Some(xyz)
scala> foo()
res1: Option[String] = None
Implicitly converting everything to an Option is a dangerous game that I would avoid! You might prefer simply having some method overloads:
object Foos {
private def foo(bar: Option[String]): Unit = println(bar.getOrElse("foobar"))
def foo(bar: String): Unit = foo(Some(bar))
def foo(): Unit = foo(None)
}
And then you can do:
Foos.foo("barfoo") //prints "barfoo"
Foos.foo() //prints "foobar"
While still only really implementing the method once. Furthermore, you can hide the Option overload this way.
I have a container type that holds metadata associated with a value.
class Container[A](val value: Option[A], val meta: Metadata)
Sometimes it's useful to access the meta but most of the time it's more convenient to work with a value as if it was Option[A]. There is an implicit conversion for this.
object Container {
implicit def containerToValue[A](c: Container[A]): Option[A] = c.value
}
All of that works fine. The issue is that often there will be an implicit conversion present from A => B and the value happens to be Container[A]. What I'm looking to do is to provide a way to do an implicit conversion basically from Container[A] => Option[B]. My first attempt was something to the effect of:
object Container {
implicit def containerToValue[A](c: Container[A]): Option[A] = c.value
implicit def containerToB[A,B](c: Container[A])(implicit conv: (A) => B): Option[B] = c.value.map(conv)
}
Scala didn't like that at all, so as a fallback since in 90% of the cases B will actually be a String, I tried doing something with more of the types filled out:
object Container {
implicit def containerToValue[A](c: Container[A]): Option[A] = c.value
implicit def containerToB[A](c: Container[A])(implicit conv: (A) => String): Option[String] = c.value.map(conv)
}
This did a little better but I got a number of errors about ambiguity. What I was wondering is if there was a way to specify that A is not String. Perhaps something like:
implicit def containerToB[A >!> String]
Such that I could tell the compiler this implicit conversion applies only when A isn't String.
Is there a better way to handle this?
Instead of doing an implicit conversion (because they're hard to debug, cause runtime errors when you least expect them, and make the code generally less clear) why not add a type class to the mix so that you can work with things the way you want to work with them?
trait Extractor[A,B]{
def opt(that: Container[A]): B
}
and then you explicitly create all the various instances that you might want to have:
def myGloriousFunction[B](that: Container[A])(implicit ex: Extractor[A,B]) ={
val value = ex.opt(that)
//more stuff
}
It'll handle the finding of the "extractor" for your inner Option and it's still fairly explicit in its signature.
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)