Behavior of implicit declaration declared after usage - scala

Scala 2.13.10. Consider the following code:
object Hello extends App {
def foo(implicit i: Int) = println(i)
foo
implicit val i: Int = 42
foo
}
It compiles with the warning
Reference to uninitialized value i
[warn] foo
and prints
0
42
The expected behavior is that it compiles with an error of implicit not found.
Why does it behave the way it is?

Related

Scala: implicitly to implicit class

Given:
implicit class Foo(val i: Int) {
def addValue(v: Int): Int = i + v
}
is it possible apply to it any implicitly?
I get an error here:
<console>:14: error: could not find implicit value for parameter e: Foo
implicitly[Foo]
An implicit class Foo(val i: Int) means that there is an implicit conversion from Int to Foo. So implicitly[Int => Foo] should work.
Think about it like this: if you could summon a Foo with implicitly[Foo], which Foo would you expect to get? A Foo(0)? A Foo(1)? A Foo(2)?
For further details,
implcitly key word can be explained as following
implitly[T] means return implicit value of type T in the context
Which means, to get Foo implicitly you need to create an implicit value in the scope
For example,
implicit class Foo(val i: Int) {
def addValue(v: Int): Int = i + v
}
implicit val foo:Foo = Foo(1)
val fooImplicitly = implicitly[Foo] // Foo(1)
Also, note that Foo itself is only a class,
But by putting implicit key word in front of class definition,
Compiler creates an implicit function of type Int => Foo

How to specify required function on generic selector in Scala

I know this can be done but I can't remember (or locate) the syntax for the life of me. How can I specify that a specific function must be present on a generic type in a function definition?
For instance, I know I can do this:
def blah[A](p: A)
What I really want is something like this (but my syntax is all wrong of course):
def blah[A(someFunction)](p: A)
I am not sure if using this is a good idea, but here is how it works:
def blah[A <: { def someFunction: String }](a: A) : Unit =
println(a.someFunction)
scala> class Test { def someFunction: String = "hello" }
defined class Test
scala> blah(new Test)
hello
scala> class Test2
defined class Test2
scala> blah(new Test2)
<console>:16: error: inferred type arguments [Test2] do not conform to method blah's type parameter bounds [A <: AnyRef{def someFunction: String}]
Note that this feature (so-called structural types) uses reflection, and has to be enabled using the language import import scala.language.reflectiveCalls
What you're looking for is called a "structural type".
Any example from here: https://twitter.github.io/scala_school/advanced-types.html
scala> def foo(x: { def get: Int }) = 123 + x.get
foo: (x: AnyRef{def get: Int})Int
scala> foo(new { def get = 10 })
res0: Int = 133
Note, however, that this is going to be slower than just declaring a trait that requiring that any argument implements that trait.

Scope of implicits

As a follow up to my other question, see comments / questions in code:
case class Implicit(name: String)
def foo(implicit i: Implicit = null) = println(Option(i))
def bar1(implicit i: Implicit) {
foo // prints None
implicit val i = Implicit("J") // Why is call to foo above affected although this line comes after?
foo // prints Some(Implicit(I))
}
def bar2(implicit i: Implicit) {
foo // prints None
implicit val i = null
implicit val j = Implicit("J")
foo // prints None // Why? Should raise ambiguous implicits or at least choose j.
}
def bar3(implicit i: Implicit) {
foo // prints None
val i = null
implicit val j = Implicit("J")
foo // prints Some(Implicit(J)) // Now it works as I expected to work in bar2.
}
def bar4(implicit i: Implicit) { // That's how I expected to see bar1 working. A ugly hack here.
foo // prints Some(Implicit(I))
locally {
val i = null
implicit val j = Implicit("J")
foo // prints Some(Implicit(J))
}
}
val i = Implicit("I")
bar1(i)
bar2(i)
bar3(i)
bar4(i)
Your code suffers from name shadowing. The spec in chapter 2 says about this:
A binding has a scope in which the entity defined by a single name can be accessed using a simple name. Scopes are nested. A binding in some inner scope shadows bindings of lower precedence in the same scope as well as bindings of the same or lower precedence in outer scopes.
In your example, this means that with
def foo(implicit i: Implicit) = println(Option(i))
we have the following possibilities:
The implicit param i gets passed to foo because x would be a forward reference:
scala> def f(implicit i: Implicit) = {foo; implicit val x = Implicit("i")}
f: (implicit i: Implicit)Unit
Nothing can be passed to foo because parameter i is shadowed by the local value i which has higher precedence but can't be called because it is a forward reference.
scala> def f(implicit i: Implicit) = {foo; implicit val i = Implicit("i")}
<console>:11: error: could not find implicit value for parameter i: Implicit
def f(implicit i: Implicit) = {foo; implicit val i = Implicit("i")}
^
A value is shadowed when it has the same name, but it must not have the same type:
scala> def f(implicit i: Implicit) = {implicit val j = Implicit("i"); foo}
<console>:11: error: ambiguous implicit values:
both value i of type Implicit
and value j of type Implicit
match expected type Implicit
def f(implicit i: Implicit) = {implicit val j = Implicit("i"); foo}
^
scala> def f(implicit i: Implicit) = {val i = null; implicit val j = Implicit("i"); foo}
f: (implicit i: Implicit)Unit
There exists multiple implicits in scope, but one has higher precedence. In this case i has the higher precedence because Null <: Implicit
scala> def f(implicit i: Implicit) = {implicit val i = null; implicit val j = Implicit("i"); foo}
f: (implicit i: Implicit)Unit
Your definition of foo was declared with a default value for the implicit parameter. This doesn't change anything at the rules mentioned above, but the compiler can choose the default value when no other value is available.

