Type alias for mix-in type - scala

Since I can do this:
case class A(a: Int)
trait C
val x = new A(10) with C
Why can't I do this:
type X = A with C
val x = new X(10)
? If I can't even construct an instance, what's the use case of type X = A with C?

The error message that you get should give you a hint:
error: class type required but A with C found
new X(10)
^
X, as a type alias, gets rewritten to an A with C type expression, which is not a class type. The latter, according to the Scala Language Specification, is:
a type designator
(§
3.2.3
) that refers to a a class or a trait
(emphasis mine)
In other words, it's not every type expression.
This is not an authoritative answer, but I don't believe it's possible to define a type alias in such a way that it becomes a class type. On the one hand, a new expression theoretically accepts an AnnotType, as defined in Section 5.1.1. However, I don't see how, using the type alias grammar from Section 4.3, you could specify what constructor are you using etc..
tl;dr - unless your type alias is directly rewritable to a class type (e.g. A in your example), you can't use it as a class type, which includes invoking new with it. If you want that, you need a class declaration, i.e. class X(a: Int) extends A(a) with C.
Regarding your second question, you say you can't instantiate X. Ah, but that's where you're wrong! Let me show you an example, based on your code:
def blah(x: X) = x.toString
val x = new A(10) with C
val y = new A(10)
blah(x) //String = A(10)
blah(y) //type error
So, it's useful whenever you need a type constraint, since the "aliased" type will be matched to the type alias, even if it wasn't explicitly declared as such.

Related

Scala cast to generic type

I'm confused about the generic type. I expect that 2.asInstanceOf[A] is cast to the type A, meanwhile, it's cast to Int.
Besides that, the input is java.lang.Long whereas the output is a list of Int (according to the definition the input and the output should be the same type). Why is that?
def whatever[A](x: A): List[A] = {
val two = 2.asInstanceOf[A]
val l = List(1.asInstanceOf[A],2.asInstanceOf[A])
println(f"Input type inside the function for 15L: ${x.getClass}")
println(f"The class of two: ${two.getClass}, the value of two: $two")
println(f"The class of the first element of l: ${l.head.getClass}, first element value: ${l.head}")
l
}
println(f"Returned from whatever function: ${whatever(15L)}")
the outupt:
Input type inside the function for 15L: class java.lang.Long
The class of two: class java.lang.Integer, the value of two: 2
The class of the first element of l: class java.lang.Integer, first element value: 1
Returned from whatever function: List(1, 2)
a.asInstanceOf[B] means:
Dear compiler;
Please forget what you think the type of a is. I know better. I know that if a isn't actually type B then my program could blow up, but I'm really very smart and that's not going to happen.
Sincerely yours, Super Programmer
In other words val b:B = a.asInstanceOf[B] won't create a new variable of type B, it will create a new variable that will be treated as if it were type B. If the actual underlying type of a is compatible with type B then everything is fine. If a's real type is incompatible with B then things blow up.
Type erasure. For the purposes of type checking 2 is cast to A; but at a later compilation stage A is erased to Object, so your code becomes equivalent to
def whatever(x: Object): List[Object] = {
val two = 2.asInstanceOf[Object]
val l = List(1.asInstanceOf[Object],2.asInstanceOf[Object])
println(f"Input type inside the function for 15L: ${x.getClass}")
println(f"The class of two: ${two.getClass}, the value of two: $two")
println(f"The class of the first element of l: ${l.head.getClass}, first element value: ${l.head}")
l
}
2.asInstanceOf[Object] is a boxing operation returning a java.lang.Integer.
If you try to actually use the return value as a List[Long] you'll eventually get a ClassCastException, e.g.
val list = whatever(15L)
val x = list(0)
x will be inferred to be Long and a cast inserted to unbox the expected java.lang.Long.
The answer from #jwvh is on point. Here I'll only add a solution in case you want to fix the problem of safely converting an Int to an A in whatever, without knowing what A is. This is of course only possible if you provide a way to build a particular A from an Int. We can do this in using a type-class:
trait BuildableFromInt[+A] {
def fromInt(i: Int): A
}
Now you only have to implicitly provide BuildableFromInt for any type A you wish to use in whatever:
object BuildableFromInt {
implicit val longFromInt: BuildableFromInt[Long] = Long.box(_)
}
and now define whatever to only accept compliant types A:
def whatever[A : BuildableFromInt](x: A): List[A] = {
val two = implicitly[BuildableFromInt[A]].fromInt(2)
// Use two like any other "A"
// ...
}
Now whatever can be used with any type for which a BuildableFromInt is available.

