Vorlagen in C++Bearbeiten

Hauptartikel: Vorlage (C++)

C++ verwendet Vorlagen, um generische Programmiertechniken zu ermöglichen. Die C++ – Standardbibliothek enthält die Standard-Vorlagenbibliothek oder STL, die ein Framework von Vorlagen für gängige Datenstrukturen und Algorithmen bereitstellt. Vorlagen in C++ können auch für die Metaprogrammierung von Vorlagen verwendet werden, um einen Teil des Codes zur Kompilierungszeit und nicht zur Laufzeit vorab auszuwerten. Mithilfe der Vorlagenspezialisierung werden C++ – Vorlagen als Turing-vollständig betrachtet.,

Technische Übersicht

Es gibt zwei Arten von Vorlagen: Funktionsvorlagen und Klassenvorlagen. Eine Funktionsvorlage ist ein Muster zum Erstellen gewöhnlicher Funktionen basierend auf den Parametriertypen, die bei der Instanziierung angegeben werden. Zum Beispiel enthält die C++ Standard Template Library die Funktionsvorlage max(x, y), die Funktionen erstellt, die entweder x oder y zurückgeben, je nachdem, was größer ist., max() könnte folgendermaßen definiert werden:

template <typename T>T max(T x, T y) { return x < y ? y : x;}

Spezialisierungen dieser Funktionsvorlage, Instanziierungen mit bestimmten Typen, können wie eine gewöhnliche Funktion aufgerufen werden:

std::cout << max(3, 7); // Outputs 7.

Der Compiler untersucht die zum Aufrufen von max verwendeten Argumente und stellt fest, dass dies ein Aufruf von max ist. (int, int)., Anschließend wird eine Version der Funktion instanziiert, in der der Parametrierungstyp T int ist, was der folgenden Funktion entspricht:

int max(int x, int y) { return x < y ? y : x;}

Dies funktioniert unabhängig davon, ob die Argumente x und y Ganzzahlen, Zeichenfolgen oder ein anderer Typ sind, für den der Ausdruck x < y sinnvoll ist oder genauer gesagt für jeden Typ, für den operator< ist definiert. Gemeinsame Vererbung ist nicht für die Menge der Typen benötigt, die verwendet werden können, und so ist es sehr ähnlich wie Ente Typisierung., Ein Programm, das einen benutzerdefinierten Datentyp definiert, kann das Überladen von Operatoren verwenden, um die Bedeutung von < für diesen Typ zu definieren, wodurch die Verwendung mit der Funktionsvorlage max() ermöglicht wird. Während dies in diesem isolierten Beispiel ein kleiner Vorteil zu sein scheint, ermöglicht es dem Programmierer im Kontext einer umfassenden Bibliothek wie der STL, umfangreiche Funktionen für einen neuen Datentyp zu erhalten, indem er nur einige Operatoren dafür definiert., Durch bloße Definition von < kann ein Typ mit den Algorithmen standard sort(), stable_sort () und binary_search() verwendet oder in Datenstrukturen wie Mengen, Heaps und assoziativen Arrays abgelegt werden.

C++ – Vorlagen sind zur Kompilierungszeit vollständig typsicher. Als Demonstration definiert der Standardtyp complex nicht den Operator <, da es keine strenge Reihenfolge für komplexe Zahlen gibt. Daher schlägt max(x, y) mit einem Kompilierungsfehler fehl, wenn x und y komplexe Werte sind., Ebenso können andere Vorlagen, die auf <, nur dann auf komplexe Daten angewendet werden, wenn ein Vergleich (in Form eines Funktors oder einer Funktion) bereitgestellt wird. ZB: Ein Komplex kann nicht als Schlüssel für eine Karte verwendet werden, es sei denn, ein Vergleich wird angegeben. Leider erzeugen Compiler historisch gesehen etwas esoterische, lange und nicht hilfreiche Fehlermeldungen für diese Art von Fehler. Das Sicherstellen, dass ein bestimmtes Objekt an einem Methodenprotokoll haftet, kann dieses Problem beheben. Sprachen, die compare anstelle von < können auch komplexe Werte als Schlüssel verwenden.,

