C ++ 0x bietet eine verdammt umfassende Unterstützung für Typinferenzen. Ich bin sehr versucht, es überall zu verwenden, um unnötige Wiederholungen zu vermeiden, aber ich frage mich, ob das Entfernen expliziter Typinformationen überall eine so gute Idee ist. Betrachten Sie dieses ziemlich erfundene Beispiel:
Foo.h
::
#include <set>
class Foo {
private:
static std::set<Foo*> instances;
public:
Foo();
~Foo();
// What does it return? Who cares! Just forward it!
static decltype(instances.begin()) begin() {
return instances.begin();
}
static decltype(instances.end()) end() {
return instances.end();
}
};
Foo.cpp
::
#include <Foo.h>
#include <Bar.h>
// The type need only be specified in one location!
// But I do have to open the header to find out what it actually is.
decltype(Foo::instances) Foo::instances;
Foo() {
// What is the type of x?
auto x = Bar::get_something();
// What does do_something() return?
auto y = x.do_something(*this);
// Well, it's convertible to bool somehow...
if (!y) throw "a constant, old school";
instances.insert(this);
}
~Foo() {
instances.erase(this);
}
Würden Sie sagen, dass dies vernünftig ist oder ist es völlig lächerlich? Schließlich, vor allem , wenn Sie es gewohnt sind in einer dynamischen Sprache zu entwickeln, müssen Sie nicht wirklich brauchen vertrauen , dass alle viel über die Arten der Dinge, und kann zu sorgen , dass der Compiler keine ungeheuerlichen Missbrauch des Typsystems fangen. Aber für diejenigen unter Ihnen, die auf die Unterstützung von Editoren für Methodensignaturen angewiesen sind, haben Sie kein Glück. Daher ist die Verwendung dieses Stils in einer Bibliotheksschnittstelle wahrscheinlich eine schlechte Praxis.
Ich finde, dass das Schreiben von Dingen mit allen möglichen impliziten Typen es mir tatsächlich viel einfacher macht, meinem Code zu folgen, da dadurch fast die gesamte übliche Unordnung von C ++ beseitigt wird. Ihr Kilometerstand kann natürlich variieren, und das ist es, worüber ich gerne hören möchte. Was sind die spezifischen Vor- und Nachteile einer radikalen Verwendung der Typinferenz?
quelle
Antworten:
Da ich selbst hauptsächlich Python-Programmierer bin, teile ich die Einstellung, dass der Programmierer den genauen Typ nicht kennen muss. Im Fall von C ++, insbesondere beim Umgang mit Vorlagen Vorlagen Vorlagen ... Vorlagen. Das liegt natürlich nicht daran, dass ich statisches Tippen ablehne (ich nicht - ich halte Haskell für eines der besten Dinge seit geschnittenem Brot, teilweise wegen seiner statischen Typisierung), sondern daran, dass mir der genaue Typ nicht wichtig ist. Warum, wird nicht gut durch Beispiele demonstriert, die Namen wie
foo
oder verwendenget_stuff()
. Wählen wir also etwas, das der Realität näher kommt:Keine einzige Typanmerkung, aber es ist völlig klar, was sie tut, oder? Diesem Code ist es egal, um welche Art es sich handelt
users
, er benötigt nur einen Bereich, um zu iterieren, der Dinge mit einem enthältname
, dem zugeführt werden kanncheck_name
. Nichts mehr. Niemand kümmert sich um die 100-stelligen Zeichen von Typnamen, die Sie sonst eingeben müssten.Gleiches gilt für die meisten Codes mit aussagekräftigen Namen. Das Beispiel in der Frage ist nicht klar, aber es wäre auch nicht klar mit expliziten Typnamen, da weder Kontext noch Bezeichner einen Hinweis darauf geben, was los ist. Verwenden Sie aussagekräftige Bezeichner, und der Code kann unabhängig von expliziten Typanmerkungen verstanden werden.
quelle
Der Grund, warum sie Schlussfolgerungen gezogen haben, war zu verhindern, dass Leute Code schreiben wie:
Wann könnten Sie schreiben:
Außer, dass Foo ein Typ mit langen Vorlagen wäre, also wird es schöner zu schreiben:
Als Faustregel gilt: Wenn Sie bei Verwendung von auto Code wie oben anstelle von Code ähnlich dem ersten Beispiel schreiben, verwenden Sie ihn auf jeden Fall. Andernfalls bleiben Sie beim Hinzufügen expliziter Definitionen.
quelle
auto
in vielen Fällen wieder, in denen ich sicher bin, dass andere explizit sind, aber ich sehe nicht, was wirklich falsch ist, sagen wirauto f = new SomethingLong()
, weil es offensichtlich ist, was der Ausdruck zurückgibt. Ich frage mich nur, wo ich die Grenze ziehen soll.SomethingLong
es nicht Teil einer Vererbungsstruktur ist, aber wenn Sie nicht sicher sind, dass dies niemals der Fall sein wird, würde ich davon abraten. Es ist viel einfacher, die Linie auf der vorsichtigen Seite zu ziehen.Es gibt gute Gründe, die Typinferenz nicht immer zu verwenden. Haskell hat Typinferenz, aber normalerweise deklariere ich Funktionstypen trotzdem explizit. Das ist teilweise ein Ergebnis meines Entwicklungsstils. Ich deklariere zuerst die Funktion:
Als nächstes schreibe ich den Code, der diese Funktion verwendet, und kompiliere, um sicherzustellen, dass die Typprüfungen durchgeführt werden. Sobald die Typprüfungen abgeschlossen sind, werde ich mit der Implementierung fortfahren.Der andere Grund für die Deklaration von Funktionstypen besteht darin, dass die Deklarationen als zusätzliche Dokumentation dienen können. Dass diese Dokumentation bei jeder Kompilierung überprüft wird, ist ein Bonus.
quelle