scala's type checker doesn't recognize types in abstract path-dependent classes scenario

Let's define a trait with an abstract class
object Outer {
trait X {
type T
val empty: T
}
Now we can make an instance of it:
val x = new X {
type T = Int
val empty = 42
}
Scala now recognizes, that x.empty is an Int:
def xEmptyIsInt = x.empty: Int
Now, let's define an other class
case class Y(x: X) extends X {
type T = x.T
val empty = x.empty
}
and make an instance of it
val y = Y(x)
But now Scala, isn't able to infer that y.empty is of type Int. The following
def yEmptyIsInt = y.empty: Int
now produces an error message:
error: type mismatch;
found : y.x.T
required: Int
y.empty : Int
Why is this the case? Is this a scala bug?
We can mitigate this issue by introducing a parameters to the case class:
case class Z[U](x: X { type T = U }) extends X {
type T = U
val empty = x.empty
}
Then it works again
val z = Z(x)
def zEmptyIsInt: Int = z.empty
But we always have to mention all the types inside X at call-site. This ideally should be an implementation detail which leads to the following approach:
case class A[U <: X](z: U) extends X {
type T = z.T
val empty = z.empty
}
This also mitigates the issue
val a = A(x)
def aEmptyIsInt: Int = a.empty
}
So, to summarize, my questions are the following: Why does the simple case doesn't work? Is this a valid workaround? What other problems might come up when we follow one of the two workaround approaches? Is there a better approach?
You've re-used x for different things, so from here on I'll call the object instantiated by val x "instance x" and the x: X used in class Y "parameter x".
"Instance x" is an anonymous subclass of trait X with concrete members overriding trait X's abstract members. As a subclass of X you can pass it to the constructor for case class Y and it will be accepted happily, since as a subclass it is an X.
It seems to me you expect that case class Y will then check at runtime to see if the instance of X it is passed has overridden X's members, and generate an instance of Y whose members have different types depending on what was passed in.
This is emphatically not how Scala works, and would pretty much defeat the purpose of its (static) type system. For example, you wouldn't be able to do anything useful with Y.empty without runtime reflection since it could have any type at all, and at that point you're better off just using a dynamic type system. If you want the benefits of parametricity, free theorems, not needing reflection, etc. then you have to stick to statically determined types (with a small exception for pattern matching). And that's what Scala does here.
What actually happens is that you've told Y's constructor that parameter x is an X, and so the compiler statically determines that x.empty, has the type of X.empty, which is abstract type T. Scala's inference isn't failing; your types are actually mismatched.
Separately, this doesn't really have anything to do with path-dependent types. Here is a good walkthrough, but in short, path-dependent types are bound to their parent's instance, not determined dynamically at runtime.

What's the rule to implement an method in trait?

