Hier, je déjeunais avec un ami et ils se plaignaient de null
en C #. Il a déclaré que null
était illogique. J'ai décidé de tester ses affirmations. J'ai donc testé quelques propositions logiques simples:
Console.WriteLine(null == null); //True
//Console.WriteLine(null == !!null); //BOOM
Console.WriteLine(10 >= null); //False
Console.WriteLine(10 <= null); //False
Console.WriteLine(!(10 >= null)); //True
Console.WriteLine(!(10 <= null)); //True
Vérifier l'égalité semble simple et c'est ce à quoi je m'attendrais. Les déclarations plus grandes/moins que sont cependant des contradictions logiques que je trouve vraiment déroutant! Ne devraient-ils pas les jeter? L'opération de négation jette comme vous vous en doutez.
Si j'essaie de faire des comparaisons (en dehors de l'égalité) en utilisant null
en Ruby ou en Python, j'obtiens une erreur de type du type "ne peut pas comparer un nombre à zéro". Pourquoi C # ne fait-il pas cela?
Excellente question.
Essayez de ne pas penser à null
comme une valeur spécifique mais plutôt "rien à voir ici." Le documentation définit null
comme
Le mot clé
null
est un littéral qui représente une référence null, qui ne fait référence à aucun objet.
Dans cet esprit, le fait que null
ne soit pas un objet signifie que les lois classiques de la pensée ne s’appliquent pas exactement à lui (ou, du moins, ne s’appliquent pas à lui de la même manière qu’il s’appliquerait à un réel. objet).
Cela étant dit, le fait que 10 >= null
et 10 <= null
soient tous deux false
n'est pas, à proprement parler, une contradiction - après tout, null
n'est littéralement rien. Si vous avez dit que 10 >= (some actual thing)
et 10 <= (some actual thing)
étaient tous les deux faux, alors cela serait clairement contradictoire, mais vous ne pouvez pas avoir une contradiction au sens classique du terme sans un objet réel. La définition de la loi par Aristote d'après métaphysique est la suivante:
Il est impossible qu'une même chose puisse appartenir et ne pas appartenir au même objet et, dans le même sens, et toutes les autres spécifications qui pourraient être faites, laissez-les être ajoutées pour répondre aux objections locales. .
Nous avons donc un peu une "échappatoire" dans un sens. Au moins, comme Aristote avait formulé la loi de la non-contradiction, elle faisait spécifiquement référence aux objets. Il existe bien entendu de nombreuses interprétations de la loi de la non-contradiction à ce stade.
Passons maintenant au cas de 10 + null
. Nous pourrions dire que c'est la même chose que null + 10
si c'est plus facile. Dans un sens, alors, que devrait-il se passer à ce stade - null
devrait-il "engloutir" les 10, ou devrions-nous simplement dire "10 + (rien du tout) devrait vraiment être égal à 10"? Honnêtement, je n'ai pas de réponse très convaincante ici d'un point de vue logique au-delà de dire «bon, c'est une sorte de choix de conception». Je suppose que les concepteurs de langage ont voulu distinguer 10 + null
de 10 + 0
, mais je n'ai pas de documentation pour le prouver. (En effet, il serait un peu étrange qu’ils soient identiques; après tout, 0 est une valeur réelle qui peut être construite à partir des nombres naturels, mais null
est "aucune valeur, quelle qu'elle soit").
Je sais que cela figure quelque part dans les spécifications linguistiques, ce n'est pas ce que je voudrais savoir. Je voudrais comprendre pourquoi ces violations logiques semblent exister ou si ma compréhension des lois logiques est incorrecte.
Le langage de programmation ne doit en aucun cas obéir à la philosophie. Des règles logiques implicites, car il s’agit d’un langage de programmation destiné à résoudre des problèmes concrets liés au secteur. Beaucoup de langues n'obéissent pas aux règles mêmes de la pensée mathématique, comme les expressions algébriques, la théorie des catégories et tout le reste, alors ...
10 doit être supérieur ou inférieur à null ... n'est-ce pas?
Non, "Le mot clé null est un littéral qui représente une référence null, qui ne fait référence à aucun objet". Selon les règles C#
, le compilateur analyse les opérateurs disponibles pour un type fourni et si l'un des participants est null
, résultat l'expression sera null
.
Rechercher opérateurs levés
Aussi, comment 10 + null peut-il être nul?
Voir au dessus.
Cela peut être utile si vous ne considérez pas la valeur «nulle» comme une valeur - c'est un concept de néant ou de manque de valeur. Ce n'est pas juste C # - vous rencontrerez la même chose en SQL (NULL + 'asdf' donnera NULL.)
Donc, des choses comme (NULL <10) en soi n’ont pas le sens le plus logique: vous comparez un concept de néant à un nombre réel. Techniquement, non, le néant n'est PAS inférieur à 10. Il n'est pas supérieur à 10 non plus. C'est pourquoi il retourne faux dans les deux cas.
La raison pour laquelle vous êtes mis à l'écart de NULL n'a rien à voir avec la logique. Voici un excellent exemple de la raison pour laquelle la valeur NULL en C # entraîne souvent des erreurs ou des bogues:
private NumericalAnalysis AnalyzeNumber(int someValue)
{
if (someCondition)
return null;
return new NumericalAnalysis(someValue);
}
... d'accord, nous pouvons maintenant appeler AnalyzeNumber () et commencer à travailler avec NumericalAnalysis:
NumericalAnalysis instance = AnalyzeNumber(3);
if (instance.IsPrime)
DoSomething();
... oups! Vous venez de rencontrer un bug. Vous avez appelé AnalyzeNumber () mais vous n'avez pas vérifié si la valeur de retour était null avant de l'utiliser. Après tout, AnalyzeNumber () renvoie parfois une valeur null - ainsi, lorsque instance.IsPrime est appelé, il va exploser. Vous devez littéralement faire un "si (myVar == null)" cochez chaque fois que cette fonction a été appelée - et si vous oubliez, vous venez de créer un bogue.
Je ne suis pas un concepteur de langage C #, donc (haussement d'épaules), mais personnellement, je le vois comme une défaillance du système de types d'origine, de sorte que ma tête peut simplement l'accepter tel quel.
La raison en est que logiquement, vous ne pouvez pas comparer une valeur déterministe (par exemple, int) avec une valeur indéterministe (nullable int), sans conversion préalable. Ce sont vraiment 2 types différents, mais les langages de programmation modernes essaient simplement de les mélanger à leur manière.
Je considère également le caractère nul comme une chose utile et utile, car nous n’avons jamais de données complètes ni les vouloir données complètes, nous n’en avons besoin que d’un sous-ensemble pour l’activité en cours.
Je crois que c'est pour des raisons historiques. La principale motivation pour ajouter des types de valeur Nullable à C # dans la version 2.0 du langage était de réduire les difficultés liées au travail avec des colonnes SQL Nullable dans ADO.NET. Par conséquent, l’ajout de nombres annulables a été conçu pour fonctionner comme dans SQL, et ainsi de suite.