Usages de Null / Nothing / Unit dans Scala


95

Je viens de lire: http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

Autant que je sache, Nullc'est un trait et son seul exemple est null.

Lorsqu'une méthode prend un argument Null, alors nous ne pouvons lui passer qu'une Nullréférence ou nulldirectement, mais pas toute autre référence, même si elle est nulle ( nullString: String = nullpar exemple).

Je me demande simplement dans quels cas l'utilisation de ce Nulltrait pourrait être utile. Il y a aussi le trait Nothing pour lequel je ne vois plus vraiment d'exemples.


Je ne comprends pas vraiment non plus quelle est la différence entre l'utilisation de Nothing et Unit comme type de retour, puisque les deux ne retournent aucun résultat, comment savoir laquelle utiliser quand j'ai une méthode qui effectue la journalisation par exemple?


Avez-vous des utilisations de Unit / Null / Nothing comme autre chose qu'un type de retour?

Réponses:


80

Vous n'utilisez Nothing que si la méthode ne retourne jamais (ce qui signifie qu'elle ne peut pas se terminer normalement en retournant, elle pourrait lever une exception). Rien n'est jamais instancié et est là pour le bénéfice du système de types (pour citer James Iry: "La raison pour laquelle Scala a un type inférieur est liée à sa capacité à exprimer la variance des paramètres de type." ). De l'article auquel vous avez lié:

Une autre utilisation de Nothing est comme type de retour pour les méthodes qui ne retournent jamais. Cela a du sens si vous y réfléchissez. Si le type de retour d'une méthode est Nothing et qu'il n'existe absolument aucune instance de Nothing, une telle méthode ne doit jamais retourner.

Votre méthode de journalisation renverrait Unit. Il existe une valeur Unit afin qu'elle puisse être retournée. À partir de la documentation de l' API :

Unit est un sous-type de scala.AnyVal. Il n'existe qu'une seule valeur de type Unit, (), et elle n'est représentée par aucun objet dans le système d'exécution sous-jacent. Une méthode avec le type de retour Unit est analogue à une méthode Java qui est déclarée void.


2
Merci, par "ne retourne jamais" signifie que l'appel se bloque indéfiniment (par exemple la méthode de démarrage du planificateur de tâches?)
Sebastien Lorber

3
@Sabastien: il ne retourne pas normalement, il pourrait lancer une exception (voir james-iry.blogspot.com/2009/08/… ). si l'appel de blocage se termine uniquement par le lancement d'une exception, cela comptera. merci pour la question, cela avait besoin d'être clarifié.
Nathan Hughes

18

L'article que vous citez peut être trompeur. Le Nulltype est là pour la compatibilité avec la machine virtuelle Java , et Java en particulier.

Nous devons considérer que Scala :

  • est complètement orienté objet: chaque valeur est un objet
  • est fortement typé: chaque valeur doit avoir un type
  • doit gérer des nullréférences pour accéder, par exemple, aux bibliothèques et au code Java

il devient donc nécessaire de définir un type pour la nullvaleur, qui est le Nulltrait, et qui a nullpour seule instance.

Il n'y a rien de particulièrement utile dans le Nulltype à moins que vous ne soyez le système de type ou que vous développiez sur le compilateur. En particulier, je ne vois aucune raison raisonnable de définir un Nullparamètre de type pour une méthode, car vous ne pouvez rien passer d'autre quenull


c'est vrai, donc à la fin il n'y a pas d'autre utilisation de Null?
Sebastien Lorber

@SebastienLorber a modifié la réponse. Je ne vois aucune utilisation pour le développeur moyen. Peut-être que quelqu'un d'autre peut penser à quelque chose d'utile.
pagoda_5b

Merci pour cela. Si nous connaissons la raison de ce genre de choses, nous les comprenons, sinon nous nous en souvenons.
Sreekar le

Null est utile lorsque vous avez un paramètre de type et que vous souhaitez renvoyer null comme dans cette question et réponse , puisque vous êtes découragé d'utiliser null dans scala, cela arrive rarement, il peut également y avoir d'autres utilisations dans le système de types
Daniel Carlsson

15

Avez-vous des utilisations de Unit / Null / Nothing comme autre chose qu'un type de retour?


Unit peut être utilisé comme ceci:

def execute(code: => Unit):Unit = {
  // do something before
  code
  // do something after
}

