Nach meinem Verständnis können implizite Konvertierungen Fehler verursachen.
Das macht aber keinen Sinn - sollten normale Konvertierungen dann nicht auch Fehler verursachen?
Warum nicht haben
len(100)
arbeiten nach der Sprache, die sie interpretiert (oder kompiliert) als
len(str(100))
Zumal das der einzige Weg ist , damit es funktioniert. Die Sprache weiß, was der Fehler ist. Warum nicht beheben?
Für dieses Beispiel habe ich Python verwendet, obwohl ich der Meinung bin, dass es für etwas so Kleines grundsätzlich universell ist.
programming-languages
type-conversion
Quelklef
quelle
quelle
perl -e 'print length(100);'
druckt 3.str
dies der implizite Weg, ein int in ein iterables zu konvertieren? wie wäre esrange
? oderbin
(hex
,oct
) oderchr
(oderunichr
)? Alle diese Elemente geben iterables zurück, auch wennstr
dies für Sie in dieser Situation am offensichtlichsten erscheint.Antworten:
Für das, was es wert ist
len(str(100))
,len(chr(100))
undlen(hex(100))
sind alle unterschiedlich.str
Dies ist nicht die einzige Möglichkeit, dies zum Laufen zu bringen, da es in Python mehr als eine unterschiedliche Konvertierung von einer Ganzzahl in eine Zeichenfolge gibt. Eine davon ist natürlich die häufigste, aber es muss nicht selbstverständlich sein, dass Sie diese gemeint haben. Eine implizite Konvertierung bedeutet wörtlich "es versteht sich von selbst".Eines der praktischen Probleme bei impliziten Konvertierungen ist, dass es nicht immer offensichtlich ist, welche Konvertierung angewendet wird, wenn verschiedene Möglichkeiten bestehen. Dies führt dazu, dass Leser Fehler bei der Interpretation des Codes machen, weil sie die korrekte implizite Konvertierung nicht herausfinden. Jeder sagt immer, dass das, was er beabsichtigt hat, die "offensichtliche Interpretation" ist. Es ist für sie offensichtlich, weil es das ist, was sie meinten. Für andere ist es möglicherweise nicht offensichtlich.
Aus diesem Grund zieht Python (die meiste Zeit) das explizite dem impliziten vor, es zieht es vor, es nicht zu riskieren. Der Hauptfall, in dem Python Typenzwang ausführt, liegt in der Arithmetik. Es erlaubt ,
1 + 1.0
weil die Alternative zu lästig sein würde , damit zu leben, aber es nicht zulässt , dass ,1 + "1"
weil es denkt , sollten Sie festlegen , ob Sie meinenint("1")
,float("1")
,ord("1")
,str(1) + "1"
oder etwas anderes. Es erlaubt auch nicht(1,2,3) + [4,5,6]
, obwohl es Regeln zur Auswahl eines Ergebnistyps definieren könnte , genau wie es Regeln zur Auswahl des Ergebnistyps definiert1 + 1.0
.Andere Sprachen stimmen nicht überein und haben viele implizite Konvertierungen. Je mehr sie enthalten, desto weniger offensichtlich werden sie. Versuchen Sie, sich vor dem Frühstück die Regeln aus dem C-Standard für "ganzzahlige Aktionen" und "übliche arithmetische Umrechnungen" zu merken!
quelle
len
nur mit einem Typ funktionieren kann, grundlegend fehlerhaft ist.str
,chr
undhex
tun alle Rückkehr die gleiche Art! Ich habe versucht, mir einen anderen Typ vorzustellen, dessen Konstruktor nur ein int aufnehmen kann, aber mir ist noch nichts eingefallen. Ideal wäre ein Container,X
in demlen(X(100)) == 100
;-)numpy.zeros
etwas dunkel wirkt.a == b
,b == c
abera == c
nicht wahr zu sein.Sie vermissen ein Wort: Implizite Konvertierungen können zu Laufzeitfehlern führen.
Für einen einfachen Fall wie Sie ist es ziemlich klar, was Sie meinten. Aber Sprachen können nicht an Fällen arbeiten. Sie müssen mit Regeln arbeiten. In vielen anderen Situationen ist nicht klar, ob der Programmierer einen Fehler gemacht hat (mit dem falschen Typ) oder ob der Programmierer beabsichtigt hat, das zu tun, was der Code voraussetzt.
Wenn der Code falsch ist, erhalten Sie einen Laufzeitfehler. Da es mühsam ist, sie aufzuspüren, gehen viele Sprachen daneben, Ihnen mitzuteilen, dass Sie Fehler gemacht haben, und Sie können dem Computer mitteilen, was Sie wirklich gemeint haben (beheben Sie den Fehler oder führen Sie die Konvertierung explizit durch). Andere Sprachen raten, da sich ihr Stil für schnellen und einfachen Code eignet, der leichter zu debuggen ist.
Zu beachten ist, dass implizite Konvertierungen den Compiler etwas komplexer machen. Sie müssen vorsichtiger mit Zyklen umgehen (probieren wir diese Konvertierung von A nach B aus; Hoppla, das hat nicht funktioniert, aber es gibt eine Konvertierung von B nach A! Und dann müssen Sie sich auch um Zyklen der Größe C und D kümmern ) ist eine kleine Motivation, implizite Conversions zu vermeiden.
quelle
len(100)
, zurückzukehren3
. Ich würde es viel intuitiver finden, die Anzahl der Bits (oder Bytes) in der Darstellung von zu berechnen100
.len(100)
dass Sie die Anzahl der Zeichen für die Dezimaldarstellung der Zahl 100 erhalten sollten von ihnen. Sie könnten starke Argumente dafür vorbringen, warum die Anzahl der Bits oder Bytes oder Zeichen der hexadezimalen Darstellung (64
-> 2 Zeichen) von zurückgegeben werden solllen()
.Implizite Konvertierungen sind durchaus möglich. Die Situation, in der Sie in Schwierigkeiten geraten, ist, wenn Sie nicht wissen, wie etwas funktionieren soll.
Ein Beispiel hierfür ist Javascript, bei dem der
+
Bediener zu verschiedenen Zeiten auf unterschiedliche Weise arbeitet.Wenn eines der Argumente eine Zeichenfolge ist, ist der
+
Operator eine Zeichenfolgenverkettung, andernfalls handelt es sich um eine Addition.Wenn Sie ein Argument erhalten und nicht wissen, ob es sich um eine Zeichenfolge oder eine Ganzzahl handelt, und dies ergänzen möchten, kann dies zu einem Durcheinander führen.
Ein anderer Weg, um damit umzugehen, ist das Basic-Erbe (das Perl folgt aus - siehe Programmierung ist schwierig, Let's Go Scripting ... ).
In Basic
len
macht die Funktion nur Sinn, wenn sie für einen String aufgerufen wird (docs for visual basic : "Jeder gültige String-Ausdruck oder Variablenname. Wenn der Ausdruck vom Typ Object ist, gibt die Len-Funktion die Größe zurück, von der aus er in die Datei geschrieben wird die FilePut-Funktion. ").Perl folgt diesem Kontextkonzept. Die Verwirrung , die mit impliziter Umwandlung von Typen für den in JavaScript vorhanden
+
Operator ist manchmal zusätzlich und manchmal in Perl - Verkettung geschieht nicht , weil+
ist immer zusätzlich und.
ist immer Verkettung.Wenn etwas in einem skalaren Kontext verwendet wird, ist es ein Skalar (z. B. bei Verwendung einer Liste als Skalar verhält sich die Liste so, als wäre es eine Zahl, die ihrer Länge entspricht). Wenn Sie einen String-Operator verwenden (
eq
für den Gleichheitstest,cmp
für den String-Vergleich), wird der Skalar so verwendet, als wäre er ein String. Wenn etwas in einem mathematischen Kontext verwendet wurde (==
für die Gleichheitsprüfung und<=>
für den numerischen Vergleich), wird der Skalar genauso verwendet, als ob es eine Zahl wäre.Die Grundregel für jede Programmierung lautet: "Tu das, was die Person am wenigsten überrascht". Das heißt nicht, dass es dort keine Überraschungen gibt, aber die Anstrengung besteht darin, die Person am wenigsten zu überraschen.
Es gibt Situationen, in denen ein Operator in einem String oder in einem numerischen Kontext auf etwas einwirken kann und das Verhalten für Menschen überraschend sein kann. Der
++
Operator ist ein solches Beispiel. Bei Zahlen verhält es sich genau wie erwartet. Wenn Sie auf eine Zeichenfolge einwirken, z. B."aa"
, wird die Zeichenfolge inkrementiert ($foo = "aa"; $foo++; echo $foo;
gedrucktab
). Es wird auch überrollen, so dass,az
wenn inkrementiert wirdba
. Das ist noch nicht besonders überraschend.( ideone )
Dies druckt aus:
Willkommen zu den Gefahren impliziter Konvertierungen und zu Operatoren, die auf derselben Zeichenfolge unterschiedlich handeln. (Perl behandelt diesen Codeblock ein bisschen anders - es entscheidet, dass
"3d8"
der++
Operator von Anfang an ein numerischer Wert ist und geht4
sofort zu ( ideone ) - dieses Verhalten ist in perlop gut beschrieben : Auto-Inkrement und Auto-Dekrement. )Warum eine Sprache etwas auf die eine und eine andere Weise tut, führt zu den Designgedanken der Designer. Perls Philosophie ist, dass es mehr als einen Weg gibt, dies zu tun - und ich kann mir eine Reihe von Wegen vorstellen, um einige dieser Operationen durchzuführen. Auf der anderen Seite hat Python eine in PEP 20 - The Zen of Python - beschriebene Philosophie, die (unter anderem) lautet: "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun."
Diese Designunterschiede haben zu unterschiedlichen Sprachen geführt. Es gibt eine Möglichkeit, die Länge einer Zahl in Python zu ermitteln. Implizite Konvertierung widerspricht dieser Philosophie.
Verwandte Lektüre: Warum hat Ruby keine implizite Konvertierung von Fixnum in String?
quelle
x
undy
in einer solchen Art und Weise , wie eine Äquivalenzbeziehung zu erhalten oder das Ranking, aber IIRC Pythons Vergleichsoperatoren ...ColdFusion hat das meiste getan. Es definiert eine Reihe von Regeln, um Ihre impliziten Konvertierungen zu handhaben, hat einen einzelnen Variablentyp und los geht's.
Das Ergebnis ist eine totale Anarchie, bei der die Addition von "4a" zu 6 6.16667 ergibt.
Warum? Nun, da die erste der beiden Variablen eine Zahl ist, ist das Ergebnis numerisch. "4a" wird als Datum analysiert und als "4 Uhr morgens" angesehen. 4 Uhr morgens ist 4: 00/24: 00 oder 1/6 eines Tages (0,16667). Addiere zu 6 und du erhältst 6.16667.
Listen haben Standardtrennzeichen eines Kommas. Wenn Sie also jemals ein Element zu einer Liste hinzufügen, die ein Komma enthält, haben Sie gerade zwei Elemente hinzugefügt. Listen sind auch geheime Zeichenfolgen, sodass sie als Datumsangaben analysiert werden können, wenn sie nur 1 Element enthalten.
Der Zeichenfolgenvergleich überprüft, ob beide Zeichenfolgen zuerst zu Datumsangaben analysiert werden können. Da es keinen Datumstyp gibt, wird dieser verwendet. Gleiches gilt für Zahlen und Zeichenfolgen mit Zahlen, Oktalnotation und Booleschen Werten ("true" und "yes" usw.).
Anstatt schnell zu versagen und einen Fehler zu melden, übernimmt ColdFusion die Datentypkonvertierung für Sie. Und nicht in guter Weise.
Natürlich können Sie die impliziten Konvertierungen korrigieren, indem Sie explizite Funktionen wie DateCompare aufrufen ... aber dann haben Sie die "Vorteile" der impliziten Konvertierung verloren.
Für ColdFusion ist dies eine Möglichkeit, Entwickler zu stärken. Besonders wenn all diese Entwickler an HTML gewöhnt sind (ColdFusion arbeitet mit Tags, es heißt CFML, später fügten sie auch Skripte über hinzu
<cfscript>
, wobei Sie nicht für alles Tags hinzufügen müssen). Und es funktioniert gut, wenn Sie nur etwas zum Laufen bringen möchten. Wenn Sie jedoch eine präzisere Vorgehensweise benötigen, benötigen Sie eine Sprache, die implizite Konvertierungen für alles ablehnt, was so aussieht, als wäre es ein Fehler gewesen.quelle
Sie sagen, dass implizite Konvertierungen eine gute Idee für Operationen sein könnten, die eindeutig sind, z. B.
int a = 100; len(a)
wenn Sie vor dem Aufruf das int offensichtlich in einen String konvertieren möchten.Aber Sie vergessen , dass diese Anrufe können syntaktisch eindeutig, aber sie können einen Tippfehler gemacht durch den Programmierer dar , die passieren gemeint
a1
, das ist eine Zeichenfolge. Dies ist ein erfundenes Beispiel, aber mit IDEs, die die automatische Vervollständigung für Variablennamen bereitstellen, treten diese Fehler auf.Das Typensystem soll uns helfen, Fehler zu vermeiden, und für Sprachen, die eine strengere Typprüfung wählen, untergraben implizite Konvertierungen dies.
Sehen Sie sich die Probleme von Javascript mit all den impliziten Konvertierungen an, die von == durchgeführt werden, so dass viele jetzt empfehlen, sich an den no-implicit-conversion-Operator === zu halten.
quelle
Betrachten Sie für einen Moment den Kontext Ihrer Aussage. Sie sagen, dies ist der "einzige Weg", wie es funktionieren könnte, aber sind Sie wirklich sicher, dass es so funktionieren wird? Was ist damit:
Wie andere bereits erwähnt haben, scheint es für den Compiler in Ihrem Beispiel einfach zu sein, zu verstehen, was Sie gemeint haben. In einem größeren Zusammenhang mit komplizierteren Programmen ist es jedoch oft gar nicht offensichtlich, ob Sie einen String eingeben oder einen Variablennamen für einen anderen tippen oder die falsche Funktion oder einen von Dutzenden anderen möglichen Logikfehlern aufrufen wollten .
In dem Fall, in dem der Interpreter / Compiler errät, was Sie gemeint haben, funktioniert dies manchmal auf magische Weise, und manchmal verbringt man Stunden damit, etwas zu debuggen, was auf mysteriöse Weise ohne ersichtlichen Grund nicht funktioniert. Im Durchschnitt ist es viel sicherer zu wissen, dass die Aussage keinen Sinn ergibt, und einige Sekunden damit zu verbringen, sie zu korrigieren, was Sie eigentlich gemeint haben.
quelle
Implizite Konvertierungen können ein echtes Problem sein. In PowerShell:
Plötzlich sind doppelt so viele Tests und Fehler erforderlich wie ohne implizite Konvertierung.
quelle
Explizite Darstellungen sind wichtig, um Ihre Absichten klar zu machen. Zuallererst erzählt die Verwendung expliziter Besetzungen jemandem eine Geschichte, der Ihren Code liest. Sie zeigen, dass Sie absichtlich das getan haben, was Sie getan haben. Im Übrigen gilt das Gleiche für den Compiler. Das Folgende ist in C # beispielsweise unzulässig
Durch die Besetzung verlieren Sie an Präzision, was leicht ein Fehler sein kann. Daher weigert sich der Compiler zu kompilieren. Indem Sie eine explizite Besetzung verwenden, sagen Sie dem Compiler: "Hey, ich weiß, was ich tue." Und er wird gehen: "Okay!" Und kompilieren.
quelle
(X)y
Meinung nach sollte das Einzige heißen: "Ich denke, Y ist konvertierbar zu X; mach die Konvertierung, wenn möglich, oder wirf eine Ausnahme, wenn nicht." Wenn eine Konvertierung erfolgreich ist, sollte man in der Lage sein, den resultierenden Wert * vorherzusagen, ohne spezielle Regeln für die Konvertierung vom Typy
zum Typ kennen zu müssenX
. Wenn Sie aufgefordert werden, -1,5 und 1,5 in Ganzzahlen umzuwandeln, ergeben einige Sprachen (-2,1). einige (-2,2), einige (-1,1) und einige (-1,2). Während C Regeln sind kaum dunkel ...Sprachen, die implizite Konvertierungen / Umwandlungen oder schwache Typisierung unterstützen, wie sie manchmal genannt wird, werden Annahmen für Sie treffen, die nicht immer mit dem beabsichtigten oder erwarteten Verhalten übereinstimmen. Die Designer der Sprache hatten möglicherweise den gleichen Denkprozess wie Sie für eine bestimmte Art von Konvertierung oder Serie von Konvertierungen, und in diesem Fall werden Sie nie ein Problem sehen. Wenn dies jedoch nicht der Fall ist, schlägt Ihr Programm fehl.
Der Fehler kann jedoch offensichtlich sein oder auch nicht. Da diese impliziten Umwandlungen zur Laufzeit auftreten, wird Ihr Programm problemlos ausgeführt, und Sie werden nur dann ein Problem feststellen, wenn Sie sich die Ausgabe oder das Ergebnis Ihres Programms ansehen. Eine Sprache, die explizite Umwandlungen erfordert (einige bezeichnen dies als starke Typisierung), würde Ihnen einen Fehler melden, bevor Sie mit der Ausführung des Programms beginnen. Dies ist ein viel offensichtlicheres und einfacher zu behebendes Problem, wenn implizite Umwandlungen fehlgeschlagen sind.
Neulich fragte ein Freund seinen 2-Jährigen, was 20 + 20 sei, und er antwortete 2020. Ich sagte meinem Freund: "Er wird ein Javascript-Programmierer."
In Javascript:
So können Sie sehen, welche Probleme implizite Casts verursachen können und warum dies nicht einfach behoben werden kann. Der Fix, den ich argumentieren würde, ist die Verwendung expliziter Casts.
quelle