Die zweite Art von Vorlage, eine Klassenvorlage, erweitert dasselbe Konzept auf Klassen. Eine Klassenvorlagenspezialisierung ist eine Klasse. Klassenvorlagen werden häufig verwendet, um generische Container zu erstellen. Beispielsweise verfügt die STL über einen verknüpften Listencontainer. Um eine verknüpfte Liste von ganzen zahlen schreibt man list<int>. Eine Liste von Zeichenfolgen wird mit list<string>bezeichnet. Einer Liste ist eine Reihe von Standardfunktionen zugeordnet, die für alle kompatiblen Parametriertypen funktionieren.,

Template specializationEdit

Eine leistungsstarke Funktion von C++’s Vorlagen ist Template-Spezialisierung. Auf diese Weise können alternative Implementierungen basierend auf bestimmten Merkmalen des parametrisierten Typs bereitgestellt werden, der instanziiert wird. Die Vorlagenspezialisierung hat zwei Zwecke: bestimmte Optimierungsformen zuzulassen und das Aufblähen von Code zu reduzieren.

Betrachten Sie beispielsweise eine Vorlagenfunktion sort (). Eine der Hauptaktivitäten einer solchen Funktion besteht darin, die Werte an zwei Positionen des Containers auszutauschen oder auszutauschen., Wenn die Werte groß sind (in Bezug auf die Anzahl der Bytes, die zum Speichern der einzelnen Bytes benötigt werden), ist es oft schneller, zuerst eine separate Liste von Zeigern auf die Objekte zu erstellen, diese Zeiger zu sortieren und dann die endgültige sortierte Sequenz zu erstellen. Wenn die Werte recht klein sind, ist es jedoch normalerweise am schnellsten, die Werte nach Bedarf einfach an Ort und Stelle auszutauschen. Wenn der parametrisierte Typ bereits einen Zeigertyp hat, ist es außerdem nicht erforderlich, ein separates Zeigerarray zu erstellen., Durch die Vorlagenspezialisierung kann der Vorlagenersteller verschiedene Implementierungen schreiben und die Merkmale angeben, die die parametrisierten Typen für jede zu verwendende Implementierung haben müssen.

Im Gegensatz zu Funktionsvorlagen können Klassenvorlagen teilweise spezialisiert werden. Das bedeutet, dass eine alternative Version des Klassenvorlagencodes bereitgestellt werden kann, wenn einige der Vorlagenparameter bekannt sind, während andere Vorlagenparameter generisch bleiben., Dies kann beispielsweise verwendet werden, um eine Standardimplementierung (die primäre Spezialisierung) zu erstellen, die davon ausgeht, dass das Kopieren eines Parametriertyps teuer ist, und dann teilweise Spezialisierungen für Typen zu erstellen, die billig zu kopieren sind, wodurch die Gesamteffizienz erhöht wird. Clients einer solchen Klassenvorlage verwenden nur Spezialisierungen davon, ohne wissen zu müssen, ob der Compiler jeweils die primäre Spezialisierung oder eine teilweise Spezialisierung verwendet hat., Klassenvorlagen können auch vollständig spezialisiert sein, was bedeutet, dass eine alternative Implementierung bereitgestellt werden kann, wenn alle Parametriertypen bekannt sind.

Vorteile und Nachteiligkeitedit

Einige Verwendungen von Vorlagen, wie z. B. die Funktion max (), wurden zuvor durch funktionsähnliche Präprozessormakros (ein Vermächtnis der Programmiersprache C) gefüllt. Hier ist beispielsweise ein mögliches max () Makro:

#define max(a,b) ((a) < (b) ? (b) : (a))

Makros werden vor der eigentlichen Kompilierung durch Präprozessor erweitert; Vorlagen werden zur Kompilierungszeit erweitert., Makros werden immer inline erweitert; Vorlagen können auch als Inline-Funktionen erweitert werden, wenn der Compiler dies für angemessen hält. Daher haben sowohl funktionsähnliche Makros als auch Funktionsvorlagen keinen Laufzeitaufwand.

Vorlagen werden jedoch im Allgemeinen als Verbesserung gegenüber Makros für diese Zwecke angesehen. Vorlagen sind typsicher. Vorlagen vermeiden einige der häufigsten Fehler im Code, die funktionsähnliche Makros stark nutzen, z. B. die doppelte Auswertung von Parametern mit Nebenwirkungen. Vielleicht am wichtigsten, Vorlagen wurden entwickelt, um auf viel größere Probleme als Makros anwendbar zu sein.,

