(Ce n'est pas un article traduit) Non.
C'est peut-être bon, non? Il est très facile de gérer l'état d'avoir une valeur et l'état de n'avoir aucune valeur. C'est l'apogée de la culture créée par Lirin.
Donc, j'ai pensé que je pourrais faire quelque chose de similaire avec Python et je l'ai implémenté.
Le corps principal est répertorié dans ici. Je pense que vous devriez certainement jouer et lancer Masakari.
Certains d'entre eux sont explicitement conscients de "les langues non sécurisées nulles ne sont plus des langues héritées", veuillez donc les lire ensemble. Je pense que c'est bien.
This Maybe est implémenté comme des classes concrètes «Something» et «Nothing» qui héritent de la classe abstraite «Maybe». «Quelque chose» indique qu'il existe une valeur et «Rien» indique que la valeur est manquante.
La fonction just
crée une instance de Something
. «Nothing» est la (seule) instance de «Nothing».
from maybe import just, nothing
a = just(42)
b = nothing
print(a)
print(b)
Just 42
Nothing
Peut-être a la propriété has_value
, Something
renvoie True
et Nothing
renvoie False
. En outre, «quelque chose» est lui-même vérité et «rien» est lui-même Falsey.
print(a.has_value)
print(b.has_value)
print('-----')
if a:
print('a is Truthy')
else:
print('a is Falsy')
if b:
print('b is Truthy')
else:
print('b is Falsy')
True
False
-----
a is Truthy
b is Falsy
Peut-être peut-il être considéré comme une boîte pour mettre des valeurs. Peut-être que lui-même peut être une valeur, alors Maybe peut être imbriqué. Peut-être a le concept de «profondeur». La profondeur de la valeur nue est 0. La profondeur de "Rien" est de 1. La profondeur de «quelque chose» est «profondeur du contenu + 1». La profondeur peut être obtenue en la passant à la fonction «dep».
from maybe import dep
a2 = just(a)
b2 = just(b)
print(a2)
print(b2)
print('-----')
print(dep(42))
print(dep(a))
print(dep(b))
print(dep(a2))
print(dep(b2))
Just Just 42
Just Nothing
-----
0
1
1
2
2
Peut-être peut comparer des valeurs égales. «Quelque chose» est supposé être égal s'ils sont «Quelque chose» et leur contenu est égal. S'il s'agit d'une structure imbriquée, elle sera creusée lors de la récurrence. «Rien» est supposé être égal s'ils sont «Rien».
print(a == 42)
print(a == just(42))
print(a == a2)
print(a == b)
print(b == nothing)
print(b == b2)
print(b2 == just(nothing))
False
True
False
False
True
False
True
Pour utiliser Maybe [T]
comme T
,
1.Assurez-vous que Maybe a une valeur, 2. Vous devez convertir «Peut-être [T]» en «T».
Il est possible de l'utiliser comme suit en utilisant l'instruction if et l'opérateur de dépliage forcé décrits plus loin.
m = just(913)
if m.has_value:
print(m.i + 555)
1488
Cependant, si ces deux processus sont séparés, les événements inattendus suivants peuvent se produire.
m = just(913)
if m.has_value:
print(m + 555) #Oubliez le déballage, peut-être[int]Et int ne peut pas être ajouté
TypeError: unsupported operand type(s) for +: 'Something' and 'int'
m = nothing
print(m.i + 555) #Oubliez Null check, si m est Nothing, la mouche visqueuse
maybe.NullpoError: it GOT no value.
En fait, Maybe peut être itéré, Something
génère la valeur du contenu une seule fois, et Nothing
ne génère rien et déclenche une exceptionStopIteration ()
. En utilisant cela, vous pouvez utiliser l'instruction for pour effectuer une vérification Null et effectuer un cast en même temps, comme indiqué ci-dessous.
m = just(913)
for v in m:
print(v + 555) #Ceci n'est exécuté que lorsque m est quelque chose
1468
J'appelle cela la «liaison peut-être» parce qu'elle ressemble à la liaison optionnelle Swift. La différence avec la liaison facultative est que l'observation (en utilisant le même nom de variable dans le bloc) n'est pas possible et que le branchement entre les valeurs manquantes est un peu compliqué.
Regardons-les dans l'ordre. Si vous faites quelque chose comme l'observation, le m
changera de Maybe [int]
à ʻint` dans la ligne de commentaire en raison de la portée variable de Python.
m = just(913)
print(m) #Ici peut-être[int]
for m in m:
print(m + 555)
print(m) #Ici int
Just 913
1468
913
Pensez-vous que c'est plus pratique parce que vous avez déjà coché Null? Mais c'est un piège. Si la valeur de m
est manquante, elle reste Maybe [int]
. Vous n'êtes plus autorisé à traiter «m» dans le même contexte que «Peut-être» à partir de maintenant, vous devez passer votre temps à avoir peur de la possibilité que «m», qui ressemble à «int», ne soit «rien». Je ne sais pas à quoi sert peut-être. N'est-ce pas très différent de simplement utiliser "Aucun" (en fait, c'est plus gênant)?
La prochaine différence. Vous souhaiterez peut-être créer une branche du processus avec et sans valeur, plutôt que de simplement le faire lorsqu'il y a une valeur. Dans Swift Optional, vous pouvez écrire comme suit.
let m: Int? = nil
if let v = m {
print(v + 555)
} else {
print("Peut-être que tu me détestes?")
}
La correspondance entre «si» et «sinon» est belle et sans égal. Et ces deux blocs sont grammaticalement appariés.
Cependant, dans Peut-être, nous devons écrire comme ça.
m = nothing
for v in m:
print(v + 555)
if not m.has_value:
print("Peut-être que tu me détestes?")
La correspondance entre «pour» et «si» est probablement née et personne ne l'a jamais vue. En outre, ces deux blocs sont écrits l'un à côté de l'autre et ne constituent pas une paire grammaticale. De plus, «if not m.has_value» est assez long. À ce propos, «Rien» est à l'origine Fassy, donc «si ce n'est pas m» c'est bien, mais il y a un inconvénient que le sens est un peu difficile à lire.
Cela dit, il est beaucoup plus sûr et plus facile à écrire que le contrôle Null et le cast sont séparés. Fondamentalement, il est préférable d'interdire l'utilisation de .i
et d'utiliser la liaison Maybe.
!
, !!
)Considérons une fonction safe_int
qui tente de convertir de str
en ʻint et ne renvoie
rien` si elle échoue.
def safe_int(s):
try:
return just(int(s))
except ValueError:
return nothing
En passant, disons que cette fonction contient une chaîne qui saute de la zone de texte "age" utilisée sur un certain site. Normalement, il est restreint de sorte que seuls les nombres puissent être saisis du côté HTML, et le prétraitement, etc. sera effectué avec JavaScript à l'étape précédente.
Dans de tels cas, il est pratiquement impossible pour cette fonction de renvoyer «rien». Cependant, Maybe [int]
ne peut pas être utilisé comme ʻint, alors dois-je écrire une liaison Maybe pendant longtemps? Alors il vaut mieux utiliser
None`.
C'est à ce moment que vous devez utiliser l'opérateur de dépliage forcé .i
. Au fait, bien que ce soit appelé un opérateur, c'est en fait une propriété.
s = get_textbox('âge')
age = safe_int(s).i # .j'attribue un entier à l'âge
if age >= 20:
...
Cela semble pratique et sans tracas, mais si vous appelez .i
pour rien
, le bon vieux volera le NullpoError
original. Encore une fois, l'opérateur de dépliage forcé est considéré comme une opération «non sûre» et ne doit être utilisé que là où il ne peut jamais être «rien» en logique.
? .
,? ->
)Supposons que vous ayez une «Peut-être [liste]» ici. Vous vouliez savoir combien il y a de «0» dans ce fichier. Je pense que Peut-être pourrait être «rien», mais la plupart du temps, si la liste elle-même n'existe pas, vous vous attendriez à «rien» (non, certaines personnes veulent «0»). Voir également «Null Healing Operator» suivant).
Pour être honnête, cela ressemble à ceci:
l = get_foobar_list('hogehoge')
for l0 in l:
num_0 = just(l0.count(0))
if not l:
num_0 = nothing
Je peux l'écrire avec certitude, mais pour être clair, c'est compliqué. Si l
est liste
, vous ne voulez pas écrire le processus qui nécessitenum_0 = l.count (0)
sur 4 lignes.
Vous pouvez l'écrire de manière concise en utilisant l'opérateur conditionnel Null .q.
(comme d'habitude, c'est vraiment une propriété).
l = get_foobar_list('hogehoge')
num_0 = l.q.count(0)
Vous pouvez également utiliser .q []
pour les indices.
l = get_foobar_list('hogehoge')
print(l.q[3])
#Peut être utilisé à la place de
# for l0 in l:
# print(just(l0[3]))
# if not l:
# print(nothing)
Pourquoi pouvons-nous faire cela? .Q
renvoie un objet qui hérite de la classe abstraite SafeNavigationOperator
. «SafeNavigationOperator» remplace «getattr» et «getitem». S'il a une valeur, "Something SNO" est renvoyé. Cela contient les informations de valeur, et __getattr__
et __getitem__
les enveloppent dans just
et les renvoient. Si la valeur est manquante, NothingSNO
est retourné, et __getattr__
et __getitem__
ne renvoient rien
.
Vous vous demandez peut-être si vous avez une bonne idée ici. some_list.count
est une méthode et un objet appelable. peut-être_list.q.count
est retourné en encapsulant davantage la fonction dans Maybe. Est-ce un objet appelable de Maybe lui-même qu'il peut être traité comme l.q.count (0)
?
En fait, c'est vrai. L'appel de Something
appelle le contenu et encapsule le résultat dans juste
et le renvoie. L'appel de "Nothing" renvoie simplement "rien". Cette spécification permet de faire les choses mentionnées ci-dessus. Cette spécification est à utiliser en même temps que «.q.». Personnellement, je pense que c'est magique de l'utiliser d'une autre manière, donc je pense qu'il vaut mieux s'abstenir de l'utiliser (cela conduit à la raison pour laquelle les quatre règles de Maybe, qui seront décrites plus loin, ne sont pas implémentées).
À propos, même parmi les langages qui implémentent «?.», Si la soi-disant «chaîne optionnelle» est adoptée, elle se terminera lorsque Null sera trouvé (pour ainsi dire, évaluation de court-circuit), mais «.q. Dans le cas de, le processus se poursuit avec «rien». Même si vous faites .q.
pour rien
, vous n'obtiendrez que rien
, et le résultat de la propagation est toujours l'équivalent de Null, mais vous devez être conscient de cette différence. Vous devrez peut-être le conserver.
Au fait, vous ne pouvez pas faire quelque chose comme foo.q.bar = baz
parce que vous n'avez pas remplacé __setattr__
. C'est ma limitation technique et je ne pouvais tout simplement pas résoudre la boucle infinie qui se produit lorsque je remplace __setattr__
. Aidez-moi, s'il vous plaît ... Je pense que foo.q [bar] = baz
peut être fait, mais ce n'est pas encore implémenté car la symétrie est cassée.
?:
, ??
)Dans le cas de Null, vouloir remplir avec la valeur par défaut est probablement la demande la plus courante lorsqu'il s'agit de Null.
Bien sûr, vous pouvez également écrire avec la liaison Maybe, mais ...
l = get_foobar_list('hogehoge')
num_0 = l.q.count(0) #Au fait, voici num_0 est peut-être[int]alors……
for v in num_0:
num_0 = v
if not num_0:
num_0 = 0
#Si tu sors d'ici, num_0 devient int.
L'opérateur de fusion Null [^ coalesce] >>
est correctement préparé.
l = get_foobar_list('hogehoge')
num_0 = l.q.count(0) >> 0 # num_0 est un entier
Le comportement de l'opérateur de fusion Null semble simple à première vue (et est en fait simple), mais il nécessite un peu d'attention.
Si la valeur du côté gauche est manquante, l'histoire est facile et le côté droit est retourné tel quel.
En revanche, lorsque le côté gauche a une valeur, il se comporte de manière intéressante (au sens traductionnel d'Intéressant). Si le côté gauche est plus profond que le côté droit, le contenu du côté gauche et du côté droit sont réunis. Si le côté droit est plus profond que le côté gauche, enveloppez le côté gauche avec «juste», puis guérissez à nouveau. S'ils sont identiques, le côté gauche est renvoyé. Cependant, si le côté droit est une valeur nue (profondeur 0), enveloppez le côté droit dans juste
et guérissez à nouveau et renvoyez le contenu.
L'opérateur «ou», qui se comporte de la même manière lorsqu'il est vu de l'extérieur, est un mouvement beaucoup plus compliqué que de le renvoyer tel quel si le côté gauche est Vérité. La raison de faire cela est qu'il renvoie toujours une valeur avec la même profondeur que le côté droit à la suite d'un appel récursif.
Dans le contexte de la «définition d'une valeur par défaut», vous vous attendez à ce qu'elle soit traitée de la même manière avec ou sans valeur. Peut-être peut être imbriqué, donc certaines opérations compliquées sont nécessaires. Cependant, c'est une histoire interne, et l'utilisateur peut simplement la traiter comme «renvoyant toujours une valeur avec la même structure».
Par exemple, lorsqu'il y a plusieurs Peut-être, quelle que soit leur structure, vous pouvez obtenir «Peut-être avec la même structure que le côté le plus à droite (valeur nue dans ce cas), où la valeur apparaît le plus tôt» comme suit. Je vais.
x = foo >> bar >> baz >> qux >> 999
D'autre part, veuillez noter que le côté droit est évalué car il ne s'agit pas d'une évaluation de court-circuit.
À propos, cet opérateur est implémenté en surchargeant l'opérateur de décalage de bit droit. Par conséquent, la priorité de calcul est également la même. Autrement dit, il est inférieur à l'opérateur d'addition et supérieur à l'opérateur de comparaison [^ operator-precedence]. Ceci est proche de la priorité de l'opérateur de fusion Null de C # [^ c-sharp], Swift [^ swift], Kotlin [^ kotlin], mais d'un autre côté, l'opérateur "None-aware" proposé dans PEP 505. C'est très différent de [^ pep-505], où ?? `a une priorité plus élevée que la plupart des opérateurs binaires. Soyez prudent lorsque le jour où la PEP 505 sera officiellement adoptée (je ne pense pas que cela viendra). De plus, «>> =» est automatiquement défini.
a = just(42)
b = nothing
print(a >> 0 + 12) # 42 ?? 0 +12 serait 54(Haz)
print('-----')
a >>= 999
b >>= 999
print(a)
print(b)
42
-----
42
999
En passant, j'ai choisi «>>» comme destination de surcharge.
Etc. ~~ Il semble que la raison tombe en panne, mais la raison est horriblement la modernisation, et vous pouvez voir que j'ai fait Maybe correctement. ~~
[^ coalesce]: Généralement, la traduction standard de Null Coalescing Operator est «Null coalescence operator», mais «coalescence» n'a pas la nuance de «remplir la partie manquante», donc cela signifie «fermer la plaie». «Guérison» est utilisé.
map
(from map
)L'opérateur conditionnel Null a en fait ses faiblesses. Il ne peut être utilisé qu'avec des objets Maybe. Vous ne pouvez pas non plus donner SafeNavigationOperator
comme argument.
Cela signifie que vous ne pouvez pas faire cela.
l = just([1, 2, 3, ])
s = .q.sum(l) #Erreur de syntaxe
s = sum(l.q) #Exception à la pop
#Pourquoi tu ne fais pas ça
#Oah, oh, oh, oh, oh, ♥
Vous pouvez écrire avec la liaison Maybe, mais c'est toujours compliqué.
l = just([1, 2, 3, ])
for l0 in l:
s = just(sum(l0))
if not l:
s = nothing
Il existe une méthode map
pour faire cela du côté objet Maybe. En utilisant la méthode map
, vous pouvez écrire:
l = just([1, 2, 3, ])
s = l.map(sum)
La fonction passée à la méthode map
renvoie le résultat encapsulé dans just
. Bien sûr, si la valeur est manquante, «rien» ne sera renvoyé. Vous pouvez également utiliser des expressions lambda pour les fonctions, vous pouvez donc effectuer les opérations suivantes:
a = just(42)
print(a.map(lambda x: x / 2))
Just 21.0
Il n'y a pas grand chose à dire sur la méthode map
(surtout si vous connaissez Monad).
bind
(from flatMap
)Rappelez-vous la fonction safe_int
que nous avons créée précédemment. Il prend str
comme argument et renvoie Maybe [int]
. Appliquons ceci à Maybe [str]
en utilisant map
.
s1 = just('12')
s2 = just('hogehoge')
s3 = nothing
print(s1.map(safe_int))
print(s2.map(safe_int))
print(s3.map(safe_int))
Just Just 12
Just Nothing
Nothing
safe_int
renvoie Maybe, et la méthode map
le réemballe avec just
, donc il est imbriqué. Peut-être que la personne qui a écrit ce programme ne voulait pas de cette fin (le fait que "peut" être imbriqué le rend plus expressif. Par exemple, si le résultat de l'analyse JSON contient null
, alorsjuste (rien)
, car si la clé n'existait pas en premier lieu, elle pourrait être exprimée par" rien ").
Jusqu'à présent, il était gardé secret, mais vous pouvez utiliser la fonction join
pour écraser les nids d'une étape. C'est une conversion naturelle μ.
from maybe import join
print(join(s1.map(safe_int)))
print(join(s2.map(safe_int)))
print(join(s3.map(safe_int)))
Just 12
Nothing
Nothing
Et surtout, il est souhaitable de combiner «« map »et« join »». Si vous avez une méthode bind
, vous pouvez l'utiliser.
print(s1.bind(safe_int))
print(s2.bind(safe_int))
print(s3.bind(safe_int))
Just 12
Nothing
Nothing
Pour ceux qui maîtrisent la ~~ transformation ~~ Haskell, vous pouvez facilement comprendre que la méthode map
est l'opérateur <$> ʻopérateur et la méthode
bind est l'opérateur
>> = . Souvenez-vous de
map pour les fonctions qui renvoient des valeurs nues et de
bind` pour les fonctions qui renvoient Maybe.
do
(à partir de la notation do
)Bien sûr, map
et bind
sont appelés à partir d'un seul objet Maybe, donc c'est un peu difficile à utiliser pour les fonctions qui prennent 2 arguments ou plus.
lhs = just(6)
rhs = just(9)
ans = lhs.bind(lambda x: rhs.map(lambda y: x * y))
print(ans)
Just 54
Au fait, l'intérieur est map
car c'est une fonction qui renvoie une valeur nue avec x * y
, et l'extérieur est bind
parce que la valeur de retour de la méthode map
est Maybe. Te souviens tu?
Vous pouvez facilement écrire ceci en utilisant la fonction do
.
from maybe import just, nothing, do
lhs = just(6)
rhs = just(9)
ans = do(lhs, rhs)(lambda x, y: x * y)
print(ans)
Just 54
La fonction do
extrait le contenu et exécute la fonction uniquement lorsque tous les arguments ont des valeurs. Renvoie «rien» s'il manque une valeur. Le nom «do» vient de Haskell, mais l'algorithme est extrêmement anti-monadique. Pardonne-moi.
Au fait, l'argument de la fonction do
ne peut être pris que par Maybe. Si vous voulez utiliser des valeurs brutes comme arguments, enveloppez-les dans juste
.
Peut-être est aussi un conteneur, et vous pouvez utiliser les opérateurs len
et ʻin`.
La fonction «len» renvoie toujours «1» pour «Something» et «0» pour «Nothing».
a = just(42)
b = nothing
a2 = just(a)
b2 = just(b)
print(len(a))
print(len(b))
print(len(a2))
print(len(b2))
1
0
1
1
L'opérateur ʻin renvoie
Truelorsque le contenu du côté droit est égal au côté gauche. Sinon, il renvoie «False».
Nothing renvoie toujours
False`.
print(42 in a)
print(42 in b)
print(42 in a2)
print(42 in b2)
True
False
False
False
Comme mentionné précédemment, Maybe peut être itératif. Ainsi, par exemple, vous pouvez le convertir en liste. @koher a dit: C'est exactement ce que le résultat est.
ʻOptional
était une boîte qui pouvait être vide. D'un autre point de vue, vous pouvez considérer ʻOptional
comme un ʻArray` qui peut contenir au plus un élément.
al = list(a)
bl = list(b)
print(al)
print(bl)
[42]
[]
Il est difficile de savoir s'il existe une opportunité d'utiliser les spécifications ici.
Peut-être a une paire de fonctions et de méthodes, peut-être_from
et to_native
. C'est une paire de fonctions et de méthodes. Ceux-ci fonctionnent pour connecter les types natifs de Python avec Maybe.
peut-être_from
prend une valeur native et retourne peut-être. La différence avec «juste» est que lorsque «Aucun» est donné, «rien» n'est renvoyé au lieu de «juste (Aucun)», et lorsque Maybe est donné, il est renvoyé tel quel. Cette fonction peut être utilisée pour utiliser collectivement les valeurs de retour des fonctions et méthodes existantes qui indiquent les valeurs de retour manquantes comme «None» dans le contexte commun de Maybe.
#Fonction existante qui renvoie None au lieu de price lorsqu'elle n'est pas dans le dictionnaire
def get_price(d, name, num, tax_rate=0.1):
if name in d:
return -(-d[name] * num * (1 + tax_rate)) // 1
else:
return None
# ...
from maybe import maybe_from
p = get_price(unit_prices, 'apple', 5) #int peut venir, aucun ne peut venir
p = maybe_from(p) #p est l'unité_aux prix'apple'Peut-être avec ou sans[int]
La méthode to_native
, d'autre part, fait de Maybe une valeur native (bien que ce soit juste une native si le contenu est un objet fourni par une bibliothèque en premier lieu). Contrairement à .i
, Nothing
renvoie None
(mais n'en abusez pas comme un opérateur de déroulement" sûr "), et même s'il est imbriqué, il creuse récursivement et est toujours nu. Renvoie la valeur de. map
considère que tout est manquant lorsque l'argument est manquant, mais cela peut être utilisé pour l'argument d'une fonction qui s'attend à donner" Aucun "pour ne signifier aucune valeur. Vous pouvez également le spécifier en tant que méthode de sérialisation JSON en utilisant le fait qu'elle renvoie une valeur native (bien qu'elle soit abrégée en native).
import json
from maybe import Maybe
def json_serial(obj):
if isinstance(obj, Maybe):
return obj.to_native()
raise TypeError ("Type {type(obj)} not serializable".format(type(obj)))
item = {
'a': just(42),
'b': nothing
}
jsonstr = json.dumps(item, default=json_serial)
print(jsonstr)
{"a": 42, "b": null}
Quand vous dites Peut-être en Python, il existe une bibliothèque existante appelée «PyMaybe». Il semble que ce soit un endroit célèbre mentionné dans la PEP 505.
La grande caractéristique ici est que vous pouvez gérer Maybe comme s'il s'agissait d'une valeur nue. Plus précisément, le code suivant dans README.rst sera utile. Pensez à «peut-être» comme «peut-être» ici, et «ou_else» comme «>> ʻopérateur ici.
>>> maybe('VALUE').lower()
'value'
>>> maybe(None).invalid().method().or_else('unknwon')
'unknwon'
Nous appelons une méthode pour les valeurs brutes pour les valeurs qui sont enveloppées dans Maybe. Vous pouvez également voir que l'appel de méthode pour Null est ignoré et que Null est propagé. Vous n'êtes pas obligé de le retirer ou de faire «.q» comme mon Maybe. Il semble que des méthodes Dunder telles que quatre règles soient également implémentées.
Pourquoi n'est-ce pas plus pratique? Je pense que beaucoup de gens pensent qu'il n'y aura pas d'erreurs supplémentaires.
Cependant, il y a une raison pour laquelle j'ai implémenté Maybe avec une telle spécification. Il s'agit simplement de «soulever une erreur».
Si vous ne reconnaissez pas correctement la différence entre Maybe [T]
et T
, vous obtiendrez immédiatement une erreur, ce qui vous aidera à remarquer la différence. Si vous le confondez, vous obtiendrez une erreur immédiatement, et si vous le convertissez en chaîne, il aura un préfixe Just
supplémentaire. C'est pour s'assurer que "si vous ne l'écrivez pas correctement, cela ne fonctionnera pas". Si vous faites une erreur, vous la remarquerez immédiatement (voir: Si vous êtes sérieux, n'ayez pas peur de "l'année optionnelle (2018)"). C'est aussi la raison pour laquelle je ne veux pas que vous appeliez directement Maybe (car cela cache la différence, même si je veux vraiment effacer la conversion de chaîne ...).
La sécurité nulle est généralement comprise comme un mécanisme qui ne cause pas de glu, et il ne fait aucun doute que le but ultime est là (et soudain j'ai commencé à parler de sécurité nulle, mais mon Les indices de type de Maybe sont inutiles, il est donc pratiquement impossible de les utiliser pour la sécurité Null). Cependant, ce qui est vraiment nécessaire pour la sécurité Null est "une distinction entre Nullable et Non-null". Pourquoi Java n'a-t-il pas échoué? C'était que vous pouviez attribuer null
à n'importe quel type de référence, et inversement, la valeur de tout type de référence pouvait être null
. Le fait que «T» puisse être Null signifie que vous ne pouvez pas l'utiliser comme «T» même si vous avez écrit «T». Devrait être. S'y rendre et briser davantage la barrière entre Nullable et Non-null - laisser les choses qui ne sont pas «T» être traitées comme «T» - est plutôt dangereux.
Objective-C a une mauvaise spécification selon laquelle les appels de méthode à «nil» sont ignorés sans erreur.
(Omis)
Cependant, en échange de cette commodité, Objective-C comporte également un risque terrifiant. J'ai oublié de cocher «nil» là où j'aurais dû cocher «nil», mais parfois cela fonctionne. Et un jour, lorsque certaines conditions se chevauchent ou qu'une petite correction est apportée, le bogue devient apparent.
Le traitement par Objective-C des «nil» semble sûr à première vue, ne faisant que retarder la découverte des problèmes et les rendre plus difficiles à résoudre. Je considère que la méthode Objective-C est la pire en ce qu'elle est sujette à des bogues potentiels. Il était une fois, lors du portage d'un programme écrit en Objective-C vers Java, il a fallu attendre une exception "NullPointerException" en Java que je me suis rendu compte que la gestion "nil" du côté Objective-C était inappropriée. était.
Bien sûr, cela ne signifie pas que vous devez être moins productif pour la sécurité Null. La vérification Null pour les variables Nullable était nécessaire «même dans l'ancien langage» [^ null-check], et cela a peut-être plutôt implémenté diverses façons de le simplifier. Si vous voulez le frapper sans vérifier Null, il existe même une opération Unsafe pour cela. Cette zone est [une histoire racontée il y a quelques années](https://qiita.com/koher/items/e4835bd429b88809ab33#null-%E5%AE%89%E5%85%A8%E3%81%AF%E7 % 94% 9F% E7% 94% A3% E6% 80% A7% E3% 82% 82% E9% AB% 98% E3% 82% 81% E3% 82% 8B).
Cependant, je pense que ceux qui aiment utiliser Python sont conscients de cette robustesse et valorisent quand même "écrivez ce que vous voulez écrire honnêtement". Donc, je ne peux pas dire que l'idée de PyMaybe est fausse ~~ Je peux dire que je suis le "Peut-être que [T] erroriste" qui se rebelle contre le monde ~~. Cependant, n'hésitez pas à dire que vous jouez à moitié, ou que vous avez écrit ce que vous voulez écrire.
[^ null-check]: Ceci est une histoire irréaliste pour un peut-être personnalisé, mais si [n'utilisez que «rien» et pas le «None» intégré](https://twitter.com/ kmizu / status / 782360813340286977) Si vous pouvez (enveloppez-le dans peut-être_from
dès que cela peut se produire), vous n'avez pas besoin de faire une vérification Null pour les valeurs brutes. En fait, c'est le plus grand avantage des langages Null-safe, et les langages Null-safe qui ont un tel mécanisme intégré dans leurs spécifications de langage n'ont besoin que d'un "contrôle Null nécessaire". La perception générale selon laquelle «les langages sûrs nuls forcent les vérifications nulles» est correcte, mais le contraire est vrai. Référence: [Anti-pattern] Syndrome qui peut être totalement nul (nul)
Recommended Posts