The following conversion works because of int2double implicit conversion
scala> val d: Double = 2
d: Double = 2.0
prior to 2.10, this implicit conversion was part of Predef object and was thus always in scope. However since 2.10, it has been moved to Int companion object. How does the implicit conversion still work without any import?
For implicits, besides the local scope (including imported ones), there is the implicit scope
Where does Scala look for implicits?
https://www.scala-lang.org/files/archive/spec/2.11/07-implicits.html
The actual arguments that are eligible to be passed to an implicit parameter of type 𝑇 fall into two categories. First, eligible are all identifiers 𝑥 that can be accessed at the point of the method call without a prefix and that denote an implicit definition or an implicit parameter. An eligible identifier may thus be a local name, or a member of an enclosing template, or it may be have been made accessible without a prefix through an import clause. If there are no eligible identifiers under this rule, then, second, eligible are also all implicit members of some object that belongs to the implicit scope of the implicit parameter's type, 𝑇.
The implicit scope of a type 𝑇
consists of all companion modules of classes that are associated with the implicit parameter's type. Here, we say a class 𝐶 is associated with a type 𝑇 if it is a base class of some part of 𝑇.
The parts of a type 𝑇 are:
...
if 𝑇 is a parameterized type 𝑆[𝑇1,…,𝑇𝑛], the union of the parts of 𝑆 and 𝑇1,…,𝑇𝑛;
...
Implicit conversion Int => Double is Function1[Int, Double], so companion objects of Function1, Int, Double will be investigated.
Related
In Scala, during type erasure, the generic variable is replaced by 'Object' type wherever the generic variable appears in type position.
E.G: val x T; --> is replaced by val x Object;
Due to this, the details of exact type which is passed, will become unavailable during runtime.
To overcome this (to get the exact type during runtime), it is mentioned that ClassTag will help us.
Can you please help me how ClassTag gets the type information during runtime ?
When ClassTag is mentioned , that is also written with a generic type in context bound.
E.G: def method[T:ClassTag] {...}
So I think, the 'T' mentioned here too, will be erased. But ClassTag somehow keeps the type info.
I am bit puzzled how this works.. (similarly TypeTag and WeakTag as well)
This is not correct:
E.G: val x T; --> is replaced by val x Object;
The type of x is not lost; you can look at the value of x at runtime and determine what type it is. Objects retain their runtime type.
Type erasure affects values of a parameterised type Y[T]. The runtime holds a single type for an object so it cannot hold T as well as Y and "erases" T from the type. If I have an instance of Y[T] I can tell at runtime that it is type Y but cannot tell which T it was parameterised with.
Thus I can distinguish List[T] from Vector[T] but cannot distinguish List[T] from List[U]. But an element of that List retains its type and can be matched against T or U. And a member val x: T can be matched directly to determine the type of the object.
A ClassTag is value that represents a type, so if you store the ClassTag of T in your object then you can match that to work out the type of T without having to look at any of the values of type T inside the object. You are explicitly storing the type information for T that was previously erased.
[ Useful discussion in the comments about this really being about classes rather than types ]
In scala, to make a class comparable we extends Ordered[T] on the class
case class A(i: Int) extends Ordered[A] {
def compare(that: A): Int = this.i compare that.i
}
and Iteratable[A]'s method sorted requires implicit parameter of type scala.math.Ordering[A] to sort Iterable[A]
Seq[A](A(2),A(1)).sorted // Seq(A(1),A(2)) Ordering will provide Ordering[A]
Seq[A](A(2),A(1)).sorted(Ordering[A]) // Seq(A(1),A(2))
and the Ordering companion object provides an implicit Ordering[T] for Iterable[A]
My question: How can the Ordering object can provide Ordering[T] to sorted.
Since [T] will be removed by JVM and it is impossible to know difference between
Ordering[A] and Ordering[Int]
How come it can work??
How come it can work?
Implicits are a compile time feature. That is, when you compile your code, the compiler enforces rules which need to check out. In this particular case, an implicit of type Ordering[Int] needs to be available in scope, otherwise you'll get a compilation error.
This means that at run-time, even though the types are erased, you can guarantee that there will be an Ordering[Int] available, even though it will look like an Ordering(obj: Object), you've already fulfilled the guarantee of it being able to order the underlying Int objects which otherwise wouldn't allow your code to compile.
I have a value parameterless method that I want to overload with another method employing a higher-kinded type constructor. I also want to make use of the type constructor parameter in the method body. I also want to capture the class tag. This is what I think should be possible:
trait SomeContainer[+A]
trait Foo[+A]
class SomeClass {
// The simple variant
def method[T <: AnyRef]: Foo[T]
// Now the overloaded higher-kinded variant
def method[F[T <: AnyRef : Manifest] <: SomeContainer[T]]: Foo[T] = {
val classTag = manifest[T]
// Do something with it
}
}
However I do not have access to T at all here. The aim here is to make the higher-kinded method here overload the non-higher kinded one def method[T <: AnyRef]: Foo[T]. Have I reached a limitation of the language? Is the non-higher kinded method signature far too open-ended making it impossible for the compiler to disambiguate the one from the other? Is there a better more idiomatic approach to this sort of pattern of overloading on type parameters?
You can't overload methods based only on type parameters at all, since they don't exist in JVM: so far as it's concerned, both methods are def method(): Foo. Technically a compiler could allow it by giving the overloaded methods different names in bytecode, but neither Java nor Scala do so.
Is there a better more idiomatic approach to this sort of pattern of overloading on type parameters?
You could give one of the methods a dummy implicit parameter (there is a DummyImplicit type in Predef for this).
Why are these type aliases and vals introduced in Predef?
Things that are in Predef are automatically imported. In Scala, you can write
val mySet : Set[String] = Set( "cat", "dog", "poop" )
without having to first write
import scala.collection.immutable.Set
Note that the declaration I wrote above might have been written equivalently as
val mySet : Set[String] = Set.apply( "cat", "dog, "poop" )
On the right-hand side of the equals sign, the word Set refers to a singleton object. We can only call methods on objects (whether singletons or instances of classes). We can't call methods on types. Somehow, we must have autoimported the name of an object Set. This is what the Predef declaration
val Set = immutable.Set
does.
If you are a Java programmer, you can think of a val declaration that just points to an object that would otherwise require the use of an import or a much longer name as being the equivalent of import static.
The Set[String] after the colon and before the equals sign is a type annotation. In this context Set[String] is a type. An object is not a type. If all we had declared in Predef were the val, our declaration could not compile. We would have been saying that mySet's type is a some particular object, but a type is very different from an object, a type is a description of a category to which an object may belong.
To let Set also serve as a type, we need the type alias
type Set[A] = immutable.Set[A]
If you are a java programmer, this functions similarly to a nonstatic import of a type name. (Scala has imports as well, but they must be scoped to a specific block or file. type aliases in Predef are available to all Scala files, so it does much more than an import of the type would do.)
The package scala.collection.immutable contains both an object, declared as
object Set{ ... }
and a type, declared as
trait Set[A]{ ... }
If we want to be able to use both the object (with its useful factory methods) and the type (the compile-time description of the objects our factory creates), we need to make both of them, object and type, available to our code. The two lines (for Set) that you quote above do precisely that. (And the other two lines do precisely the same for Map.)
These types and vals just make importing unnecessary, I believe.
The vals are assigning the companion objects into the vals - again, getting rid of an import.
I suspect they are done in this odd way to avoid a circular compile-time dependency between Predef.scala and Map/Set.scala, but I'm only guessing.
The whole point of Predef is to avoid explicit qualifications and import statements. From the docs:
The Predef object provides definitions that are accessible in all
Scala compilation units without explicit qualification.
Predef provides type aliases for types which are commonly used, such as the immutable collection types scala.collection.immutable.Map,
scala.collection.immutable.Set, and the
scala.collection.immutable.List constructors
(scala.collection.immutable.:: and scala.collection.immutable.Nil).
This way, you can refer to Map without having to explicitly qualify or import scala.collection.immutable.Map.
When I compile:
object Test extends App {
implicit def pimp[V](xs: Seq[V]) = new {
def dummy(x: V) = x
}
}
I get:
$ fsc -d aoeu go.scala
go.scala:3: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
def dummy(x: V) = x
^
one error found
Why?
(Scala: "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement" doesn't really answer this.)
It's disallowed by the spec. See 3.2.7 Compound Types.
Within a method declaration in a structural refinement, the type of any value parameter may only refer to type parameters or abstract types that are contained inside the refinement. That is, it must refer either to a type parameter of the method
itself, or to a type definition within the refinement. This restriction does not apply
to the function’s result type.
Before Bug 1906 was fixed, the compiler would have compiled this and you'd have gotten a method not found at runtime. This was fixed in revision 19442 and this is why you get this wonderful message.
The question is then, why is this not allowed?
Here is very detailed explanation from Gilles Dubochet from the scala mailing list back in 2007. It roughly boils down to the fact that structural types use reflection and the compiler does not know how to look up the method to call if it uses a type defined outside the refinement (the compiler does not know ahead of time how to fill the second parameter of getMethod in p.getClass.getMethod("pimp", Array(?))
But go look at the post, it will answer your question and some more.
Edit:
Hello list.
I try to define structural types with abstract datatype in function
parameter. ... Any reason?
I have heard about two questions concerning the structural typing
extension of Scala 2.6 lately, and I would like to answer them here.
Why did we change Scala's native values (“int”, etc.) boxing scheme
to Java's (“java.lang.Integer”).
Why is the restriction on parameters for structurally defined
methods (“Parameter type in structural refinement may not refer
to abstract type defined outside that same refinement”) required.
Before I can answer these two questions, I need to speak about the
implementation of structural types.
The JVM's type system is very basic (and corresponds to Java 1.4). That
means that many types that can be represented in Scala cannot be
represented in the VM. Path dependant types (“x.y.A”), singleton types
(“a.type”), compound types (“A with B”) or abstract types are all types
that cannot be represented in the JVM's type system.
To be able to compile to JVM bytecode, the Scala compilers changes the
Scala types of the program to their “erasure” (see section 3.6 of the
reference). Erased types can be represented in the VM's type system and
define a type discipline on the program that is equivalent to that of
the program typed with Scala types (saving some casts), although less
precise. As a side note, the fact that types are erased in the VM
explains why operations on the dynamic representation of types (pattern
matching on types) are very restricted with respect to Scala's type
system.
Until now all type constructs in Scala could be erased in some way.
This isn't true for structural types. The simple structural type “{ def
x: Int }” can't be erased to “Object” as the VM would not allow
accessing the “x” field. Using an interface “interface X { int x{}; }”
as the erased type won't work either because any instance bound by a
value of this type would have to implement that interface which cannot
be done in presence of separate compilation. Indeed (bear with me) any
class that contains a member of the same name than a member defined in
a structural type anywhere would have to implement the corresponding
interface. Unfortunately this class may be defined even before the
structural type is known to exist.
Instead, any reference to a structurally defined member is implemented
as a reflective call, completely bypassing the VM's type system. For
example def f(p: { def x(q: Int): Int }) = p.x(4) will be rewritten
to something like:
def f(p: Object) = p.getClass.getMethod("x", Array(Int)).invoke(p, Array(4))
And now the answers.
“invoke” will use boxed (“java.lang.Integer”) values whenever the
invoked method uses native values (“int”). That means that the above
call must really look like “...invoke(p, Array(new
java.lang.Integer(4))).intValue”.
Integer values in a Scala program are already often boxed (to allow the
“Any” type) and it would be wasteful to unbox them from Scala's own
boxing scheme to rebox them immediately as java.lang.Integer.
Worst still, when a reflective call has the “Any” return type,
what should be done when a java.lang.Integer is returned? The called
method may either be returning an “int” (in which case it should be
unboxed and reboxed as a Scala box) or it may be returning a
java.lang.Integer that should be left untouched.
Instead we decided to change Scala's own boxing scheme to Java's. The
two previous problems then simply disappear. Some performance-related
optimisations we had with Scala's boxing scheme (pre-calculate the
boxed form of the most common numbers) were easy to use with Java
boxing too. In the end, using Java boxing was even a bit faster than
our own scheme.
“getMethod”'s second parameter is an array with the types of the
parameters of the (structurally defined) method to lookup — for
selecting which method to get when the name is overloaded. This is the
one place where exact, static types are needed in the process of
translating a structural member call. Usually, exploitable static types
for a method's parameter are provided with the structural type
definition. In the example above, the parameter type of “x” is known to
be “Int”, which allows looking it up.
Parameter types defined as abstract types where the abstract type is
defined inside the scope of the structural refinement are no problem
either:
def f(p: { def x[T](t: T): Int }) = p.xInt
In this example we know that any instance passed to “f” as “p” will
define “x[T](t: T)” which is necessarily erased to “x(t: Object)”. The
lookup is then correctly done on the erased type:
def f(p: Object) = p.getClass.getMethod("x", Array(Object)).invoke(p,
Array(new java.lang.Integer(4)))
But if an abstract type from outside the structural refinement's scope
is used to define a parameter of a structural method, everything breaks:
def f[T](p: { def x(t: T): Int }, t: T) = p.x(t)
When “f” is called, “T” can be instantiated to any type, for example:
f[Int]({ def x(t: Int) = t }, 4)
f[Any]({ def x(t: Any) = 5 }, 4)
The lookup for the first case would have to be “getMethod("x",
Array(int))” and for the second “getMethod("x", Array(Object))”, and
there is no way to know which one to generate in the body of
“f”: “p.x(t)”.
To allow defining a unique “getMethod” call inside “f”'s body for
any instantiation of “T” would require any object passed to “f” as the
“p” parameter to have the type of “t” erased to “Any”. This would be a
transformation where the type of a class' members depend on how
instances of this class are used in the program. And this is something
we definitely don't want to do (and can't be done with separate
compilation).
Alternatively, if Scala supported run-time types one could use them to
solve this problem. Maybe one day ...
But for now, using abstract types for structural method's parameter
types is simply forbidden.
Sincerely,
Gilles.
Discovered the problem shortly after posting this: I have to define a named class instead of using an anonymous class. (Still would love to hear a better explanation of the reasoning though.)
object Test extends App {
case class G[V](xs: Seq[V]) {
def dummy(x: V) = x
}
implicit def pimp[V](xs: Seq[V]) = G(xs)
}
works.