Ich lerne Ruby und habe ein großes konzeptionelles Problem beim Tippen. Erlaube mir zu erklären, warum ich das Paradigma nicht verstehe.
Sagen Sie, ich bin eine Methodenverkettung für prägnanten Code wie in Ruby. Ich muss genau wissen, welchen Rückgabetyp jede Methode in der Kette aufruft, sonst kann ich nicht wissen, welche Methoden auf der nächsten Verbindung verfügbar sind. Muss ich jedes Mal die Methodendokumentation überprüfen? Ich laufe auf diese ständig laufenden Tutorial-Übungen. Es scheint, dass ich mit einem Prozess des Verweises festhalte, folge, laufe, scheitere, repariere, wiederhole, um Code laufen zu lassen, anstatt genau zu wissen, womit ich beim Codieren arbeite. Dies widerspricht Rubys Versprechen der Intuitivität.
Sagen wir, ich benutze eine Third-Party-Bibliothek, noch einmal muss ich wissen, welche Typen die Parameter übergeben dürfen, sonst bekomme ich einen Fehler. Ich kann mir den Code ansehen, aber es kann oder darf keine Kommentare oder Deklarationen darüber geben, welchen Typ die Methode erwartet. Ich verstehe, dass Code basierend auf Methoden für ein Objekt verfügbar ist, nicht für den Typ. Aber dann muss ich sicher sein, dass alles, was ich als Parameter übergebe, alle Methoden hat, die die Bibliothek erwartet, also muss ich noch eine Typüberprüfung durchführen. Muss ich hoffen und beten, dass alles an einer Schnittstelle richtig dokumentiert ist, damit ich weiß, ob ich einen String, einen Hash, eine Klasse, etc. geben soll.
Wenn ich mir die Quelle einer Methode anschaue, kann ich eine Liste der aufgerufenen Methoden erhalten und den erwarteten Typ ableiten, aber ich muss eine Analyse durchführen.
Eingabe von Ruby und Duck: Vertragsgestaltung unmöglich?
Die Diskussionen in der vorhergehenden stackoverflow-Frage beantworten wirklich nichts anderes als "es gibt Prozesse, denen Sie folgen müssen" und diese Prozesse scheinen nicht Standard zu sein, jeder hat eine andere Meinung darüber, welchen Prozess zu folgen, und Die Sprache hat keine Durchsetzung. Methodenvalidierung? Testgetriebenes Design? Dokumentierte API? Strenge Methoden Namenskonventionen? Was ist der Standard und wer diktiert das? Was folge ich? Würden diese Richtlinien dieses Problem lösen Ссылка ? Gibt es Editoren, die helfen?
Vom Konzept her habe ich auch keinen Vorteil. Sie müssen wissen, welche Methoden für jede aufgerufene Methode benötigt werden, also unabhängig davon, ob Sie etwas eingeben, wenn Sie etwas programmieren. Sie informieren die Sprache oder andere Personen nicht explizit, es sei denn, Sie beschließen, dies zu dokumentieren. Dann stecken Sie nicht mehr während der Programmierung, sondern während der Laufzeit alle Typprüfungen ab. Ich habe PHP und Python programmiert und ich verstehe es auch nicht.
Was vermisse ich oder verstehe ich nicht? Bitte helfen Sie mir, dieses Paradigma zu verstehen.
Dies ist kein Ruby-spezifisches Problem, es ist das gleiche für alle dynamisch typisierten Sprachen.
Normalerweise gibt es keine Richtlinien dafür, wie dies zu dokumentieren ist (und die meiste Zeit nicht wirklich möglich). Siehe zum Beispiel map in der Ruby-Dokumentation
%Vor% Was ist item
, block
und new_ary
hier und wie hängen sie zusammen? Es gibt keine Möglichkeit, dies zu sagen, es sei denn, Sie kennen die Implementierung oder können sie irgendwie aus dem Namen der Funktion ableiten. Die Angabe des Typs ist ebenfalls schwierig, da new_ary
davon abhängt, was block
zurückgibt, was wiederum vom Typ von item
abhängt, der für jedes Element im Array unterschiedlich sein kann.
Oft stolpert man auch über die Dokumentation, die besagt, dass ein Argument vom Typ Object
ist, was wiederum nichts sagt, da alles ein Objekt ist.
OCaml hat hierfür eine Lösung, es unterstützt strukturelle Typisierung, so dass eine Funktion, die ein Objekt mit einer Eigenschaft foo
benötigt, das ein String
ist, wird als { foo : String }
anstelle eines konkreten Typs abgeleitet. Aber OCaml ist immer noch statisch getippt.
Bemerkenswert ist, dass dies auch in statisch getippten Sprachen ein Problem sein kann. Scala hat sehr allgemeine Methoden für Sammlungen, die zu Typensignaturen wie ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Array[T], B, That]): That
für das Anhängen von zwei Sammlungen führen.
In den meisten Fällen müssen Sie dies nur in dynamisch typisierten Sprachen auswendig lernen und vielleicht die Dokumentation der von Ihnen verwendeten Bibliotheken verbessern.
Und deshalb bevorzuge ich statische Typisierung;)
Bearbeiten Eine Sache, die vielleicht Sinn macht, ist zu tun, was Scala auch tut. Sie zeigt diese Typ-Signatur für ++
nicht standardmäßig an, sondern zeigt ++[B](that: GenTraversableOnce[B]): Array[B]
an, was nicht so generisch ist, aber wahrscheinlich die meisten Anwendungsfälle abdeckt. Also könnte Rubys Karte eine monomorphe Signatur wie Array<a> -> (a -> b) -> Array<b>
haben. Es ist nur für die Fälle richtig, in denen die Liste nur Werte eines Typs enthält und der Block nur Elemente eines anderen Typs zurückgibt, aber es ist viel einfacher zu verstehen und gibt einen guten Überblick darüber, was die Funktion macht.
Beachten Sie, dass die Entwurfsoptionen stark typisierter Sprachen (C ++, Java, C # usw.) strikte Deklarationen des an Methoden übergebenen Typs und des von Methoden zurückgegebenen Typs erzwingen. Dies liegt daran, dass diese Sprachen entworfen wurden, um zu überprüfen, dass die Argumente korrekt sind (und da diese Sprachen kompiliert werden, kann diese Arbeit zur Kompilierungszeit ausgeführt werden). Einige Fragen können jedoch nur zur Laufzeit beantwortet werden, und C ++ beispielsweise verfügt über RTTI (Run Time Type Interpreter), um Typgarantien zu prüfen und durchzusetzen. Aber als Entwickler werden Sie von Syntax, Semantik und dem Compiler geleitet, um Code zu erzeugen, der diesen Typbeschränkungen folgt.
Ruby gibt Ihnen die Flexibilität, dynamische Argumenttypen zu verwenden und dynamische Typen zurückzugeben. Diese Freiheit ermöglicht es Ihnen, mehr generischen Code zu schreiben (lesen Sie Stepanov über die STL und generische Programmierung) und gibt Ihnen eine Fülle von Introspektionsmethoden (is_a ?, instance_of ?, respond_to ?, kind_of ?, is_array ?, usw.), die Sie kann dynamisch verwenden. Ruby ermöglicht es Ihnen, generische Methoden zu schreiben, aber Sie können das Design auch explizit nach Vertrag erzwingen und das Fehlschlagen des Vertrags mit der gewählten Methode bearbeiten.
Ja, Sie müssen vorsichtig sein, wenn Sie Methoden aneinander ketten, aber Ruby zu lernen ist nicht nur ein paar neue Schlüsselwörter. Ruby unterstützt mehrere Paradigmen; Sie können prozedurale, objektorientierte, generische und funktionale Programme schreiben. Der Zyklus, in dem Sie gerade sind, wird sich schnell verbessern, wenn Sie etwas über Ruby erfahren.
Vielleicht liegt Ihre Besorgnis an einer Voreingenommenheit gegenüber stark typisierten Sprachen (C ++, Java, C #, usw.). Duck Typisierung ist ein anderer Ansatz. Du denkst anders. Duck typing bedeutet, dass wenn ein Objekt wie a aussieht, sich wie ein a verhält, dann ist es ein. Alles (fast) ist ein Objekt in Ruby, also ist alles polymorph.
Betrachten Sie Vorlagen (C ++ hat sie, C # hat sie, Java bekommt sie, C hat Makros). Sie erstellen einen Algorithmus und lassen den Compiler Instanzen für die ausgewählten Typen generieren. Sie machen kein Vertragsdesign mit Generika, aber wenn Sie ihre Macht erkennen, schreiben Sie weniger Code und produzieren mehr.
Einige Ihrer anderen Anliegen,
Vorschlag - gehen Sie unvoreingenommen auf ein Online-Tutorial zu, machen Sie das Tutorial ( Ссылка ist gut), und Sie werden es tun fokussiertere Fragen.
Ja, Sie scheinen das Konzept falsch zu verstehen. Es ist kein Ersatz für die statische Typprüfung. Es ist nur anders . Wenn Sie zum Beispiel Objekte in json konvertieren (um sie in den Client zu rendern), interessiert Sie der tatsächliche Typ des Objekts nicht, solange es #to_json
method hat. In Java müssten Sie IJsonable
interface erstellen. In Ruby wird kein Overhead benötigt.
Wie zu wissen, was wo passiert und was was zurückgibt: merken Sie sich dies oder konsultieren Sie jedes Mal Dokumente. Wir machen das alle.
Nur ein weiterer Tag, ich habe gesehen, Rails-Programmierer mit 6+ Jahren Erfahrung beschweren sich auf Twitter, dass er nicht die Reihenfolge der Parameter an alias_method
merken kann: geht neuer Name zuerst oder zuletzt?
Dies steht im Widerspruch zu Rubys Versprechen der Intuitivität.
Nicht wirklich. Vielleicht ist es nur schlecht geschriebene Bibliothek. Im Kern Ruby ist alles ziemlich intuitiv, wage ich zu sagen.
Statisch typisierte Sprachen mit ihren leistungsfähigen IDEs haben hier einen kleinen Vorteil, weil sie Ihnen hier sehr schnell die Dokumentation zeigen können. Dies greift jedoch immer noch auf die Dokumentation zu. Nur schneller.
Tags und Links ruby duck-typing