Implicit conversion, import required or not? - scala

I write
object MyString {
implicit def stringToMyString(s: String) = new MyString(s)
}
class MyString(str: String) {
def camelize = str.split("_").map(_.capitalize).mkString
override def toString = str
}
object Parse {
def main(args: Array[String]) {
val x = "active_record".camelize
// ...
}
}
in my program. This causes a compiling error. After I inserted
import MyString.stringToMyString
Then it works.
From Odersky's Programming in Scala I got that implicit conversion in the companion object of the source or expected target types don't need to be imported.

implicit conversion in the companion
object of the source or expected
target types don't need to be
imported.
True enough. Now, the method camelize is defined on the class MyString, and, indeed, there is an implicit conversion to MyString inside its object companion. However, there is nothing in the code telling the compiler that MyString is the expected target type.
If, instead, you wrote this:
val x = ("active_record": MyString).camelize
then it would work, because the compiler would know you expect "active_record" to be a MyString, making it look up the implicit conversion inside object MyString.
This might look a bit restrictive, but it actually works in a number of places. Say, for instance, you had:
class Fraction(num: Int, denom: Int) {
...
def +(b: Fraction) = ...
...
}
And then you had a code like this:
val x: Fraction = ...
val y = x + 5
Now, x does have a + method, whose expected type is Fraction. So the compiler would look, here, for an implicit conversion from Int to Fraction inside the object Fraction (and inside the object Int, if there was one, since that's the source type).

In this situation you need the import because the compiler doesn't know where you pulled out the camelize method from. If the type is clear, it will compile without import:
object Parse {
def foo(s: MyString) = s.camelize
def main(args: Array[String]) {
val x = foo("active_record")
println(x.toString)
}
}
See Pimp my library pattern, based on Martin's article:
Note that it is not possible to put defs at the top level, so you can’t define an implicit conversion with global scope. The solution is to place the def inside an object, and then import it, i.e.
object Implicits {
implicit def listExtensions[A](xs : List[A]) = new ListExtensions(xs)
}
And then at the top of each source file, along with your other imports:
import Implicits._

I tried the Rational class example in Programming in Scala book, put an implicit method in its companion object:
object Rational {
implicit def intToRational(num: Int) =
new Rational(num)
}
but the code
2 + new Rational(1, 2)
does not work. For the conversion to happen, the single identifier rule applies, i.e., you need to import the explicit method into scope even though it is defined in the companion object.

Related

When doing implicit resolution with type parameters, why does val placement matter?

In one file, I have:
trait JsonSchema[T] {
val propertyType: String
override def toString: String = propertyType
}
object JsonSchema {
implicit def stringSchema: JsonSchema[String] = new JsonSchema[String] {
override val propertyType: String = "string"
}
implicit def intSchema: JsonSchema[Int] = new JsonSchema[Int] {
override val propertyType: String = "integer"
}
implicit def booleanSchema: JsonSchema[Boolean] = new JsonSchema[Boolean] {
override val propertyType: String = "boolean"
}
}
In my main file:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])
object JsonSchemaExample extends App {
println(MetaHolder(3).meta.toString)
println(MetaHolder("wow").meta.toString)
}
That works hunky-dory. Now suppose I do this instead:
case class MetaHolder[T](v: T) {
val meta: JsonSchema[T] = implicitly[JsonSchema[T]]
}
It no longer compiles. Why?
My goal is to modify the anonymous Endpoint classes in the scala Finch library by adding a val meta to everything. I've been able to do this without any fancy-business so far, but now I want to do some fancy implicit resolution with shapeless to provide a JsonSchema definition for arbitrary case classes. My question is how to do this while maintaining backward compatibility. As in: provide the jsonschema meta feature for people who want to opt in, don't change the compilation burden for anyone who does not want to use meta,
If instead I go the first route, with an added implicit parameter, wouldn't that require a special import to be added by everyone? Or am I missing something and would backward compatibility still be maintained?
There is big difference between implicit x: X among parameters and implicitly[X] inside body.
When you say implicitly[X] this means "check now whether in the current scope there is an implicit X".
When you say def foo(...)(implicit x: X) = ... this means "check later when foo is called that in the scope of the call site there will be an implicit X (and for now inside foo just assume without checking that there is)".
class Foo(...)(implicit x: X) is similar to the latter, "check when constructor is called that there will be an implicit X".
Regarding whether users have to import or not. If you put implicits for type X to companion object of X then they will be found automatically (implicits for type X[Y] should be put to companion object of either X or Y). If you put them somewhere else then they have to be imported to the current scope.
In order for implicitly[JsonSchema[T]] to compile, there must be a JsonSchema[T] in the implicit scope, which means that there must be a JsonSchema[T] (or something implicitly convertible to a JsonSchema[T]) passed through as an implicit argument, as you had with:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])