Die Verwendung von Vorlagen hat vier Hauptnachteile: unterstützte Funktionen, Compiler-Unterstützung, schlechte Fehlermeldungen und Aufblähen des Codes:

  1. Vorlagen in C++ fehlen viele Funktionen, was die Implementierung und Verwendung auf einfache Weise oft unmöglich macht. Stattdessen müssen sich Programmierer auf komplizierte Tricks verlassen, die zu aufgeblähtem, schwer verständlichem und schwer zu wartendem Code führen. Aktuelle Entwicklungen in den C++ – Standards verschärfen dieses Problem, indem Sie diese Tricks intensiv nutzen und viele neue Funktionen für Vorlagen erstellen.,
  2. Viele Compiler haben historisch gesehen eine schlechte Unterstützung für Vorlagen, daher kann die Verwendung von Vorlagen Code etwas weniger portabel machen. Die Unterstützung kann auch schlecht sein, wenn ein C++-Compiler mit einem Linker verwendet wird, der nicht C++ – fähig ist, oder wenn versucht wird, Vorlagen über gemeinsam genutzte Bibliotheksgrenzen hinweg zu verwenden. Die meisten modernen Compiler verfügen jedoch jetzt über eine ziemlich robuste und standardmäßige Vorlagenunterstützung, und der neue C++ – Standard C++11 behebt diese Probleme weiter.
  3. Fast alle Compiler erzeugen verwirrende, lange oder manchmal nicht hilfreiche Fehlermeldungen, wenn Fehler in Code erkannt werden, der Vorlagen verwendet., Dies kann die Entwicklung von Vorlagen erschweren.
  4. Schließlich erfordert die Verwendung von Vorlagen, dass der Compiler für jede Permutation der damit verwendeten Typparameter eine separate Instanz der Vorlagenklasse oder Funktion generiert. (Dies ist notwendig, da Typen in C++ nicht alle die gleiche Größe haben und die Größe von Datenfeldern für die Klassenarbeit wichtig ist.) Die wahllose Verwendung von Vorlagen kann also zu einer Aufblähung des Codes führen, was zu übermäßig großen ausführbaren Dateien führt., Eine vernünftige Verwendung von Vorlagenspezialisierung und-ableitung kann jedoch in einigen Fällen ein solches Aufblähen des Codes drastisch reduzieren:

Kann die Ableitung verwendet werden, um das Problem der Codereplikation zu reduzieren, da Vorlagen verwendet werden? Dies würde das Ableiten einer Vorlage aus einer normalen Klasse beinhalten. Diese Technik erwies sich als erfolgreich bei der Eindämmung von Code Bloat im realen Gebrauch. Leute, die keine solche Technik verwenden, haben festgestellt, dass replizierter Code selbst in Programmen mittlerer Größe Megabyte Code-Speicherplatz kosten kann.,

– Bjarne Stroustrup, The Design and Evolution of C++, 1994

Die zusätzlichen Instanziierungen, die von Vorlagen generiert werden, können auch dazu führen, dass Debugger Schwierigkeiten haben, ordnungsgemäß mit Vorlagen zu arbeiten. Beispielsweise kann das Festlegen eines Debug-Haltepunkts innerhalb einer Vorlage aus einer Quelldatei entweder das Festlegen des Haltepunkts in der gewünschten tatsächlichen Instanziierung übersehen oder an jeder Stelle, an der die Vorlage instanziiert wird, einen Haltepunkt festlegen.,

Da der Compiler makroähnliche Erweiterungen von Vorlagen durchführen und zur Kompilierungszeit verschiedene Instanzen davon generieren muss, muss der Implementierungsquellcode für die Vorlagenklasse oder-funktion für den Code verfügbar sein (z. B. in einem Header enthalten) es verwenden. Template-Klassen oder-Funktionen, einschließlich eines großen Teils der Standard Template Library (STL), wenn sie nicht in Header-Dateien enthalten sind, können nicht kompiliert werden. (Dies steht im Gegensatz zu nicht Vorlagencode, der möglicherweise binär kompiliert wird und nur eine Deklarationsheaderdatei für den Code bereitstellt, der ihn verwendet.,) Dies kann ein Nachteil sein, wenn der implementierende Code offengelegt wird, der einige Abstraktionen entfernt und seine Verwendung in Closed-Source-Projekten einschränken kann.

Templates in DEdit