Case class companion object generation error for compound type

Defined empty trait Test:
trait Test
what used in compound type:
scala> val a : Int with Test = 10.asInstanceOf[Int with Test]
a: Int with Test = 10
and case class with parameter of compound type (like Unboxed Tagged Type):
scala> case class Foo(a: Int with Test)
error: type mismatch;
found : Double
required: AnyRef
Note: an implicit exists from scala.Double => java.lang.Double, but
methods inherited from Object are rendered ambiguous. This is to avoid
a blanket implicit which would convert any scala.Double to any AnyRef.
You may wish to use a type ascription: `x: java.lang.Double`.
But it is perfectly work for:
scala> case class Foo(a: List[Int] with Test)
defined class Foo
And no problem with method definition:
scala> def foo(a: Int with Test) = ???
foo: (a: Int with Test)Nothing
Scala version 2.10.3
Is it normal compiler behaviour?
You've bumped into one of the cases where Scala's attempt to unify primitives and Objects breaks down. Since Int in Scala represents the Java primitive type int, it can't have any traits mixed into it. When doing asInstanceOf, the Scala compiler autoboxes the Int into a java.lang.Integer:
scala> val a: Int with Test = 10.asInstanceOf[Int with Test]
a: Int with Test = 10
scala> a.getClass
res1: Class[_ <: Int] = class java.lang.Integer
However, autoboxing doesn't happen when declaring types, so you have to do it by hand:
scala> case class Foo(x: Integer with Test)
defined class Foo
But then the compiler type checker won't autobox before checking the types:
scala> Foo(a)
<console>:12: error: type mismatch;
found : Int with Test
required: Integer with Test
Foo(a)
^
So you would have to declare your variable as Integer with Test:
scala> val a: Integer with Test = 10.asInstanceOf[Integer with Test]
a: Integer with Test = 10
scala> Foo(a)
res3: Foo = Foo(10)
or use a cast when calling the case class:
val a : Int with Test = 10.asInstanceOf[Int with Test]
scala> a: Int with Test = 10
scala> Foo(a.asInstanceOf[Integer with Test])
res0: Foo = Foo(10)
as #Travis Brown said This is a know issue,fixed in scala 2.11.7.
run under ammonite Repl 2.0.4 (scala 2.12.10 java 1.8.0_242)
#case class Foo(a: Int with Test)
a: Int with Test = 10

Why does Scala's type inferencer fail with this set of implicit arguments involving parameterized types?

I would like to define a method parameterized with type T that has behavior dependent on what implicit argument can be found of type Box[T]. The following code has this method defined as foo. When called with foo[Int] or foo[String] it will without issue return 1 or "two" as expected.
Where things get weird is with the method bar. It is defined as returning an Int, but instead of foo[Int] I have just foo. My hope was that the compiler would infer that T must be of type Int. It does not do that and instead fails:
bash $ scalac Code.scala
Types.scala:15: error: ambiguous implicit values:
both value one in object Main of type => Main.Box[Int]
and value two in object Main of type => Main.Box[java.lang.String]
match expected type Main.Box[T]
def bar: Int = foo
^
one error found
What is causing this error? Replacing foo with foo[Int] compiles fine. The simpler situation where there is no Box[T] type also compiles fine. That example is also below and uses argle and bargle instead of foo and bar.
object Main extends Application {
case class Box[T](value: T)
implicit val one = Box(1)
implicit val two = Box("two")
def foo[T](implicit x: Box[T]): T = {
x.value
}
// does not compile:
// def bar: Int = foo
// does compile
def bar: Int = foo[Int]
println(bar)
// prints 1
// the simpler situation where there is no Box type
implicit val three = 3
implicit val four = "four"
def argle[T](implicit x: T): T = x
def bargle: String = argle
println(bargle)
// prints "four"
}
What is going on in this snippet that causes this behavior? What about this interaction of implicit arguments, type inference, and erasure is causing problems? Is there a way to modify this code such that the line def foo: Int = bar works?
Someone else will have to explain why the type inference mechanism cannot handle that case, but if you are looking to cleanup your code you could probably do this:
object Test extends App {
case class Box[T](value: T)
implicit val one: Box[Int] = Box(1)
implicit val two: Box[String] = Box("two")
def foo[T : Box]: T = implicitly[Box[T]].value
val bar = foo[Int]
}
Note that:
I removed the type annotation from bar so you are really just indicating the type once (just in a different spot than you wanted)
I am using App instead of deprecated Application
Using a context bound in the type signature of foo
This might be related to SI-3346, though there it is implicit arguments to implicit conversions, and here you have a single implicit.