Understanding implicit conversions

I'm reading Scala documentation of implicit conversions and decided to try it out:
object Main extends App {
val test = TestConversion(100)
test.its
}
class Test[T](val t : T) {
def its = println(t)
}
object Test {
def apply[T](t: T): Test[T] = new Test(t)
}
class TestConversion(v : Int) {
val value = v
}
object TestConversion{
implicit def implicitConversionTest2Int(ict : TestConversion): Test[Int] = Test(ict.value)
def apply(v : Int) = new TestConversion(v)
}
As it's said:
To define your own implicit conversions, you must first import
scala.language.implicitConversions (or invoke the compiler with
-language:implicitConversions). The feature must be explicitly enabled because it has pitfalls if used indiscriminately.
I tried it both in IntelliJ and online IdeOne and I didn't add anything special to make it compile.
What pitfalls it brings and why does it work without any imports?
You don't need to import anything.
The idea is that you can declare implicit conversion function wherever you want in the scope.
For example:
case class Coins(amount:Int)
case class Bills(amount:Int)
object Main {
implicit def billsToCoins(bills:Bills):Coins = Coins(bills.amount * 100)
def printCoins(coins:Coins) = println(s"You have ${coins.amount} coins." )
def main(args:Array[String]): Unit ={
printCoins(Bills(3))
}
}
I have declared here implicit function billsToCoins so it is available in scope of the main function. The only thing needed for the function to act as implicit converter is to have the implicit modifier, compiler will find it and use. You see that the printCoins function takes argument of the Coins type but I was able to pass the value of Bills type and it was successfully created.
Here is the console output:
You have 300 coins.
Process finished with exit code 0

Scala implicit conversion not recognised

I have the following object for making a conversion of an object ParsedItemDocument to a json String. I should note that ParsedItemDocument is a trait. My problem is that the implicit conversion that is called on the second snippet is not recognized by the compiler. Is there anything more that needs to be done for the implicit conversion to work?
import scala.language.implicitConversions
import wikidataParser.ParsedItemDocument
object Converters {
def toJson(obj: Any): String = {
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
val out = new StringWriter
mapper.writeValue(out, obj)
return out.toString()
}
implicit def parsedItemDocumentToJsonString
(item: ParsedItemDocument): String = {
Converters.toJson(item)
}
}
Now, I use the following code-snippet in my code
import tools.Converters._
import wikidataParser.ParsedItemDocument
class WikipediaRankingTester2 extends FlatSpec {
"It" should "do something" in {
val jsonrdd:RDD[String]=rankedItems.map(t:Long,ParsedItemDocument)=>
t._2.parsedItemDocumentToJsonString)//compilation error here
}
}
You are mixing up implicit conversions and implicit classes.
If you want to use parsedItemDocumentToJsonString as a "method" of an object of type ParsedItemDocument, then you would need to define your implicit as
implicit class JSONParsing(item: ParsedItemDocument): String {
def parsedItemDocumentToJsonString = Converters.toJson(item)
}
If you declare it as an implicit conversion, as you did, then it means that you can call any methods of String on an object of type ParsedItemDocument, as the object will be implicitly converted to a String through the implicit method.
Also, it is not great practice to declare an entire implicit class / conversion, unless you 1) cannot add it to the original class, or 2) will be reusing the conversion very often, and it would save great amounts of code/readability. This does not seem to be the case here, as you are only wrapping in Converters.toJSON, which is not very verbose, and jsut as readable.
PS: your syntax in your "map" is wrong, the right syntax would be
val jsonrdd = rankedItems.map(t => t._2.parsedItemDocumentToJsonString)
If your implicit is working this should do it:
rankedItems.map(t => t._2)
You can test this by making the call explicit
rankedItems.map(t => parsedItemDocumentToJsonString(t._2))
If you want to add an extra method to a ParsedItemDocument you could use an implicit class, I don't think you need it but your code looks a bit that way.