Cela vous permet de passer un bloc de code arbitraire à exécuter.


Nullpeut être utilisé comme type inférieur pour toute valeur pouvant être Nullable. Un exemple est celui-ci:

implicit def zeroNull[B >: Null] =
    new Zero[B] { def apply = null }

Nothing est utilisé dans la définition de None

object None extends Option[Nothing]

Cela vous permet d'attribuer un Noneà n'importe quel type de Optioncar Nothing«étend» tout.

val x:Option[String] = None

D'accord. Pour votre utilisation de Unit, vous auriez pu utiliser un type générique afin que l'exécution puisse renvoyer ce type générique si votre bloc de code renvoie autre chose que unit.
Sebastien Lorber

Comme @drexin l'a dit dans un commentaire sur une autre réponse, il est principalement utilisé pour désigner un effet secondaire.
EECOLOR

6

si vous utilisez Nothing, il n'y a rien à faire (inclure la console d'impression) si vous faites quelque chose, utilisez le type de sortieUnit

object Run extends App {
  //def sayHello(): Nothing = println("hello?")
  def sayHello(): Unit = println("hello?")
  sayHello()
}

... alors comment l'utiliser Nothing?

trait Option[E]
case class Some[E](value: E) extends Option[E]
case object None extends Option[Nothing]

1
De plus, Edans le Optiondoit être en position covariante: trait Option[+E]pour autoriser des choses commeval x: Option[Int] = None
vim

5

Je n'ai jamais réellement utilisé le Nulltype, mais vous utilisez Unit, là où vous utiliseriez java void. Nothingest un type spécial, car comme Nathan l'a déjà mentionné, il ne peut y avoir aucune instance de Nothing. Nothingest ce qu'on appelle un type inférieur, ce qui signifie qu'il s'agit d'un sous-type de tout autre type. Ceci (et le paramètre de type contravariant) est la raison pour laquelle vous pouvez ajouter n'importe quelle valeur à Nil- qui est un List[Nothing]- et la liste sera alors de ce type d'éléments. Noneégalement si de type Option[Nothing]. Chaque tentative d'accès aux valeurs à l'intérieur d'un tel conteneur lèvera une exception, car c'est le seul moyen valide de retourner à partir d'une méthode de type Nothing.


merci je ne savais pas que None étend l'option [rien]. Cela a du sens dans certains usages génériques où un sous-type pourrait utiliser Nothing (je suppose qu'il est difficile de trouver un exemple pour Null et Unit ...)
Sebastien Lorber

L'unité est utilisée, lorsque des effets secondaires se produisent, par exemple la monade IO peut être du type IO[Unit]pour l'impression sur la console et similaire.
drexin

Oui, jamais utilisé la monade IO, il est logique de l'utiliser avec Unit (et peut-être rien si c'est une opération IO qui produit un flux infini?)
Sebastien Lorber

Non, rien n'a de sens là-bas.
drexin

3

Rien n'est souvent utilisé implicitement. Dans le code ci-dessous, val b: Boolean = if (1 > 2) false else throw new RuntimeException("error") la clause else est de type Nothing , qui est une sous-classe de Boolean (ainsi que tout autre AnyVal). Ainsi, toute l'affectation est valide pour le compilateur, bien que la clause else ne renvoie vraiment rien.


1

Voici un exemple de Nothingde scala.predef:

  def ??? : Nothing = throw new NotImplementedError

Si vous n'êtes pas familier (et que les moteurs de recherche ne peuvent pas effectuer de recherche), ???la fonction d'espace réservé de Scala pour tout ce qui n'a pas encore été implémenté. Tout comme KotlinTODO .

Vous pouvez utiliser la même astuce lors de la création d'objets fictifs: remplacez les méthodes inutilisées par une notUsedméthode personnalisée . L'avantage de ne pas utiliser ???est que vous n'obtiendrez pas d'avertissements de compilation pour des choses que vous n'avez jamais l'intention d'implémenter.


0

En termes de théorie des catégories Rien n'est un objet initial et Unit est un objet terminal .

https://en.wikipedia.org/wiki/Initial_and_terminal_objects

Les objets initiaux sont également appelés coterminaux ou universels , et les objets terminaux sont également appelés finaux .

Si un objet est à la fois initial et terminal , il est appelé objet zéro ou objet nul .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.