Artikelformat

Eins plus Zwei

Eine Überraschung in Ruby.

Selbst bei so etwas einfachen wie der Addition von Zahlen gibt es manchmal Überraschungen. Doch der Reihe nach. Wenn wir den interaktiven Ruby-Interpreter “irb” starten, können wir in als einfachen Rechner nutzen.

irb> 1+2
=> 3

So weit so praktisch. In der Programmierpraxis liegen Zahlen häufig als String vor, z.B in Textdateien oder als Formularparameter in Webseiten. Probieren wir also folgendes:

> input="1"
> input+2
TypeError: can't convert Fixnum into String

Richtig, wir müssen in Ruby erst explizit den String in einen Integer umwandeln. Dafür gibt es die Methode to_i

> input.to_i+2
=> 3

Ok, damit es etwas besser aussieht, fügen wir ein Leerzeichen ein

> input.to_i +2
=> 1

Huch? Was war das? Ist unsere Variable vielleicht überschrieben worden? Probieren wir es mal direkt:

>"1".to_i+2
=> 3
>"1".to_i +2
=> 1

Bei einen Leerzeichen vor dem Pluszeichen und keinem Leerzeichen nach dem Pluszeichen gibt es ein anderes Ergebnis. Wo kann dieses Ergebnis herkommen? Probieren wir andere Zahlen:

>"2".to_i +2
=> 0

Es wird immer rätselhafter!

> "1".to_i +1
ArgumentError: illegal radix 1

Aha, es gibt eine Spur. Vielleicht schaut wir uns die Dokumentation der Methode “to_i”genauer an:

http://ruby-doc.org/core/classes/String.html#M000787

Die Methode to_i hat demnach einen optionalen Parameter Namens “radix”. Der String kann als Zahl im Hexadecimal-, Decimal, Octal- oder Binärsystem interpretiert werden.

Weiter steht dort momentan: “This method *never* raises an exception.” Also soll die Methode, falls sie auf Grund von unerlaubten Eingaben zu Fehlern führt, immer 0 liefern, und niemals eine Exception erzeugen. Gut, wenn das so exakt dokumentiert ist. Leider ist die Aussage so nicht richtig, denn der ArgumentError ist schließlich auch eine Exception.

Wie hilft uns dies jetzt, das eigenartige Verhalten zu erklären? In Ruby kann man die Klammern auch bei einen Funktionsaufruf weglassen. Offenbar macht unser Rubyinterpreter aus:

"1".to_i +2
"1".to_i( +2 ) => "1".to_i( 2 ) => 1

Der String “1” wird als Binärzahl interpretiert, und liefert dann die Zahl 1. Eine Addition findet nicht mehr statt. So lässt sich auch erklären:

"2".to_i(+2) = 0

Ruby versucht den String “2” als Binärzahl zu interpretieren. Das geht nicht, weil Binärzahlen nur aus 0 und 1 bestehen. Ruby liefert dann wie dokumentiert einfach eine 0 zurück.

Insgesamt bleibt dabei ein ungutes Gefühl: Selbst bei einer einfachen Addition kann durch hinzufügen oder weglassen von Leerzeichen aus einen korrekten Programm ein Falsches werden. Leider der Preis, den man in Ruby für den Verzicht auf Klammern zahlen muss. In diesen Fall ermöglicht der optionale Parameter der Methode “to_i” diese Mehrdeutigkeiten. Optionale Klammern in Zusammenspiel mit optionalen Parametern sind leider eine gefährliche Kombination.

Autor: Karsten Meier

Weil ich gerne Probleme löse bin ich Informatiker geworden. Für meine Kunden berate und konzeptioniere ich und entwickle mit fast allem, was einen Prozessor hat. Sie finden mich auch auf Twitter

1 Kommentar

Hinterlassen Sie eine Antwort

Pflichtfelder sind mit * markiert.