I defined a trait:
trait A {
def hello(name:Any):Any
}
Then define a class X to implement it:
class X extends A {
def hello(name:Any): Any = {}
}
It compiled. Then I change the return type in the subclass:
class X extends A {
def hello(name:Any): String = "hello"
}
It also compiled. Then change the parameter type:
class X extends A {
def hello(name:String): Any = {}
}
It can't compiled this time, the error is:
error: class X needs to be abstract, since method hello in trait A of type (name: Any)
Any is not defined
(Note that Any does not match String: class String in package lang is a subclass
of class Any in package scala, but method parameter types must match exactly.)
It seems the parameter should match exactly, but the return type can be a subtype in subclass?
Update: #Mik378, thanks for your answer, but why the following example can't work? I think it doesn't break Liskov:
trait A {
def hello(name:String):Any
}
class X extends A {
def hello(name:Any): Any = {}
}
It's exactly like in Java, to keep Liskov Substitution principle, you can't override a method with a more finegrained parameter.
Indeed, what if your code deals with the A type, referencing an X type under the hood.
According to A, you can pass Any type you want, but B would allow only String.
Therefore => BOOM
Logically, with the same reasonning, a more finegrained return type is allowed since it would be cover whatever the case is by any code dealing with the A class.
You may want to check those parts:
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Covariant_method_return_type
and
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Contravariant_method_argument_type
UPDATE----------------
trait A {
def hello(name:String):Any
}
class X extends A {
def hello(name:Any): Any = {}
}
It would act as a perfect overloading, not an overriding.
In Scala, it's possible to have methods with the same name but different parameters:
class X extends A {
def hello(name:String) = "String"
def hello(name:Any) = "Any"
}
This is called method overloading, and mirrors the semantics of Java (although my example is unusual - normally overloaded methods would do roughly the same thing, but with different combinations of parameters).
Your code doesn't compile, because parameter types need to match exactly for overriding to work. Otherwise, it interprets your method as a new method with different parameter types.
However, there is no facility within Scala or Java to allow overloading of return types - overloading only depends on the name and parameter types. With return type overloading it would be impossible to determine which overloaded variant to use in all but the simplest of cases:
class X extends A {
def hello: Any = "World"
def hello: String = "Hello"
def doSomething = {
println(hello.toString) // which hello do we call???
}
}
This is why your first example compiles with no problem - there is no ambiguity about which method you are implementing.
Note for JVM pedants - technically, the JVM does distinguish between methods with different return types. However, Java and Scala are careful to only use this facility as an optimisation, and it is not reflected in the semantics of Java or Scala.
This is off the top of my head, but basically for X.hello to fit the requirements of A.hello, you need for the input of X.hello to be a superclass of A.hello's input (covariance) and for the output of X.hello to be a subclass of A.hello's output(contravariance).
Think of this is a specific case of the following
class A
class A' extends A
class B
class B' extends B
f :: A' -> B
g :: A -> B'
the question is "Can I replace f with g in an expression y=f(x) and still typecheck in the same situations?
In that expression, y is of type B and x is of type A'
In y=f(x) we know that y is of type B and x is of type A'
g(x) is still fine because x is of type A' (thus of type A)
y=g(x) is still fine because g(x) is of type B' (thus of type B)
Actually the easiest way to see this is that y is a subtype of B (i.e. implements at least B), meaning that you can use y as a value of type B. You have to do some mental gymnastics in the other thing.
(I just remember that it's one direction on the input, another on the output, and try it out... it becomes obvious if you think about it).

Scala - how to go resolve "Value is not a member of Nothing" error

This example code is based on Atmosphere classes, but if someone could give me some insights into what the error means in general, I think I can figure out any Atmosphere-specific solution...
val bc = BroadcasterFactory.getDefault().lookup(_broadcasterId)
bc.broadcast(message)
After the first line, bc should contain a handle to an object whose class definition includes the method broadcast() -- in fact, it contains several overloaded variations. However, the compiler chokes on the second line of code with the following: "value broadcast is not a member of Nothing"
Any ideas/suggestions on what would be causing this?
Thanks.
EDIT: signature for [BroadcasterFactor].lookup :
abstract Broadcaster lookup(Object id)
Note: 1) that is the signature version that I've used in the example, 2) it is the java Inteface signature - whereas the getDefault() hands back an instantiated object that implements that interface.
Solution: force type cast on value:
val bc: Broadcaster = BroadcasterFactory.getDefault().lookup(_broadcasterId)
Nothing is the type name. It's the subtype of all other types. You can't call methods from Nothing itself, you have to specify exact type ((bc: ExactType).broadcast(message)). Nothing has no instances. Method, that returns Nothing will, actually, never return value. It will throw an exception eventually.
Type inference
Definition of lookup:
abstract public <T extends Broadcaster> T lookup(Object id);
in scala this definition looks this way:
def lookup[T <: Broadcaster](Object id): T
There is not specified type parameter in lookup method. In this case compiler will infer this type parameter as the most specific type - Nothing:
scala> def test[T](i: Int): T = ???
test: [T](i: Int)T
scala> lazy val x = test(1)
x: Nothing = <lazy>
scala> lazy val x = test[String](1)
x: String = <lazy>
You could specify type parameter like this:
val bc = BroadcasterFactory.getDefault().lookup[Broadcaster](_broadcasterId)
Draft implementation
In development process lookup can be "implemented" like this:
def lookup(...) = ???
??? returns Nothing.
You should specify either result type of lookup method like this: def lookup(...): <TypeHere> = ... or type of bc: val bc: <TypeHere> =.