Creating `**` power operator for Scala?

I quite like the ** syntax for pow, available in many languages (such as Python).
Is it possible to introduce this into Scala, without modifying the Scala 'base' code?
My attempt at an Int only one:
import scala.math.pow
implicit class PowerInt(i: Int) {
def `**`(n: Int, b: Int): Int = pow(n, b).intValue
}
(see it failing on IDEone)
this works for me: (problem#1 pow is defined on doubles, problem#2 extending anyval)
(also there is no point in having those backticks in the methodname?)
import scala.math.pow
object RichIntt {
implicit class PowerInt(val i:Double) extends AnyVal {
def ** (exp:Double):Double = pow(i,exp)
}
def main(args:Array[String])
{
println(5**6)
}
}
This answer is 2 years late, still for the benefit of others I'd like to point out that the accepted answer unnecessarily extends from AnyVal.
There is just a minor bug that needs to be fixed in the original answer. The def ** method needs only one parameter, i.e. the exponent as the base is already passed in the constructor and not two as in the original code. Fixing that and removing the backticks results in:
import scala.math.pow
implicit class PowerInt(i: Int) {
def ** (b: Int): Int = pow(i, b).intValue
}
Which works as expected as seen here.
Scala compiler will cast an Int to a PowerInt only if the method that is called on it is undefined. That's why you don't need to extend from AnyVal.
Behind the scenes, Scala looks for an implicit class whose constructor argument type is the same as the type of the object that is cast. Since the object can have only one type, implicit classes cannot have more than one argument in their constructor. Moreover, if you define two implicit classes with the same constructor type, make sure their functions have unique signatures otherwise Scala wouldn't know which class to cast to and will complain about the ambiguity.
There is a way to make the solution a little bit more generic using Numeric typeclass:
implicit class PowerOp[T: Numeric](value: T) {
import Numeric.Implicits._
import scala.math.pow
def **(power: T): Double = pow(value.toDouble(), power.toDouble())
}
This is my solution using recursion (so I don't need import scala.Math.pow):
object RichInt {
implicit class PowerInt(val base:Double) {
def ** (pow:Double):Double = if (pow==0) 1 else base*(base**(pow-1))
}
def main(args:Array[String]){
println(2.0**3.0) //8.0
println(2.0**0.0) //1.0
}
}

Why does an implicit conversion on the constructor require 'this'?

Consider the following typical Scala 'pimp' code:
class PimpedA(a:A){
def pimp() = "hi"
}
implicit def pimpA(a:A) = new PimpedA(a)
new A(){
pimp() //<--- does not compile
}
However, changing it to:
new A(){
this.pimp()
}
Makes it work.
Shouldn't it be the same to the Scala compiler?
EDIT : Is there any solution that can make it work without having to add the this.?
Not at all. For it to work, pimp needs to be either an object or an imported member of a value, and it is neither. A class has an "implicit" import this._. It has not a mechanism that auto-prepends this to stuff to see if it compiles.
In this case you should give compiler a hint that pimp() is not a random function. When you write
this.pimp()
compiler know there isn't pimp function on class A so it's an error and before giving up it searches implicit conversion in scope and finds it.
pimpA(this).pimp()
And when you just call pimp() compiler doesn't know what object to pass to the pimpA(a: A) implicit function.
UPDATE
It is hard to understand what is your goal. I can only suggest to make PimpedA a typeclass (Pimp[T] in this example).
trait Pimp[T] {
def action(p: T): String
}
implicit object PimpA extends Pimp[A] {
override def action(p: A) = "some actions related to A"
}
def pimp[T: Pimp](p: T) = implicitly[Pimp[T]].action(p)
class A {
val foo = pimp(this)
}
scala> new A foo
res2: String = some actions related to A