Question

Chaque si souvent lorsque les programmeurs se plaignent sur les erreurs null / exceptions quelqu'un demande ce que nous faisons sans nul.

J'ai une idée de base de la fraîcheur des types d'options, mais je n'ai pas les compétences de connaissances ou les langues au mieux l'exprimer. Qu'est-ce qu'un grande explication de ce qui suit écrit dans une manière accessible au programmeur moyen que nous pourrions pointer cette personne vers?

  • Le inopportunité d'avoir des références / pointeurs être nulle par défaut
  • Comment les types d'options de travail, y compris des stratégies pour faciliter la vérification des cas nuls tels que
    • correspondance de motif et
    • compréhensions monades
  • Autre solution, comme un message manger nul
  • (d'autres aspects que je manqué)
Était-ce utile?

La solution

Je pense que le résumé succinct des raisons pour lesquelles nul est indésirable est que États dépourvus de sens ne doivent pas être représentable .

Supposons que je modélisant une porte. Il peut être dans l'un des trois états: ouvert, fermés mais non verrouillée et fermée et verrouillée. Maintenant, je pouvais modéliser le long des lignes de

class Door
    private bool isShut
    private bool isLocked

et il est clair comment cartographier mes trois états dans ces deux variables booléennes. Mais cela laisse une quatrième état indésirable disponible: isShut==false && isLocked==true. Parce que les types que j'ai choisis comme ma représentation admettre cet état, je dois dépenser effort mental pour faire en sorte que la classe ne fait jamais dans cet état (peut-être en codant explicitement un invariant). En revanche, si j'utilisais un langage avec des types de données algébriques ou vérifié énumérations qui me permet de définir

type DoorState =
    | Open | ShutAndUnlocked | ShutAndLocked

alors je pourrais définir

class Door
    private DoorState state

et il n'y a pas plus de soucis. Le système de type veillera à ce qu'il n'y a que trois états possibles pour une instance de class Door être dans c'est ce que les systèmes de type sont bons -.. Pouvoir explicitement toute une classe d'erreurs à la compilation

Le problème avec null est que chaque type de référence obtient cet état supplémentaire dans l'espace qui est généralement indésirable. Une variable string pourrait être une séquence de caractères, ou il pourrait être cette folle valeur null supplémentaire qui ne correspond pas dans mon domaine de problème. Un objet Triangle a trois Points, qui eux-mêmes ont des valeurs de X et Y, mais malheureusement les Points ou Triangle lui-même peut-être cette valeur nulle folle qui n'a pas de sens pour le domaine graphique des je travaille. Etc.

Lorsque vous avez l'intention de modéliser une valeur peut-inexistante, alors vous devriez opter pour explicitement. Si la façon dont je compte les gens du modèle est que chaque Person a une FirstName et un LastName, mais seulement certaines personnes ont MiddleNames, je voudrais dire quelque chose comme

class Person
    private string FirstName
    private Option<string> MiddleName
    private string LastName

string est supposé ici pour être un type non annulable. Ensuite, il n'y a pas d'établir invariants délicate et pas NullReferenceExceptions inattendue lorsque vous essayez de calculer la longueur du nom de quelqu'un. Le système de type garantit que toute transaction de code avec les comptes MiddleName pour la possibilité qu'il soit None, alors que toute transaction de code avec le FirstName peut supposer sans risque il y a une valeur là-bas.

Ainsi, par exemple, en utilisant le type ci-dessus, nous pourrions l'auteur de cette fonction stupide:

let TotalNumCharsInPersonsName(p:Person) =
    let middleLen = match p.MiddleName with
                    | None -> 0
                    | Some(s) -> s.Length
    p.FirstName.Length + middleLen + p.LastName.Length

sans soucis. En revanche, dans une langue avec des références nullables pour des types comme chaîne, en supposant alors

class Person
    private string FirstName
    private string MiddleName
    private string LastName

vous finissez par des choses comme authoring

let TotalNumCharsInPersonsName(p:Person) =
    p.FirstName.Length + p.MiddleName.Length + p.LastName.Length

qui explose si l'objet Personne entrant n'a pas l'invariant de tout étant non nulle, ou

let TotalNumCharsInPersonsName(p:Person) =
    (if p.FirstName=null then 0 else p.FirstName.Length)
    + (if p.MiddleName=null then 0 else p.MiddleName.Length)
    + (if p.LastName=null then 0 else p.LastName.Length)

ou peut-être

let TotalNumCharsInPersonsName(p:Person) =
    p.FirstName.Length
    + (if p.MiddleName=null then 0 else p.MiddleName.Length)
    + p.LastName.Length

en supposant que p assure premier / dernier sont là, mais du milieu peut être nulle, ou peut-être vous faire des vérifications qui jettent différents types d'exceptions, ou qui sait quoi. Tous ces choix de mise en œuvre et folles choses à penser parce que surgissent il y a cette stupide valeur représentable que vous ne voulez pas ou besoin.

Null ajoute généralement la complexité inutile. La complexité est l'ennemi de tous les logiciels, et vous devriez vous efforcer de réduire la complexité si cela est raisonnable.

(notez bien qu'il y ait plus de complexité à même ces exemples simples. Même si un FirstName ne peut pas être null, un string peut représenter "" (la chaîne vide), ce qui est probablement pas non plus un nom de personne que nous avons l'intention de modèle. en tant que tel, même avec des chaînes non-nullable, il pourrait encore être le cas que nous sommes « représentant des valeurs vides de sens ». Again, vous pouvez choisir de combattre ce soit par code conditionnel invariants et à l'exécution, ou en utilisant le système de type (par exemple d'avoir un type de NonEmptyString). Ce dernier est peut-être malavisé (types de « bons » sont souvent « fermé » sur un ensemble d'opérations communes, et par exemple NonEmptyString est pas fermé sur .SubString(0,0)), mais il montre plus de points dans l'espace de conception. A la fin de la journée, dans tout système de type donné, il y a une certaine complexité, il sera très bon pour se débarrasser, et d'autres la complexité qui est juste intrinsèquement plus difficile de se débarrasser. La clé de ce sujet est que dans presque tous système de type, le passage de « références nullables par défaut » à « références non nulle par défaut » est presque toujours un changement simple qui rend le un système de type beaucoup mieux à la complexité et aux prises en excluant certains types d'erreurs et d'états vides de sens. Il est donc assez fou que tant de langues ne cessent de répéter cette erreur encore et encore.)

Autres conseils

La chose agréable sur les types d'options n'est pas qu'ils sont en option. Il est que tous les autres types ne sont pas .

Parfois , nous devons être en mesure de représenter une sorte d'état "null". Parfois, nous devons représenter une option « sans valeur », ainsi que les autres valeurs possibles d'une variable peut prendre. Donc, une langue à plat cela va interdit d'être un peu estropié.

souvent , on n'a pas besoin, et permettant un tel état « nul » que les conduit à l'ambiguïté et de la confusion: chaque fois que j'accéder à une variable de type de référence dans .NET, je dois considérer que il peut être nULL .

Souvent, il ne sera jamais en fait est nulle, parce que les structures de programmeur du code afin qu'il puisse jamais arriver. Mais le compilateur ne peut pas vérifier que, et chaque fois que vous le voyez, vous devez vous demander « peut-il null soit? Ai-je besoin de vérifier null ici? »

Idéalement, dans les nombreux cas où nul n'a pas de sens, il ne devrait pas être autorisé .

C'est difficile à réaliser dans .NET, où presque tout peut être nul. Vous devez compter sur l'auteur du code que vous appelez à 100% disciplinée et cohérente et ont clairement documenté ce qui peut et ne peut pas être nulle, ou vous devez être paranoïaque et contrôle tout .

Toutefois, si les types ne sont pas annulable par défaut , alors vous n'avez pas besoin de vérifier si oui ou non ils sont nuls. Vous savez qu'ils ne peuvent jamais être nulle, car le vérificateur compilateur / de type Garantit que pour vous.

Et puis nous avons juste besoin d'une porte arrière pour les rares cas où nous ne nécessité de gérer un état nul. Ensuite, un type « option » peut être utilisé. Ensuite, nous permettons nulle dans les cas où nous avons pris une décision consciente que nous devons être en mesure de représenter la « aucune valeur » cas, et dans tous les cas, nous savons que la valeur ne sera jamais nulle.

Comme d'autres l'ont mentionné, en C # ou Java par exemple, nul ne peut vouloir dire deux choses:

  1. la variable est non initialisée. Cela devrait, idéalement, jamais se produire. Une variable ne doit pas exist à moins qu'il est initialisé.
  2. la variable contient des données « facultatives »: il doit être en mesure de représenter le cas où il n'y a pas de données . Ceci est parfois nécessaire. Peut-être que vous essayez de trouver un objet dans une liste, et vous ne savez pas à l'avance si oui ou non il est là. Ensuite, nous devons être en mesure de représenter qu ' « aucun objet n'a été trouvé ».

La deuxième signification doit être conservée, mais le premier devrait être entièrement éliminé. Et même le second sens ne doit pas être la valeur par défaut. C'est quelque chose que nous pouvons opter pour si et quand nous en avons besoin . Mais quand on n'a pas besoin d'être quelque chose facultative, nous voulons que le vérificateur de type garantie qu'il ne sera jamais nul.

Toutes les réponses à ce jour se concentrer sur pourquoi null est une mauvaise chose, et comment il est un peu pratique si une langue ne peut garantir que certaines valeurs seront jamais est nulle.

Ils ont ensuite continuer à penser que ce serait une très bonne idée si vous Impose les valeurs NULL pour tous valeurs, ce qui peut être fait si vous ajoutez un concept comme Option ou Maybe pour représenter les types cela ne peut pas toujours avoir une valeur définie. Telle est l'approche adoptée par Haskell.

Il est tout de bonnes choses! Mais il ne fait pas obstacle à l'utilisation de explicitement nullables / types non-nuls pour obtenir le même effet. Pourquoi, alors, est l'option toujours une bonne chose? Après tout, Scala prend en charge les valeurs nullables (est a , il peut donc travailler avec les bibliothèques Java), mais soutient Options aussi bien.

Q. Quels sont les avantages au-delà d'être en mesure d'éliminer nulls d'une langue tout à fait?

A. Composition

Si vous faites une traduction naïve de code null-courant

def fullNameLength(p:Person) = {
  val middleLen =
    if (null == p.middleName)
      p.middleName.length
    else
      0
  p.firstName.length + middleLen + p.lastName.length
}

à code prenant en compte l'option

def fullNameLength(p:Person) = {
  val middleLen = p.middleName match {
    case Some(x) => x.length
    case _ => 0
  }
  p.firstName.length + middleLen + p.lastName.length
}

il n'y a pas beaucoup de différence! Mais il est aussi un terribles façon d'utiliser les options ... Cette approche est beaucoup plus propre:

def fullNameLength(p:Person) = {
  val middleLen = p.middleName map {_.length} getOrElse 0
  p.firstName.length + middleLen + p.lastName.length
}

Ou même:

def fullNameLength(p:Person) =       
  p.firstName.length +
  p.middleName.map{length}.getOrElse(0) +
  p.lastName.length

Lorsque vous commencez à traiter Liste des options, il y a encore mieux. Imaginez que la liste people lui-même est en option:

people flatMap(_ find (_.firstName == "joe")) map (fullNameLength)

Comment ça marche?

//convert an Option[List[Person]] to an Option[S]
//where the function f takes a List[Person] and returns an S
people map f

//find a person named "Joe" in a List[Person].
//returns Some[Person], or None if "Joe" isn't in the list
validPeopleList find (_.firstName == "joe")

//returns None if people is None
//Some(None) if people is valid but doesn't contain Joe
//Some[Some[Person]] if Joe is found
people map (_ find (_.firstName == "joe")) 

//flatten it to return None if people is None or Joe isn't found
//Some[Person] if Joe is found
people flatMap (_ find (_.firstName == "joe")) 

//return Some(length) if the list isn't None and Joe is found
//otherwise return None
people flatMap (_ find (_.firstName == "joe")) map (fullNameLength)

Le code correspondant à des contrôles nuls (ou même ELVIS: les opérateurs) seraient douloureusement longtemps. Le vrai truc est ici l'opération de flatMap, qui permet la compréhension imbriquée des options et des collections d'une manière que les valeurs nullables ne peut jamais atteindre.

Puisque les gens semblent manquer il. null est ambigu

La date de naissance d'Alice est null. Qu'est-ce que cela signifie?

date de décès de Bob est null. Qu'est-ce que cela veut dire?

Une interprétation « raisonnable » pourrait être que la date de naissance d'Alice existe mais est inconnue, alors que Bob date de-mort n'existe pas (Bob est encore en vie). Mais pourquoi avons-nous à des réponses différentes?


Un autre problème. null est un cas limite

  • est null = null?
  • est nan = nan?
  • est inf = inf?
  • est +0 = -0?
  • est +0/0 = -0/0?

Les réponses sont habituellement "oui", "non", "oui", "oui", "non", "oui" respectivement. Crazy « mathématiciens » appel NaN « nullité » et dire qu'il compare égal à lui-même. SQL traite des nulls comme ne correspond pas à quoi que ce soit (de sorte qu'ils se comportent comme NaN). On se demande ce qui se passe lorsque vous essayez de stocker ± 8, ± 0, et NaN dans la même colonne de base de données (il y a 2 53 NaN, dont la moitié sont « négative »).

Pour aggraver les choses, les bases de données diffèrent dans leur façon NULL traiter, et la plupart d'entre eux ne sont pas cohérentes (voir Manipulation NULL dans SQLite pour un aperçu). Il est assez horrible.


Et maintenant l'histoire obligatoire:

J'ai récemment conçu une table de base de données (sqlite3) avec cinq colonnes a NOT NULL, b, id_a, id_b NOT NULL, timestamp. Parce qu'il est un schéma générique conçu pour résoudre un problème générique pour des applications assez arbitraires, il y a deux contraintes d'unicité:

UNIQUE(a, b, id_a)
UNIQUE(a, b, id_b)

id_a existe uniquement pour la compatibilité avec un design d'application existante (en partie parce que je ne suis pas venu avec une meilleure solution), et n'est pas utilisé dans la nouvelle application. En raison de la NULL fonctionne dans SQL façon, je peux insérer (1, 2, NULL, 3, t) et (1, 2, NULL, 4, t) et ne viole pas la première contrainte d'unicité (parce (1, 2, NULL) != (1, 2, NULL)).

Cela fonctionne précisément en raison de la façon dont NULL fonctionne dans une contrainte d'unicité sur la plupart des bases de données (sans doute il est donc plus facile de modéliser des situations, par exemple, pas deux personnes « monde réel » peuvent avoir le même numéro de sécurité sociale, mais pas tous les gens ont un ).


FWIW, sans avoir d'abord d'invoquer un comportement non défini, C ++ références ne peuvent pas «pointez sur » null, et il est impossible de construire une classe avec des variables membres de référence initialisés (si une exception est levée, ne la construction).

Sidenote: De temps en temps, vous voudrez peut-être des pointeurs mutuellement exclusifs (à savoir que l'un d'entre eux peut être non NULL), par exemple dans un type DialogState = NotShown | ShowingActionSheet UIActionSheet | ShowingAlertView UIAlertView | Dismissed iOS hypothétique. Au lieu de cela, je suis obligé de faire des choses comme assert((bool)actionSheet + (bool)alertView == 1).

inopportunité de HAVING références / pointeurs être nulle par défaut.

Je ne pense pas que ce soit la question principale avec nulls, la question principale avec nulls est qu'ils peuvent vouloir dire deux choses:

  1. La référence / pointeur est non initialisée: le problème est ici le même que celui mutabilité en général. D'une part, il est plus difficile d'analyser votre code.
  2. La variable étant nulle signifie réellement quelque chose: c'est le cas quels types d'options réellement Formaliser
  3. .

Langues qui en charge les types d'options interdisent généralement aussi ou découragent l'utilisation des variables non initialisées ainsi.

Comment types d'options de travail, y compris des stratégies pour faciliter la vérification des cas nuls tels que correspondance de motif.

Pour être efficaces, les types d'options doivent être pris en charge directement dans la langue. Sinon, il faut beaucoup de code plaque de la chaudière pour les simuler. Les filtrages et le type inférence sont deux caractéristiques linguistiques clés rendant les types d'options facile à travailler. Par exemple:

F #:

//first we create the option list, and then filter out all None Option types and 
//map all Some Option types to their values.  See how type-inference shines.
let optionList = [Some(1); Some(2); None; Some(3); None]
optionList |> List.choose id //evaluates to [1;2;3]

//here is a simple pattern-matching example
//which prints "1;2;None;3;None;".
//notice how value is extracted from op during the match
optionList 
|> List.iter (function Some(value) -> printf "%i;" value | None -> printf "None;")

Cependant, dans un langage comme Java sans soutien direct pour les types d'options, nous aurions quelque chose comme:

//here we perform the same filter/map operation as in the F# example.
List<Option<Integer>> optionList = Arrays.asList(new Some<Integer>(1),new Some<Integer>(2),new None<Integer>(),new Some<Integer>(3),new None<Integer>());
List<Integer> filteredList = new ArrayList<Integer>();
for(Option<Integer> op : list)
    if(op instanceof Some)
        filteredList.add(((Some<Integer>)op).getValue());

Une solution alternative, comme un message manger nul

Objective-C « un message Eating nul » n'est pas tant une solution comme une tentative d'alléger la douleur de la tête de contrôle nul. En fait, au lieu de lancer une exception d'exécution lorsque vous essayez d'appeler une méthode sur un objet null, l'expression est évaluée au lieu de se null. Incrédulité Suspendre, il est comme si chaque méthode d'instance commence par if (this == null) return null;. Mais il y a une perte d'information: vous ne savez pas si la méthode retourne null, car il est la valeur de retour valide, ou parce que l'objet est en fait nul. Il est un peu comme avalement d'exception, et ne fait pas de progrès aborder les questions Null décrites précédemment.

Assemblée nous a également connu sous le nom adresses des pointeurs non typées. C les mappée directement en tant que pointeurs typés, mais introduit le nul de Algol comme valeur unique pointeur, compatible avec tous les pointeurs typés. Le gros problème avec nul en C est que, puisque chaque pointeur peut être nul, on ne peut utiliser un pointeur en toute sécurité sans une vérification manuelle.

Dans les langues de niveau supérieur, ayant nul est maladroit, car il transmet vraiment deux notions distinctes:

  • Dire que quelque chose est undefined .
  • Dire que quelque chose est option .

Avoir des variables non définies est à peu près inutile, et les rendements à un comportement non défini chaque fois qu'ils se produisent. Je suppose que tout le monde conviendra que d'avoir des choses non définies doivent être évités à tout prix.

Le second cas est optionalité et est mieux fourni explicitement, par exemple avec un type d'option .


Le mot Let nous sommes dans une société de transport et nous avons besoin de créer une application pour aider à créer un calendrier pour nos pilotes. Pour chaque pilote, nous enregistrons quelques informations telles que: les permis de conduire et ils ont le numéro de téléphone à appeler en cas d'urgence

.

En C on pourrait avoir:

struct PhoneNumber { ... };
struct MotorbikeLicence { ... };
struct CarLicence { ... };
struct TruckLicence { ... };

struct Driver {
  char name[32]; /* Null terminated */
  struct PhoneNumber * emergency_phone_number;
  struct MotorbikeLicence * motorbike_licence;
  struct CarLicence * car_licence;
  struct TruckLicence * truck_licence;
};

Comme vous le constatez, tout traitement sur notre liste de pilotes nous allons devoir vérifier les pointeurs NULL. Le compilateur ne vous aidera pas, la sécurité du programme repose sur vos épaules.

En OCaml, le même code ressemblerait à ceci:

type phone_number = { ... }
type motorbike_licence = { ... }
type car_licence = { ... }
type truck_licence = { ... }

type driver = {
  name: string;
  emergency_phone_number: phone_number option;
  motorbike_licence: motorbike_licence option;
  car_licence: car_licence option;
  truck_licence: truck_licence option;
}

Disons que maintenant que nous voulons imprimer les noms de tous les pilotes ainsi que leurs numéros de licence de camion.

C:

#include <stdio.h>

void print_driver_with_truck_licence_number(struct Driver * driver) {
  /* Check may be redundant but better be safe than sorry */
  if (driver != NULL) {
    printf("driver %s has ", driver->name);
    if (driver->truck_licence != NULL) {
      printf("truck licence %04d-%04d-%08d\n",
        driver->truck_licence->area_code
        driver->truck_licence->year
        driver->truck_licence->num_in_year);
    } else {
      printf("no truck licence\n");
    }
  }
}

void print_drivers_with_truck_licence_numbers(struct Driver ** drivers, int nb) {
  if (drivers != NULL && nb >= 0) {
    int i;
    for (i = 0; i < nb; ++i) {
      struct Driver * driver = drivers[i];
      if (driver) {
        print_driver_with_truck_licence_number(driver);
      } else {
        /* Huh ? We got a null inside the array, meaning it probably got
           corrupt somehow, what do we do ? Ignore ? Assert ? */
      }
    }
  } else {
    /* Caller provided us with erroneous input, what do we do ?
       Ignore ? Assert ? */
  }
}

OCaml qui serait:

open Printf

(* Here we are guaranteed to have a driver instance *)
let print_driver_with_truck_licence_number driver =
  printf "driver %s has " driver.name;
  match driver.truck_licence with
    | None ->
        printf "no truck licence\n"
    | Some licence ->
        (* Here we are guaranteed to have a licence *)
        printf "truck licence %04d-%04d-%08d\n"
          licence.area_code
          licence.year
          licence.num_in_year

(* Here we are guaranteed to have a valid list of drivers *)
let print_drivers_with_truck_licence_numbers drivers =
  List.iter print_driver_with_truck_licence_number drivers

Comme vous pouvez le voir dans cet exemple trivial, il n'y a rien de compliqué dans la version sûre:

  • de terser.
  • Vous obtenez beaucoup de meilleures garanties et aucune vérification nul est nécessaire à tous.
  • Le compilateur a assuré que vous a correctement traité avec l'option

Alors qu'en C, vous pouvez simplement avoir oublié un chèque nul et boum ...

Note: ces exemples de code où non compilé, mais j'espère que vous avez les idées

.

Microsoft Research a un projet intersting appelé

  

Spec #

Il est une extension C # avec Type non NULL et un mécanisme à vérifier vos objets contre ne pas être nulle , bien que, à mon humble avis, l'application de la conception par contrat principe peut être plus approprié et plus utile pour de nombreuses situations problématiques causées par des références nulles.

En venant de fond .NET, j'ai toujours pensé nulle avait un point, son utilité. Jusqu'à ce que je suis venu à connaître de struct et comment il a été facile de travailler avec eux en évitant beaucoup de code de passe-partout. Tony Hoare parlant au QCon Londres en 2009, a présenté ses excuses pour avoir inventé la référence null . Pour le citer:

  

Je l'appelle mon erreur milliards de dollars. Il a été l'invention de l'hypothèse nulle   référence en 1965. A cette époque, je concevais la première   système complet pour les références dans un objet orienté   langue (Algol W). Mon objectif était de faire en sorte que toute utilisation de références   devrait être tout à fait sûr, avec vérification effectuée automatiquement par   le compilateur. Mais je ne pouvais pas résister à la tentation de mettre dans un null   référence, simplement parce qu'il était si facile à mettre en œuvre. Cela a conduit à   d'innombrables erreurs, les vulnérabilités et les pannes du système, qui ont   probablement causé un milliard de dollars de la douleur et les dommages dans les quarante dernières   ans. Ces dernières années, un certain nombre d'analyseurs programme comme préfixer et   PREfast dans Microsoft ont été utilisés pour vérifier les références et donner   des avertissements s'il y a un risque qu'ils peuvent être non nulle. Plus récent   langages de programmation tels que Spec # ont présenté des déclarations pour   références non nulles. C'est la solution que je rejetais en 1965.

Voir cette question trop aux programmeurs

Robert Nystrom propose un bel article ici:

http://journal.stuffwithstuff.com / 2010/08/23 / vide-nulle-peut-être-et-rien /

décrivant son processus de pensée en ajoutant le soutien de l'absence et l'absence de son Magpie langage de programmation.

Je l'ai toujours regardé nulle (ou nul) comme étant l'absence d'une valeur .

Parfois vous voulez cela, parfois non. Cela dépend du domaine que vous travaillez. Si l'absence est significative: pas de prénom, votre application peut agir en conséquence. D'autre part, si la valeur NULL ne doit pas être là: Le premier nom est nul, le développeur reçoit l'appel téléphonique proverbiale 2 a.m..

J'ai également le code vu surchargé et trop compliquées avec des chèques pour nul. Pour moi, cela signifie deux choses:
a) un bug plus haut dans l'arborescence de l'application
b) mauvaise / incomplète conception

Du côté positif - nul est probablement l'une des notions les plus utiles pour vérifier si quelque chose est absent, et les langues sans le concept de null sera endup de compliquer les choses quand il est temps de faire la validation des données. Dans ce cas, si une nouvelle variable n'est pas initialisé, a déclaré languagues les variables seront généralement mis à une chaîne vide, 0, ou une collection vide. Toutefois, si une chaîne vide ou 0 ou collection vide sont des valeurs valides pour votre application - alors vous avez un problème.

Parfois, cela contournée en inventant des valeurs spéciales / étranges pour les champs pour représenter un état non initialisée. Mais ce qui se passe lorsque la valeur spéciale est entrée par un utilisateur bien intentionné? Et Il faut que ça pas dans le désordre cela fera des routines de validation des données. Si la langue a soutenu le concept nul toutes les préoccupations disparaîtraient.

langues vectorielles peuvent parfois se contenter de ne pas avoir une valeur nulle.

Le vecteur vide sert de nulle typé dans ce cas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top