Scala priority of method call on implicit object

Let's say I have the following scala code:
case class Term(c:Char) {
def unary_+ = Plus(this)
}
case class Plus(t:Term)
object Term {
implicit def fromChar(c:Char) = Term(c)
}
Now I get this from the scala console:
scala> val p = +'a'
p: Int = 97
scala> val q:Plus = +'a'
<console>:16: error: type mismatch;
found : Int
required: Plus
val q:Plus = +'a'
^
Because '+' is already present on the Char type, the implicit conversion does not take place, I think. Is there a way to override the default behaviour and apply '+' on the converted Term before applying on the Char type?
(BTW, the example is artificial and I'm not looking for alternative designs. The example is just here to illustrate the problem)
No, there is no way to override the default + operator, not even with an implicit conversion. When it encounters an operator (actually a method, as operators are just plain methods) that is not defined on the receiving object, the compiler will look for an implicit conversion to an object to does provide this operator. But if the operator is already defined on the target object, it will never look up for any conversion, the original operator will always be called.
You should thus define a separate operator whose name will not conflict with any preexisting operator.
UPDATE:
The precise rules that govern implicit conversions are defined in the Scala Language Specification:
Views are applied in three situations.
If an expression e is of type T , and T does not conform to the expression’s
expected type pt. In this case an implicit v is searched which is applicable to
e and whose result type conforms to pt. The search proceeds as in the case of
implicit parameters, where the implicit scope is the one of T => pt. If such a
view is found, the expression e is converted to v(e).
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.
In a selection e.m(args) with e of type T , if the selector m denotes some member(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 contains 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 T . If such a
view is found, the selection e.m is converted to v(e).m(args).
In other words, an implicit conversion occurs in 3 situations:
when an expression is of type T but is used in a context where the unrelated type T' is expected, an implicit conversion from T to T' (if any such conversion is in scope) is applied.
when trying to access an object's member that does not exists on said object, an implicit conversion from the object into another object that does have this member (if any such conversion is in scope) is applied.
when trying to call a method of an object's with a parameter list that does not match any of the corresponding overloads, the compiler applies an implicit conversion from the object into another object that does have a method of this name and with a compatible parameter list (if any such conversion is in scope).
Note for completeness that this actually applies to more than just methods (inner objects/vals with an apply method are eligible too). Note also that this is the case that Randall Schulz was talking about in his comment below.
So in your case, points (2) and (3) are relevant. Given that you want to define a method named unary_+, which already exists for type Int, case (2) won't kick in. And given that your version has the same parameter list as the built-in Int.unary_+ method (they are both parameterless), point (3) won't kick in either. So you definitly cannot define an implicit that will redefine unary_+.