Die Programmiersprache D unterstützt Templates, die auf C++basieren.,Die meisten C++ – Template-Idiome werden ohne Änderung auf D übertragen, aber D fügt einige zusätzliche Funktionen hinzu:

  • Template-Parameter in D sind nicht nur auf Typen und primitive Werte beschränkt, sondern erlauben auch beliebige Kompilierungszeitwerte (wie Strings und Strukturliterale) und Aliase für beliebige Bezeichner, einschließlich anderer Vorlagen oder Template-Instanziierungen.
  • Template-Einschränkungen und die statische if-Anweisung bieten eine Alternative zu C++’s Substitutionsfehler ist kein Fehler (SFINAE) Mechanismus, ähnlich wie C++ Konzepte.
  • Der is(…,) expression ermöglicht spekulative Instanziierung, um die Eigenschaften eines Objekts zur Kompilierungszeit zu überprüfen.
  • Das Schlüsselwort auto und der typeof-Ausdruck erlauben Typinferenz für Variablendeklarationen und Funktionsrückgabewerte, was wiederum „Voldemort-Typen“ (Typen ohne globalen Namen) zulässt.

Vorlagen in D verwenden eine andere Syntax als in C++: Während in C++ Template-Parameter in eckigen Klammern stehen (Template<param1, param2>), verwendet D ein Ausrufezeichen und Klammern: Template!(param1, param2).,Dies vermeidet die C++ – Parsing-Schwierigkeiten aufgrund von Mehrdeutigkeiten mit Vergleichsoperatoren.Wenn nur ein Parameter vorhanden ist, können die Klammern weggelassen werden.

Herkömmlicherweise kombiniert D die oben genannten Funktionen, um einen Kompilierzeitpolymorphismus unter Verwendung einer merkmalsbasierten generischen Programmierung bereitzustellen.,Ein Eingabebereich ist beispielsweise definiert als jeder Typ, der die von isInputRange durchgeführten Prüfungen erfüllt, der wie folgt definiert ist:

Eine Funktion, die nur Eingabebereiche akzeptiert, kann dann die obige Vorlage in einer Vorlageneinschränkung verwenden:

