Quais regras especiais o compilador scala possui para o tipo de unidade no sistema de tipos
oUnit
recebe tratamento especial pelo compilador ao gerar código de bytes, porque é análogo avoid
na jvm. Mas conceitualmente como um tipo no sistema de tipos scala, parece que também recebe tratamento especial na própria linguagem (exemplos abaixo).
Portanto, minha pergunta é esclarecer isso e entender quais mecanismos são usados e se realmente existe um tratamento especial para o problema.Unit
tipo.
Exemplo 1:
Para tipos de escala normais, comoSeq
, se um método retornarSeq
, então você deve retornarSeq
(ou um tipo mais específico que se estendeSeq
)
def foo1: Seq[Int] = List(1, 2, 3)
def foo2: Seq[Int] = Vector(1, 2, 3)
def foo3: Seq[Int] = "foo" // Fails
Os dois primeiros exemplos são compilados porqueList[Int]
eVector[Int]
são subtipos deSeq[Int]
. O terceiro falha porqueString
não é.
Mas se eu mudar o terceiro exemplo para retornarUnit
emboravai compilar e executar sem problemas, emboraString
não é um subtipo deUnit
:
def foo3(): Unit = "foo" // Compiles (with a warning)
Não conheço nenhum outro tipo pelo qual essa exceção seria permitida em scala. O compilador também possui regras especiais para oUnit
tipo no nível do sistema de tipos ou existe algum tipo de mecanismo mais geral em funcionamento, por exemplo uma conversão implícita.
Exemplo 2:
Também não estou claro como a unidade interage em situações em que as regras de variação normalmente seriam aplicadas.
Por exemplo, às vezes atingimos esse bug comFuture[Unit]
onde usamos acidentalmentemap
ao invés deflatMap
e crie umFuture[Future]
:
def save(customer: Customer): Future[Unit] = ... // Save to database
def foo: Future[Unit] = save(customer1).map(_ => save(customer2))
omap
está criando umFuture[Future[Unit]]
e o compilador requer umFuture[Unit]
. No entanto, isso compila!
No começo eu pensei que era porqueFuture[+T]
é covariante, mas na verdadeFuture[Unit]
não é um subtipo deUnit
então não parece ser isso.
Se o tipo for alterado paraBoolean
por exemplo, o compilador detecta o erro:
def save(customer: Customer): Future[Boolean] = ...
def foo: Future[Boolean] = save(customer1).map(_ => save(customer2)) // Compiler fails this
E para todos os outrosUnit
digite que não será compilado (excetoAny
PorqueFuture[Any]
passa a ser um subtipo deAny
por coincidência).
Então, o compilador tem regras especiais nesse caso? Ou há um processo mais geral acontecendo?