Pourquoi n'avons-nous pas deux nuls?
Je me suis souvent demandé pourquoi les langues avec un null
représentant "Aucune valeur" ne font pas la différence entre le passif "Je ne sais pas quelle est la valeur" et le plus affirmatif " il n'y a pas de valeur.".
Il y a eu plusieurs cas où j'aurais aimé faire la différence entre les deux (en particulier lorsque je travaille avec l'entrée utilisateur et les bases de données).
J'imagine ce qui suit, où nous nommons les deux états unknown
et null
:
var apple;
while (apple is unknown)
{
askForApple();
}
if (apple is null)
{
sulk();
}
else
{
eatApple(apple);
}
Évidemment, nous peut s'en passer en stockant manuellement l'état quelque part ailleurs, mais nous pouvons le faire pour les valeurs nulles aussi .
Donc, si nous pouvons avoir un null
, pourquoi ne pouvons-nous pas avoir les deux?
27 réponses
Dans ma programmation, j'ai récemment adopté la pratique de différencier "language null" et "domain null".
Le "language null" est la valeur spéciale fournie par le langage de programmation pour exprimer qu'une variable n'a "aucune valeur". Il est nécessaire comme valeur fictive dans les structures de données, les listes de paramètres et les valeurs de retour.
Le "domaine null" est un nombre quelconque d'objets qui implémentent le modèle de conception NullObject. En fait, vous avez un domaine null distinct pour chacun le contexte d'un domaine.
Il est assez courant pour les programmeurs d'utiliser le langage null comme un domaine catch-all null, mais j'ai trouvé qu'il tend à rendre le code plus procédural (moins orienté objet) et l'intention plus difficile à discerner.
Chaque fois que vous voulez un null, demandez-vous: est-ce un langage null, ou un domaine null?
Dans la plupart des langages de programmation null signifie "vide" ou "indéfini". "Inconnu" d'autre part est quelque chose de différent. En substance, "inconnu", décrit l'état de l'objet. Cet État doit provenir de quelque part dans votre programme.
Regardez le modèle D'objet Null . Il peut vous aider avec ce que vous essayez d'atteindre.
Javascript a en fait null et undefined ( http://www.w3schools.com/jsref/jsref_undefined.asp ), mais beaucoup d'autres langues ne le font pas.
, Il serait assez facile de créer une constante statique indiquant inconnu, pour les rares cas où vous auriez besoin d'une telle chose.
var apple = Apple.Unknown;
while (apple == Apple.Unknown) {} // etc
Existence de la valeur:
- Python:
vars().has_key('variableName')
- PHP:
isset(variable)
- JavaScript:
typeof(variable) != 'undefined'
- Perl:
(variable != undef)
, ou si vous le souhaitez:(defined variable)
Bien sûr, lorsque la variable n'est pas définie, elle n'est pas nulle
Note null
est une condition acceptable, mais connue. Un état inconnu est une chose différente IMO. Ma conversation avec Dan dans la section des commentaires du poste supérieur clarifiera ma position. Merci Dan!.
Ce que vous voulez probablement interroger est de savoir si l'objet a été initialisé ou non.
Actionscript a une telle chose (null
et undefined
). Avec quelques restrictions cependant.
Voir documentation:
Type de données vide
Le vide le type de données ne contient qu'une seule valeur, indéfinie. Dans les versions précédentes D'ActionScript, undefined était la valeur par défaut pour les instances de la classe Object. Dans ActionScript 3.0, la valeur par défaut pour les instances D'objet est null. Si vous essayez d'attribuer la valeur undefined à une instance de la classe Object, Flash Player ou Adobe AIR convertiront la valeur en null. Vous ne pouvez attribuer une valeur de undefined qu'à des variables non typées. Les variables non typées sont des variables qui manquent de tout type annotation, ou utilisez le symbole astérisque ( * ) pour l'annotation de type. Vous pouvez utiliser void uniquement comme annotation de type de retour.
Pourquoi s'arrêter à deux?
Quand j'ai pris des bases de données au collège, on nous a dit que quelqu'un (désolé, ne se souvient pas du nom du chercheur ou du papier) avait regardé un tas de schémas db et trouvé que null avait quelque chose comme 17 significations différentes: "ne sait pas encore", "ne peut pas être connu", "ne s'applique pas", "aucun", "vide", "action non prise", "champ non utilisé", et ainsi de suite.
Le type Null est un sous-type de tous les types de référence - vous pouvez utiliser null au lieu d'une référence à n'importe quel type d'objet - ce qui affaiblit gravement le système de type. Il est considéré comme l'une des a historiquement mauvaise idée par son Créateur, et existe seulement comme vérifier si une adresse est nulle est facile à mettre en œuvre.
Quant à Pourquoi nous n'avons pas deux null, Est-ce dû au fait que, historiquement en C, NULL était un simple #define
et pas une partie distincte du langage?
Dans PHP Strict, vous devez faire un isset()
Vérifier les variables set (ou bien il lance un avertissement)
if(!isset($apple))
{
askForApple();
}
if(isset($apple) && empty($apple))
{
sulk();
}
else
{
eatApple();
}
Dans les langages. Net, vous pouvez utiliser nullable types , qui résolvent ce problème pour les types de valeur.
Le problème demeure, cependant, pour les types de référence. Comme il n'y a pas de pointeurs dans. net (au moins dans les blocs 'sûrs'), " object? o " ne compilera pas.
Le problème est que dans un langage fortement typé ces valeurs null sont censé contenir des informations spécifiques sur le type.
Fondamentalement, votre null supplémentaire est une méta-information d'une sorte, une méta-information qui peut dépendre du type.
Certains types de valeur ont cette information supplémentaire, par exemple de nombreux types numériques ont une constante NaN.
Dans un langage typé dynamiquement, vous devez tenir compte de la différence entre une référence sans valeur (null) et une variable où le type peut être n'importe quoi (inconnu ou indéfini)
Ainsi, par exemple, en C # typé statiquement, une variable de type String
peut être null, car c'est un type de référence. Une variable de type Int32
ne peut pas, car c'est un type de valeur, elle ne peut pas être null. Nous connaissons toujours le type.
En Javascript typé dynamiquement, le type d'une variable peut être laissé indéfini, auquel cas la distinction entre une référence nulle et une valeur indéfinie est nécessaire.
Dans haskell, vous pouvez définir quelque chose comme ceci:
data MaybeEither a b = Object a
| Unknown b
| Null
deriving Eq
main = let x = Object 5 in
if x == (Unknown [2]) then putStrLn ":-("
else putStrLn ":-)"
L'idée étant que les valeurs inconnues contiennent des données de type b
qui peuvent les transformer en valeurs connues (comment vous le feriez dépend des types concrets a
et b
).
Le lecteur observateur remarquera que je combine juste peut-être et soit en un seul type de données:)
Certaines personnes diront que nous devrions nous débarrasser de null
carrément, ce qui semble assez valable. Après tout, pourquoi s'arrêter à deux nulls? Pourquoi pas trois ou quatre, et ainsi de suite, chacun représentant un "aucune valeur" état?
Imaginez ce, avec refused
, null
, invalid
:
var apple;
while (apple is refused)
{
askForApple();
}
if (apple is null)
{
sulk();
}
else if(apple is invalid)
{
discard();
}
else
{
eatApple(apple);
}
Il a été essayé: Visual Basic 6 n'avait rien, Null et vide. Et cela a conduit à un code si pauvre, il a figuré au # 12 dans le légendaire treize façons de détester VB article dans Dr Dobbs.
Utilisez le modèle D'objetNull à la place, comme d'autres l'ont suggéré.
Certaines personnes ont déjà une longueur d'avance sur vous. ;)
Compte tenu du temps qu'il a fallu à la philosophie occidentale pour comprendre comment il était possible de parler du concept de "rien"... Ouais, Je ne suis pas trop surpris que la distinction ait été négligée pendant un moment.
Je pense qu'avoir un NULL est un dénominateur commun inférieur pour traiter le modèle de base
if thing is not NULL
work with it
else
do something else
Dans la partie" faire autre chose", il y a un large éventail de possibilités allant de "OK, oubliez ça" à essayer d'obtenir "chose" ailleurs. Si vous n'ignorez pas simplement quelque chose qui est nul, vous devez probablement savoir pourquoi "chose" était nul. Avoir plusieurs types de NULL, vous aiderait à répondre à cette question, mais les réponses possibles sont nombreuses comme indiqué dans les autres réponses ici. Le chose manquante pourrait être simplement un bug, il pourrait être une erreur en essayant de l'obtenir, il peut ne pas être disponible en ce moment, et ainsi de suite. Pour décider quels cas s'appliquent à votre code - ce qui signifie que vous devez les gérer-il est spécifique au domaine. Il est donc préférable d'utiliser un mécanisme défini par l'application pour encoder ces raisons au lieu de trouver une fonctionnalité de langage qui essaie de les traiter toutes.
C'est parce que Null est un artefact de la langue que vous utilisez, pas une commodité de programmeur. Il décrit un état naturel de l'objet dans le contexte dans lequel il est utilisé.
Si vous utilisez. net 3.0 + et avez besoin d'autre chose, vous pouvez essayer le peut-être Monad. Vous pouvez créer tous les types "peut-être" dont vous avez besoin et, en utilisant la syntaxe LINQ, traiter en conséquence.
AppleInformation appleInfo;
while (appleInfo is null)
{
askForAppleInfo();
}
Apple apple = appleInfo.apple;
if (apple is null)
{
sulk();
}
else
{
eatApple(apple);
}
D'abord, vous vérifiez si vous avez les informations apple, plus tard, vous vérifiez s'il y a une pomme ou non. Vous n'avez pas besoin d'un support de langue maternelle différent pour cela, utilisez simplement les bonnes classes.
Pour moi, null représente l'absence de valeur, et j'essaie de l'utiliser uniquement pour la représenter. Bien sûr, vous pouvez donner null autant de significations que vous le souhaitez, tout comme vous pouvez utiliser 0 ou -1 pour représenter les erreurs au lieu de leurs valeurs numériques. Donner diverses significations à une représentation pourrait être ambigu, donc je ne le recommanderais pas.
Vos exemples peuvent être codés comme apple.isRefused() ou !Apple.isValid() avec peu de travail; vous devriez définir à l'avance ce qui est une pomme invalide de toute façon, donc je ne voyez pas le gain d'avoir plus de mots clés.
Vous pouvez toujours créer un objet et l'affecter au même champ statique pour obtenir un 2ème null.
Par exemple, ceci est utilisé dans les collections qui permettent aux éléments d'être null. En interne, ils utilisent un private static final Object UNSET = new Object
qui est utilisé comme valeur non définie et vous permet ainsi de stocker null
s dans la collection. (Si je me souviens bien, le framework de collection de Java appelle cet objet TOMBSTONE au lieu de UNSET. Ou était le cadre de collecte de ce Smalltalk?)
VB6
- rien = > " il n'y a pas de valeur."
- Null = > "Je ne sais pas quelle est la valeur" - identique à DBNull.Valeur dans. NET
Deux null seraient la réponse la plus erronée. Si un null ne suffit pas, vous avez besoin de nulls infinity.
Null peut signifier:
- "non Initialisé"
- 'L'utilisateur n'a pas spécifié'
- 'ne S'applique pas ici, la couleur d'une voiture avant qu'elle ait été peinte'
- ' Unity: ce domaine ne contient aucune information.'
- 'vide: ceci ne contient correctement Aucune donnée dans ce cas, par exemple la dernière fois que les pneus ont été tournés sur une nouvelle voiture'
- 'Multiple, En Cascade nulls: par exemple, l'extension d'un prix de quantité lorsqu'aucune quantité ne peut être spécifiée multiplie une quantité qui n'a pas été spécifiée par l'utilisateur de toute façon '
Et votre domaine particulier peut avoir besoin de nombreux autres types de valeurs "hors bande". Vraiment, ces valeurs sont dans le domaine, et doivent avoir une signification bien définie dans chaque cas. (ergo, l'infini est vraiment zéro)