Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is "Shadowed Implicit Value Members" in Scala doc?

Tags:

scala

There is a Shadowed Implicit Value Members section in StringOps doc. E.g.:

def split(arg0: String, arg1: Int): Array[String]

Implicit information
This member is added by an implicit conversion from StringOps to String performed by method unaugmentString in scala.Predef.

Shadowing
This implicitly inherited member is shadowed by one or more members in this class. To access this member you can use a type ascription:

(stringOps: String).split(arg0, arg1)

Definition Classes
String

But when I try to run following program:

"aaa bbb ccc".split(" ", 2) //> res0: Array[String] = Array(aaa, bbb ccc)

Calling the String.split(arg0: String, arg1: Int) doesn't need using type ascription as in the doc described.

So what is the Shadowed Implicit Value Members referring to? I tried to ask google but cannot find any reference.

Is it something like:

class A {
  def foo() = println("foo")
}

class AOps(a: A) {
  def bar() = println("bar")
  def foo() = println("new foo")
  def foo(i: Int) = println("foo %d".format(i))
}

object Program {
  implicit def A2AOps(a: A) = new AOps(a)         //> A2AOps: (a: A)AOps

  val a = new A()                                 //> a  : A = A@15669ae
  a.foo                                           //> foo
  a.bar                                           //> bar
  (a: AOps).foo                                   //> new foo
  a.foo(1)                                        //> foo 1
}

Then the String.split(...) and StringOps.split function signatures are different, so there will no need be "type ascription".

Is this what "Shadowed Implicit Value Members" stands for? I'm a little puzzled. Thanks!

like image 721
Xin Huang Avatar asked Oct 27 '13 07:10

Xin Huang


1 Answers

Normally the Scala compiler will look to perform implicit conversions when you call a method that doesn't exist for a given type:

case class Foo(x :String)

implicit class Bar(foo: Foo) {
  def barOnly = "w00p"
}

println( Foo("test").barOnly )

Here when we call the method barOnly on an instance of Foo the scala compiler can see it needs to do an implicit conversion from Foo to Bar to provide us with that method and we get the expected output of w00p. Try it

However if a method with the same signature exists in Foo and Bar, then we have some shadowing and the scala compiler will not do the implicit conversion unless we explicitly ask for it with type ascription:

case class Foo(x :String) {
  def whoAmI = "Foo: " + x
}

implicit class Bar(foo: Foo) {
  def whoAmI = "Bar: " + foo.x
}

println( Foo("test").whoAmI )
println( (Foo("test"): Bar).whoAmI )

The output is:

Foo: test
Bar: test

Try it

In your example of split in the scaladocs, there are methods called split on both String and StringOps, however they take different argument types, so I'm not entirely sure why the docs are warning us about having to use type ascription. We do not need to disambiguate anything for the compiler in this situation and type ascription has no effect:

import scala.collection.immutable.StringOps

val stringOps: StringOps = "aaa bbb ccc"

println( stringOps.split("a", 2).mkString )
println( (stringOps: String).split("a", 2).mkString )

The output for these two lines is identical:

aa bbb ccc
aa bbb ccc

Try it

Maybe just an error in the docs.

like image 72
theon Avatar answered Nov 02 '22 14:11

theon