Scala not resolving X as Y, even though X extends Y
-
22-12-2019 - |
Pergunta
[See snippet Below] I read that I have a X which is a Piece, and I have a Player that requires a Piece. The player Me attempts to define this Piece with Piece X. Yet the Scala does not recognize X as a piece, rather it sees 'X.type'. What does X.type mean? I'm not exactly sure what my problem is so I'm having a hard time searching.
I don't see how this can be type shadowing [ See Scala really weird Type Mismatch ], since I don't specify another 'Piece', rather I only specify that I require a 'Piece'.
It seems like there is something preventing Scala to resolve X as a Piece.
To try in REPL
trait Piece { val piece: Char }
case class X extends Piece { val piece: Char = 'X' }
trait Player { val piece: Piece }
case class Me extends Player { val piece: Piece = X }
Result
error: type mismatch;
found : X.type
required: Piece
case class Max extends Player { val piece: Piece = X }
Solução
That is probably because by X you're only describing a class (so it's actually a type), whereas Scala is expecting an object (or instance) of type Piece. You would get the same error by doing this in the first case:
case class X extends Piece { val piece: Char = Char }
As you can see, your version works because you pass a specific character, not a type. If you want your code to work, you probably have to create a new object and pass it in:
case class Me extends Player { val piece: Piece = new X }
EDIT: As the OP noted in the comment below, using X() also works, because as X is a case class it gets an implicit apply() method:
case class Me extends Player { val piece: Piece = X() }
Outras dicas
Case classes without parameters are deprecated. Use case class X()
and case class Me()
instead. That way you will have to create object of X
class with X()
call, as is described in other answers.
Alternatively you can use case object
s:
case object X extends Piece { val piece: Char = 'X' }.
In fact, if you use case object here, your code will start to work:
case class Me extends Player { val piece: Piece = X } // Works fine
It depends on your requirements though. It is possible that you need multiple instances of X
; then case object is not for you.
When you write case class X
, you're also creating a companion object X
, which has a member apply
that lets you say X()
. All this is obvious after some experience with Scala.
X.type
is the singleton type of the object X. It has nothing to do with "assigning a type", as the other answers put it.
When you say X
as a value, it means that object. It is a term (i.e. value), not a type.
To create a new X, everyone writes X()
, which is exactly X.apply()
, and never new X()
. Never? Yeah, pretty much never.
Note that paramless case classes are long since deprecated.
You are assigning the type X
to the variable piece
, rather than an instance of X
.