2
votes

I want to add new function "extra" to library class ("orig" for example).

orig.extra(rich.Arg()) // <- like this

If I comment 1st implicit conversion than I get error. I read Scala specification, and suspect that there are two places for implicit lookup:

  1. companion object of argument

  2. object that holds argument

Any tips? Unfortunately most official documentation about implicit is not very helpful and stack overflow search too.

scala> object container {
 |   //implicit def orig2rich(o: orig.type) = new { def extra(a: rich.Arg) = "extra" }
 |   object rich {
 |     implicit def orig2rich(o: orig.type) = new { def extra(a: Arg) = "extra" }
 |     case class Arg(val some: String = "some")
 |     object Arg {
 |       implicit def orig2rich(o: orig.type) = new { def extra(a: Arg) = "extra" }
 |     }
 |   }
 |   object orig {
 |     def standard(s: String) = "standard"
 |   }
 |   orig.extra(rich.Arg())
 | }
<console>:35: error: value extra is not a member of object container.orig
     orig.extra(rich.Arg())

EDIT

I read Where does Scala look for implicits?, very useful. And find my case - Implicit scope of an argument's type

Example that worked:

object container {
class A(val n: Int) {
  def +(other: A) = new A(n + other.n)
}
object A {
  implicit def fromInt(n: Int) = new A(n)
}

// This becomes possible:
1 + new A(1)
// because it is converted into this:
A.fromInt(1) + new A(1)
}

Change it a bit, just function name (what I actually want), and :-( oops

object container {
class A(val n: Int) {
  def hello(other: A) = new A(n + other.n)
}
object A {
  implicit def fromInt(n: Int) = new A(n)
}

// This becomes possible:
1.hello(new A(1))
// because it is converted into this:
A.fromInt(1).hello(new A(1))
}

<console>:16: error: value hello is not a member of Int
       1.hello(new A(1))

Scala version 2.9.1.r0-b20120114153402 (OpenJDK 64-Bit Server VM, Java 1.6.0_22).

It is a bit confusing. I tried to mix

7.3 Views

  1. In a selection e.m with e of type T , if the selector m does not denote a member of T . In this case, a view v is searched which is applicable to e and whose result contains a member named m. The search proceeds as in the case of implicit parameters, where the implicit scope is the one of T . If such a view is found, the selection e.m is converted to v (e ).m.
  2. In a selection e.m(args) with e of type T , if the selector m denotes some mem- ber(s) of T , but none of these members is applicable to the arguments args. In this case a view v is searched which is applicable to e and whose result con- tains a method m which is applicable to args. The search proceeds as in the case of implicit parameters, where the implicit scope is the one of

IMHO it is not possible

Thank you

2

2 Answers

3
votes

scala is applying implicit conversions that are visible in the same scope, so you can just add line

import rich.orig2rich

or

import rich._

This code will work

object container {

  //implicit def orig2rich(o: orig.type) = new { def extra(a: rich.Arg) = "extra" }
  object rich {
    implicit def orig2rich(o: orig.type) = new {
      def extra(a: Arg) = "extra"
    }

    case class Arg(val some: String = "some")

    object Arg {
      implicit def orig2rich(o: orig.type) = new {
        def extra(a: Arg) = "extra"
      }
    }

  }

  object orig {
    def standard(s: String) = "standard"
  }

  import rich.orig2rich

  def test = orig.extra(rich.Arg())
}

println(container.test)
0
votes

The problem might be the loading sequence, of orig and rich, or the rich and the implicit def.

Btw, the following code works fine, I defined orig first than rich and finally applied the implicit conversion to pimp orig

object container {
    object orig {
            def standard(s:String) = "standard"
    }

    object rich {
            case class Arg(val some: String = "some")

            object Arg {
                    implicit def orig2rich(o: orig.type) = new { def extra(a: Arg) = "extra" }
            }
    }

    implicit def orig2rich(o: orig.type) = new { def extra(a: rich.Arg) = "extra" }

    orig.extra(rich.Arg())
}

println(container.orig.extra(container.rich.Arg()))