auto fun(Range)(Range range) if (isInputRange!Range){ // ...}
Code generationEdit

Zusätzlich zur Vorlagenmetaprogrammierung bietet D mehrere Funktionen, um die Codegenerierung zur Kompilierungszeit zu ermöglichen:

auto fun(Range)(Range range) if (isInputRange!Range){ // ...}
  • Der Importausdruck ermöglicht das Lesen einer Datei von der Festplatte und die Verwendung ihres Inhalts als Zeichenfolgenausdruck.,
  • Compile-time reflection ermöglicht die Aufzählung und Überprüfung von Deklarationen und deren Mitgliedern während der Kompilierung.
  • Benutzerdefinierte Attribute ermöglichen es Benutzern, Deklarationen beliebige Bezeichner anzuhängen, die dann mithilfe der Kompilierungszeitreflexion aufgezählt werden können.
  • Compile-Time Function Execution (CTFE) ermöglicht die Interpretation einer Teilmenge von D (beschränkt auf sichere Operationen) während der Kompilierung.
  • String-Mixins ermöglichen das Auswerten und Kompilieren des Inhalts eines String-Ausdrucks als D-Code, der Teil des Programms wird.,

Durch die Kombination der oben genannten Elemente kann Code basierend auf vorhandenen Deklarationen generiert werden.Beispielsweise können D-Serialisierungsframeworks die Mitglieder eines Typs aufzählen und spezielle Funktionen für jeden serialisierten Typ generieren, um die Serialisierung und Deserialisierung durchzuführen.Benutzerdefinierte Attribute können weiter auf Serialisierungsregeln hinweisen.

Der Importausdruck und die Ausführung von Kompilierungsfunktionen ermöglichen auch die effiziente Implementierung domänenspezifischer Sprachen.,Bei einer Funktion, die eine Zeichenfolge mit einer HTML-Vorlage verwendet und einen äquivalenten D-Quellcode zurückgibt, ist es beispielsweise möglich, sie auf folgende Weise zu verwenden:

Generizität in EiffelEdit

Generische Klassen sind seit dem ursprünglichen Methoden-und Sprachdesign Teil von Eiffel. Die Stiftung Publikationen von Eiffel, verwenden Sie den Begriff Generizität, um die Erstellung und Verwendung von generischen Klassen zu beschreiben.

Basic / Unconstrained genericityEdit

Generische Klassen werden mit ihrem Klassennamen und einer Liste von einem oder mehreren formalen generischen Parametern deklariert., Im folgenden Code hat die Klasse LIST einen formalen generischen Parameter G

Die formalen generischen Parameter sind Platzhalter für beliebige Klassennamen, die bei einer Deklaration der generischen Klasse angegeben werden, wie in den beiden generischen Ableitungen unten gezeigt, wobei ACCOUNT und DEPOSIT andere klassennamen. ACCOUNT und DEPOSIT gelten als tatsächliche generische Parameter, da sie echte Klassennamen bereitstellen, die bei tatsächlicher Verwendung G ersetzen.,

 list_of_accounts: LIST -- Account list list_of_deposits: LIST -- Deposit list

Im Eiffeltypsystem wird die Klasse LIST zwar als Klasse betrachtet, jedoch nicht als Typ. Eine generische Ableitung von LIST wie LIST wird jedoch als Typ betrachtet.

Eingeschränkte Generizitätedit

Für die oben gezeigte Listenklasse kann ein tatsächlicher generischer Parameter, der G ersetzt, jede andere verfügbare Klasse sein., Um den Satz von Klassen einzuschränken, aus denen gültige tatsächliche generische Parameter ausgewählt werden können, kann eine generische Einschränkung angegeben werden. In der Deklaration der Klasse SORTED_LIST unten schreibt die generische Einschränkung vor, dass jeder gültige tatsächliche generische Parameter eine Klasse ist, die von der Klasse COMPARABLEerbt. Die generische Einschränkung stellt sicher, dass Elemente einer SORTED_LIST tatsächlich sortiert werden können.,

class SORTED_LIST 

Generika in JavaEdit

Hauptartikel: Generika in Java

Unterstützung für die Generika oder“ Container-of-type-T “ wurde der Java-Programmiersprache im Jahr 2004 als Teil von J2SE 5.0 hinzugefügt. In Java werden Generika nur zur Kompilierungszeit auf Typkorrektheit überprüft. Die generischen Typinformationen werden dann über einen Prozess namens type Erasure entfernt, um die Kompatibilität mit alten JVM-Implementierungen aufrechtzuerhalten, sodass sie zur Laufzeit nicht verfügbar sind., Beispielsweise wird eine List<String> in die Rohtypliste konvertiert. Der Compiler fügt Typumwandlungen ein, um die Elemente beim Abrufen aus der Liste in den Zeichenfolgentyp zu konvertieren, wodurch die Leistung im Vergleich zu anderen Implementierungen wie C++ – Vorlagen verringert wird.

Genericity in .NETTO Bearbeiten

Generika Hinzugefügt wurden, als Teil des .NET Framework 2.0 im November 2005, basierend auf einer Forschungs-Prototyp von Microsoft Research begann im Jahr 1999. Obwohl ähnlich wie Generika in Java, .,NET Generics wenden keine Typlöschung an, sondern implementieren Generika als erstklassigen Mechanismus in der Laufzeit mithilfe von Reification. Diese Entwurfsauswahl bietet zusätzliche Funktionen, z. B. Reflektion mit Beibehaltung generischer Typen sowie Linderung einiger Einschränkungen des Löschens (z. B. nicht in der Lage, generische Arrays zu erstellen). Dies bedeutet auch, dass es keinen Leistungseinbruch durch Laufzeitcasts und normalerweise teure Boxkonvertierungen gibt., Wenn primitive und Werttypen als generische Argumente verwendet werden, erhalten sie spezielle Implementierungen, die effiziente generische Sammlungen und Methoden ermöglichen. Wie in C++ und Java, geschachtelte generische Typen wie Dictionary< – string, List<int>> sind gültige Arten, jedoch abgeraten für die Signaturen in code-Analyse-design-Regeln.

.,NET ermöglicht sechs Arten generischer Typbeschränkungen, die das Schlüsselwort where verwenden, einschließlich der Einschränkung generischer Typen auf Werttypen, Klassen, Konstruktoren und Schnittstellen. Nachfolgend finden Sie ein Beispiel mit einer Schnittstelleneinschränkung:

Die Methode MakeAtLeast () ermöglicht den Betrieb von Arrays mit Elementen des generischen Typs T. Die Typeinschränkung der Methode gibt an, dass die Methode auf jeden Typ T anwendbar ist, der das generische IComparable implementiert<T> interface., Dies stellt einen Kompilierungsfehler sicher, wenn die Methode aufgerufen wird, wenn der Typ den Vergleich nicht unterstützt. Die Schnittstelle bietet die generische Methode CompareTo(T).

Die obige Methode könnte auch ohne generische Typen geschrieben werden, einfach mit dem nicht generischen Array-Typ. Da Arrays jedoch kontravariant sind, ist das Casting nicht typsicher und der Compiler kann bestimmte mögliche Fehler nicht finden, die andernfalls bei Verwendung generischer Typen abgefangen würden. Darüber hinaus müsste die Methode stattdessen auf die Array-Elemente als Objekte zugreifen und würde Casting erfordern, um zwei Elemente zu vergleichen., (Für Werttypen wie Typen wie int erfordert dies eine Boxkonvertierung, obwohl dies mit dem Komparator<T> Klasse umgangen werden kann, wie dies in den Standardsammlungsklassen der Fall ist.)

Ein bemerkenswertes Verhalten statischer Elemente in einer generischen. NET-Klasse ist die statische Memberinstanziierung pro Laufzeittyp (siehe Beispiel unten).

Generizität in DelphiEdit

Delphis Object Pascal-Dialekt erwarb Generika in der Delphi 2007-Version, zunächst nur mit dem (jetzt eingestellt) .,NET-Compiler vor dem Hinzufügen zum nativen Code in der Delphi 2009-Version. Die Semantik und die Fähigkeiten von Delphi Generics sind weitgehend denen von Generics in.NET 2.0 nachempfunden, obwohl die Implementierung notwendigerweise ganz anders ist. Hier ist eine mehr oder weniger direkte Übersetzung des ersten oben gezeigten C# – Beispiels:

Wie bei C# können Methoden sowie ganze Typen einen oder mehrere Typparameter haben. Im Beispiel ist TArray ein generischer Typ (definiert durch die Sprache) und MakeAtLeast eine generische Methode., Die verfügbaren Einschränkungen sind den verfügbaren Einschränkungen in C# sehr ähnlich: jeder Werttyp, jede Klasse, eine bestimmte Klasse oder Schnittstelle und eine Klasse mit einem parameterlosen Konstruktor. Mehrere Einschränkungen wirken als additive Union.

Generizität in Free PascalEdit

Free Pascal implementierte Generika vor Delphi und mit unterschiedlicher Syntax und Semantik. Seit der FPC-Version 2.6.0 ist die Syntax im Delphi-Stil jedoch verfügbar, wenn der Delphi-Sprachmodus {$mode} verwendet wird. So können freie Pascal-Programmierer Generika in jedem Stil verwenden, den sie bevorzugen.,

Delphi und Free Pascal Beispiel:

Funktionale Sprachenedit

Generizität in HaskellEdit

Der Typklassenmechanismus von Haskell unterstützt generische Programmierung.Sechs der vordefinierten Typklassen in Haskell (einschließlich Eq, den Typen, die auf Gleichheit verglichen werden können, und Show, deren Werte als Zeichenfolgen gerendert werden können) haben die spezielle Eigenschaft, abgeleitete Instanzen zu unterstützen., Dies bedeutet, dass ein Programmierer, der einen neuen Typ definiert, angeben kann, dass dieser Typ eine Instanz einer dieser speziellen Typklassen sein soll, ohne Implementierungen der Klassenmethoden bereitzustellen, wie dies normalerweise beim Deklarieren von Klasseninstanzen erforderlich ist. Alle notwendigen Methoden werden“ abgeleitet “ – dh automatisch konstruiert – basierend auf der Struktur des Typs.,Die folgende Deklaration eines Typs von Binärbäumen besagt beispielsweise, dass es sich um eine Instanz der Klassen Eq und Show:

data BinTree a = Leaf a | Node (BinTree a) a (BinTree a) deriving (Eq, Show)

Dies führt dazu, dass eine Gleichheitsfunktion (==) und eine Zeichenfolgendarstellungsfunktion (show) automatisch für jeden Typ des Formulars definiert werden BinTree T vorausgesetzt, dass T selbst diese Operationen unterstützt.,

Die Unterstützung abgeleiteter Instanzen von Eq und Show macht ihre Methoden == und show generisch qualitativ anders als para-metrisch polymorphe Funktionen: Diese „Funktionen“ (genauer gesagt typindizierte Funktionsfamilien) können auf Werte verschiedener Typen angewendet werden, und obwohl sie sich für jeden Argumenttyp unterschiedlich verhalten, ist wenig Arbeit erforderlich, um Unterstützung für einen neuen Typ hinzuzufügen. Ralf Hinze (2004) hat gezeigt, dass ein ähnlicher Effekt für benutzerdefinierte Typklassen durch bestimmte Programmiertechniken erzielt werden kann., Andere Forscher haben Ansätze für diese und andere Arten von Generizität im Zusammenhang mit Haskell und Erweiterungen von Haskell vorgeschlagen (siehe unten).

PolyPEdit

PolyP war die erste generische Programmiersprachenerweiterung für Haskell. In PolyP werden generische Funktionen polytypisch genannt. Die Sprache führt ein spezielles Konstrukt ein, in dem solche polytypischen Funktionen über strukturelle Induktion über die Struktur des Musterfunktors eines regulären Datentyps definiert werden können. Reguläre Datentypen in PolyP sind eine Teilmenge von Haskell-Datentypen., Ein regulärer Datentyp t muss von der Art * → * sein, und wenn a das formale Typargument in der Definition ist, müssen alle rekursiven Aufrufe von t die Form t a. Diese Einschränkungen schließen übergeordnete Datentypen sowie verschachtelte Datentypen aus, bei denen die rekursiven Aufrufe eine andere Form haben.Die Flatten-Funktion in PolyP wird hier als Beispiel bereitgestellt:

Generic HaskellEdit

Generic Haskell ist eine weitere Erweiterung von Haskell, die an der Universität Utrecht in den Niederlanden entwickelt wurde., Die bereitgestellten Erweiterungen sind:

  • Typindizierte Werte werden als Wert definiert, der über die verschiedenen Haskell-Typkonstruktoren (unit, primitive Typen, Summen, Produkte und benutzerdefinierte Typkonstruktoren) indiziert ist. Darüber hinaus können wir auch das Verhalten von typindizierten Werten für einen bestimmten Konstruktor mithilfe von Konstruktorfällen angeben und eine generische Definition in einer anderen mit Standardfällen wiederverwenden.

Der resultierende typindizierte Wert kann auf jeden Typ spezialisiert werden.

  • Kind-indizierte Typen sind Typen, die über Arten indiziert sind, definiert durch Angabe eines Falls für * und k → k‘., Instanzen werden erhalten, indem der Typ kind-indexed auf eine Art angewendet wird.
  • Generische Definitionen können verwendet werden, indem sie auf einen Typ oder eine Art angewendet werden. Dies wird als generische Anwendung bezeichnet. Das Ergebnis ist ein Typ oder Wert, je nachdem, welche Art von generischer Definition angewendet wird.
  • Mit der generischen Abstraktion können generische Definitionen definiert werden, indem ein Typparameter (einer bestimmten Art) abstrahiert wird.
  • Typindizierte Typen sind Typen, die über die Typkonstruktoren indiziert werden. Diese können verwendet werden, um Typen zu mehr beteiligten generischen Werten zu geben., Die resultierenden typindizierten Typen können auf jeden Typ spezialisiert werden.

Als Beispiel bietet die Gleichheitsfunktion in Generic Haskell:

CleanEdit

Clean generische programmierbasierte Polypen und die generische Haskell, wie sie vom GHC unterstützt wird>=6.0. Es parametrisiert nach Art als solche, bietet aber Überlastung.

Andere Sprachenedit

Die ML-Familie von Programmiersprachen unterstützt generische Programmierung durch parametrischen Polymorphismus und generische Module, die als Funktoren bezeichnet werden.,Sowohl Standard ML als auch OCaml bieten Funktoren, die Klassenvorlagen und generischen Ada-Paketen ähneln. Schema syntaktische Abstraktionen haben auch eine Verbindung zur Generizität – diese sind in der Tat eine Obermenge von Templating à la C++.

Ein Verilog-Modul kann einen oder mehrere Parameter verwenden, denen ihre tatsächlichen Werte bei der Instanziierung des Moduls zugewiesen werden. Ein Beispiel ist ein generisches Registerarray, bei dem die Array-Breite über einen Parameter angegeben wird., Ein solches Array kann in Kombination mit einem generischen Drahtvektor aus einer einzelnen Modulimplementierung einen generischen Puffer oder ein Speichermodul mit einer beliebigen Bitbreite herstellen.

VHDL, abgeleitet von Ada, hat auch generische Funktionen.