Allgemeine Programmierung

In der einfachsten Definition ist allgemeine Programmierung ein Stil der Computerprogrammierung, in der Algorithmen geschrieben werden in Bezug auf, spätere Typen angegeben zu werden, die dann, wenn erforderlich, für spezifische als Rahmen zur Verfügung gestellte Typen realisiert werden. Diese Annäherung, die von Ada 1983 den Weg gebahnt ist, erlaubt, allgemeine Funktionen oder Typen zu schreiben, die sich nur im Satz von Typen unterscheiden, auf denen sie, wenn verwendet, funktionieren, so Verdoppelung reduzierend. Solche Softwareentitäten sind als generics in Ada, Eiffel, Java, C#, F#, und Visueller Grundlegender.NET bekannt; parametrischer polymorphism in ML, Scala und Haskell (gebraucht die Gemeinschaft von Haskell auch den Begriff "allgemeiner" für ein zusammenhängendes, aber etwas verschiedenes Konzept); Schablonen in C ++; und parametrisierte Typen bestellen einflussreichen 1994 Designmuster vor. Die Autoren von Designmustern bemerken, dass diese Technik, besonders wenn verbunden, mit der Delegation, sehr stark ist, aber dass" [dynamisch] hoch parametrisierte Software härter ist zu verstehen als mehr statische Software."

Allgemeine Programmierung des Begriffes wurde von David Musser und Alexander Stepanov in einem spezifischeren Sinn ursprünglich ins Leben gerufen als das obengenannte, um eine Annäherung an die Softwarezergliederung zu beschreiben, wodurch grundsätzliche Voraussetzungen an Typen von jenseits konkreter Beispiele von Algorithmen und Datenstrukturen abstrahiert und als Konzepte analog zur Abstraktion von algebraischen Theorien in der abstrakten Algebra formalisiert werden. Frühe Beispiele dieser Programmierannäherung wurden im Schema und Ada durchgeführt, obwohl das am besten bekannte Beispiel Standard Template Library (STL) ist, in der eine Theorie von iterators entwickelt wird, der an decouple Folge-Datenstrukturen und die Algorithmen gewöhnt ist, die auf ihnen funktionieren.

Zum Beispiel, gegeben Folge-Datenstrukturen, hat z.B einzeln Liste, Vektor usw. und Algorithmen verbunden, um auf ihnen z.B usw. zu funktionieren, eine direkte Annäherung würde jeden Algorithmus spezifisch für jede Datenstruktur durchführen, Kombinationen gebend, um durchzuführen. Jedoch, in der allgemeinen Programmierannäherung, gibt jede Datenstruktur ein Modell eines iterator Konzepts zurück (ein einfacher Werttyp, der dereferenced sein kann, um den aktuellen Wert, oder geändert zum Punkt zu einem anderen Wert in der Folge wiederzubekommen), und jeder Algorithmus stattdessen allgemein mit Argumenten solchen iterators, z.B ein Paar von iterators geschrieben wird, der zum Anfang und Ende der Subfolge hinweist, um in einer Prozession zu gehen. So müssen nur Datenkombinationen des Struktur-Algorithmus durchgeführt werden. Mehrere iterator Konzepte werden im STL, jeder angegeben, der eine Verbesserung von einschränkenderen Konzepten z.B iterators nachschickt, nur stellen Bewegung dem folgenden Wert in einer Folge zur Verfügung (z.B. passend für eine einzeln verbundene Liste), wohingegen ein zufälliger Zugang iterator auch direkten unveränderlich-maligen Zugang zu jedem Element der Folge (z.B passend für einen Vektoren) zur Verfügung stellt. Ein wichtiger Punkt ist, dass eine Datenstruktur ein Modell des am meisten Gesamtkonzeptes zurückgeben wird, das effizient durchgeführt werden kann — sind rechenbetonte Kompliziertheitsvoraussetzungen ausführlich ein Teil der Konzeptdefinition. Das beschränkt, auf den Datenstrukturen ein gegebener Algorithmus angewandt werden kann und solche Kompliziertheitsvoraussetzungen eine Hauptdeterminante der Datenstruktur-Wahl sind. Allgemeine Programmierung ist ähnlich in anderen Gebieten z.B Graph-Algorithmen angewandt worden.

Bemerken Sie, dass, obwohl diese Annäherung häufig Spracheigenschaften der Übersetzungszeit genericity/templates verwertet, es tatsächlich von besonderen sprachtechnischen Details unabhängig ist. Allgemeiner Programmierpionier Alexander Stepanov hat geschrieben: "Allgemeine Programmierung ist über das Entziehen und Klassifizieren von Algorithmen und Datenstrukturen. Es bekommt seine Inspiration von Knuth und nicht aus der Typ-Theorie. Seine Absicht ist der zusätzliche Aufbau von systematischen Katalogen von nützlichen, effizienten und abstrakten Algorithmen und Datenstrukturen. Solch ein Unternehmen ist noch ein Traum."; und "Ich glaube, dass iterator Theorien so zur Informatik zentral sind wie Theorien von Ringen oder Banachräume zur Mathematik zentral sind." Folgender Stepanov, Bjarne Stroustrup hat allgemeine Programmierung definiert, ohne Spracheigenschaften zu erwähnen: "[l] ift Algorithmen und Datenstrukturen von konkreten Beispielen bis ihre allgemeinste und abstrakte Form."

Andere Programmierparadigmen, die als allgemeine Programmierung beschrieben worden sind, schließen datatype allgemeine Programmierung, wie beschrieben, in die "allgemeine Programmierung — eine Einführung" ein. Das Stück Ihre Textbaustein-Annäherung ist eine allgemeine Leichtgewichtsprogrammierannäherung für Haskell (Lämmel und Peyton Jones, 2003).

In diesem Artikel unterscheiden wir die Programmierparadigmen auf höchster Ebene der allgemeinen Programmierung oben, aus der Programmiersprache der niedrigeren Ebene genericity Mechanismen hat gepflegt, sie durchzuführen (sieh Programmiersprache-Unterstützung für genericity). Für die weitere Diskussion und den Vergleich von allgemeinen Programmierparadigmen, sieh.

Programmiersprache-Unterstützung für genericity

Möglichkeiten von Genericity haben auf höheren Programmiersprachen seitdem mindestens die 1970er Jahre auf Sprachen wie CLU und Ada bestanden, und wurden nachher durch viele Gegenstand-basierte und objektorientierte Sprachen, einschließlich des BETAS, C ++, D, Eiffel, Java, und DEZ jetzt verstorbene Sprache der Gitterwerk-Eule angenommen. Durchführungen von generics auf Sprachen wie Java und C# basieren formell auf dem Begriff von parametricity wegen John C. Reynolds.

Genericity wird durchgeführt und verschieden auf verschiedenen Programmiersprachen unterstützt; der Begriff "allgemeiner" ist auch verschieden in verschiedenen Programmierzusammenhängen gebraucht worden. Zum Beispiel, in Hervor dem Bearbeiter kann Code durchführen, während man kompiliert, und man kann neue Bearbeiter-Schlüsselwörter und neue Durchführungen für jene Wörter im Fluge schaffen. Es hat wenige Wörter, die das Bearbeiter-Verhalten ausstellen und deshalb natürlich genericity Kapazitäten anbietet, die jedoch solchen in am meisten Hervor Texten nicht genannt werden. Der Begriff ist in der funktionellen Programmierung spezifisch auf Haskell ähnlichen Sprachen gebraucht worden, die ein Strukturtyp-System verwenden, wo Typen immer parametrisch sind und der wirkliche Code auf jenen Typen allgemein ist. Dieser Gebrauch dient noch einem ähnlichen Zweck des Codesparens und der Übergabe einer Abstraktion.

Reihe und structs können als vorherbestimmte allgemeine Typen angesehen werden. Jeder Gebrauch einer Reihe oder struct Typs realisiert einen neuen konkreten Typ, oder verwendet einen vorherigen realisierten Typ wieder. Reihe-Element-Typen und struct Element-Typen sind parametrisierte Typen, die verwendet werden, um den entsprechenden allgemeinen Typ zu realisieren. All das ist gewöhnlich im Bearbeiter eingebaut, und die Syntax unterscheidet sich von anderen allgemeinen Konstruktionen.

Ein breiter Überblick über genericity Mechanismen auf Programmiersprachen folgt. Für einen spezifischen Überblick, der Eignung von Mechanismen für die allgemeine Programmierung vergleicht, sieh.

Auf objektorientierten Sprachen

Wenn

man Behälterklassen auf statisch getippten Sprachen schafft, ist es ungünstig, um spezifische Durchführungen für jeden datatype enthalten besonders schreiben zu müssen, wenn der Code für jeden datatype eigentlich identisch ist. Zum Beispiel, in C ++, kann diese Verdoppelung des Codes durch das Definieren einer Schablone-Klasse überlistet werden:

Schablone

Benotungsliste

{

/* Klasseninhalt */

};

Liste

Liste</Quelle>

Oben, ist ein Platzhalter für beliebigen Typ wird angegeben, wenn die Liste geschaffen wird. Diese "Behälter des Typs T" erlauben allgemein genannte Schablonen einer Klasse, mit verschiedenem datatypes so lange bestimmte Verträge wie Subtypen und Unterschrift wiederverwendet zu werden, werden behalten. Dieser genericity Mechanismus sollte mit der Einschließung polymorphism nicht verwirrt sein, der der algorithmische Gebrauch von austauschbaren Unterklassen ist: Zum Beispiel, eine Liste von Gegenständen des Typs, der Gegenstände des Typs enthält und. Schablonen können auch für mit dem Typ unabhängige Funktionen als im Beispiel unten verwendet werden:

Schablone

leerer Tausch (T & a, T & b)//"&" Pass-Rahmen durch die Verweisung

{\

T Zeitsekretärin = b;

b = a;

a = Zeitsekretärin;

}\

spannen Sie hallo = "Welt!", Welt = "Hallo";

Tausch (Welt, hallo);

cout

Der C ++ wird Konstruktion, die oben verwendet ist, als die Genericity-Konstruktion weit zitiert, die den Begriff unter Programmierern und Sprachentwerfern verbreitet hat und viele allgemeine Programmieridiome unterstützt. Die D Programmiersprache bietet auch völlig allgemein-fähige Schablonen an, die auf dem C ++ Präzedenzfall, aber mit einer vereinfachten Syntax gestützt sind. Die javanische Programmiersprache hat genericity Möglichkeiten zur Verfügung gestellt, die syntaktisch auf C ++ 's seit der Einführung von J2SE 5.0 gestützt sind.

C# 2.0 hat Chrom 1.5 und.NET Grundlegender Seh-2005 Konstruktionen, die die Unterstützung für die Generics-Gegenwart im Microsoft.NET Fachwerk seit der Version 2.0 ausnutzen.

Das dynamische Schreiben (solches, das im Ziel-C gezeigt wird) und vernünftiger Gebrauch von Protokollen überlistet das Bedürfnis nach dem Gebrauch von genericity Mechanismen, da dort ein allgemeiner Typ besteht, um jeden Gegenstand zu enthalten. Während Java also auch tut, bricht das Gussteil, das getan werden muss, die Disziplin des statischen Schreibens, und generics sind eine Weise, einige der Vorteile des dynamischen Schreibens mit den Vorteilen zu erreichen, das statische Schreiben zu haben.

Generics in Ada

Ada hat generics gehabt, seitdem er zuerst in 1977-1980 entworfen wurde. Die Standardbibliothek verwendet generics, um viele Dienstleistungen zur Verfügung zu stellen. Ada 2005 fügt eine umfassende allgemeine Behälterbibliothek zur Standardbibliothek hinzu, die durch C ++ 's Standardschablone-Bibliothek begeistert wurde.

Eine allgemeine Einheit ist ein Paket oder ein Unterprogramm, das einen oder mehr allgemeine formelle Rahmen nimmt.

Ein allgemeiner formeller Parameter ist ein Wert, eine Variable, eine Konstante, ein Typ, ein Unterprogramm oder sogar ein Beispiel von einem anderen, benannter, allgemeiner Einheit. Für allgemeine formelle Typen unterscheidet die Syntax zwischen dem getrennten, Schwimmpunkt, festen Punkt, Zugang (Zeigestock) Typen usw. Einige formelle Rahmen können Verzug-Werte haben.

Um eine allgemeine Einheit zu realisieren, passiert der Programmierer wirkliche Rahmen für jeden formell. Das allgemeine Beispiel benimmt sich dann gerade wie jede andere Einheit. Es ist möglich, allgemeine Einheiten an der Durchlaufzeit zum Beispiel innerhalb einer Schleife zu realisieren.

Beispiel

Die Spezifizierung eines allgemeinen Pakets:

allgemeiner

Max_Size: Natürlich; - ein allgemeiner formeller Wert

Typ Element_Type ist privat; - ein allgemeiner formeller Typ; akzeptiert jeden nichtbeschränkten Typ

Paket-Stapel sind

Typ Size_Type ist Reihe 0.. Max_Size;

Typ Stack wird privat beschränkt;

Verfahren Schafft (S: Stapel;

Initial_Size: in Size_Type: = Max_Size);

Verfahren Stoß (In: im Stapel; Element: in Element_Type);

Verfahren Pop (Von: im Stapel; Element: Element_Type);

Überschwemmung: Ausnahme;

Unterlauf: Ausnahme;

privater

Subtyp Index_Type ist Size_Type-Reihe 1.. Max_Size;

Typ Vector ist Reihe (Index_Type Reihe

Typ Stack (Allocated_Size: Size_Type: = ist 0) Rekord-

Spitze: Index_Type;

Lagerung: Vektor (1.. Allocated_Size);

Endaufzeichnung;

Endstapel;

</Quelle>

Das Realisieren des allgemeinen Pakets:

Typ Bookmark_Type ist Natürlich neu;

- registriert eine Position im Textdokument wir editieren

Paket Bookmark_Stacks ist neue Stapel (Max_Size => 20,

Element_Type => Bookmark_Type);

- Erlaubt dem Benutzer, zwischen registrierten Positionen in einem Dokument zu springen

</Quelle>

Das Verwenden eines Beispiels eines allgemeinen Pakets:

Typ Document_Type ist Rekord-

Inhalt:

Ada.Strings.Unbounded.Unbounded_String;

Lesezeichen: Bookmark_Stacks. Stapel;

Endaufzeichnung;

Verfahren Editiert (Document_Name: In der Schnur) ist

Dokument: Document_Type;

beginnen Sie

- Initialisieren Sie den Stapel von Lesezeichen:

Bookmark_Stacks. Schaffen Sie (S => Dokument. Lesezeichen, Initial_Size => 10);

- Öffnen Sie jetzt die Datei Document_Name und lesen Sie es darin...

Ende Editiert;

</Quelle>
Vorteile und Beschränkungen

Die Sprachsyntax erlaubt genaue Spezifizierung von Einschränkungen auf allgemeine formelle Rahmen. Zum Beispiel ist es möglich anzugeben, dass ein allgemeiner formeller Typ nur einen Modultyp als das wirkliche akzeptieren wird. Es ist auch möglich, Einschränkungen zwischen allgemeinen formellen Rahmen auszudrücken; zum Beispiel:

allgemeiner

Typ Index_Type ist (

Typ Element_Type ist privat; - kann jeder nichtbeschränkte Typ sein

Typ Array_Type ist Reihe (Index_Type Reihe

</Quelle>

In diesem Beispiel wird Array_Type sowohl durch Index_Type als auch durch Element_Type beschränkt. Wenn er die Einheit realisiert, muss der Programmierer einen wirklichen Reihe-Typ passieren, der diese Einschränkungen befriedigt.

Der Nachteil dieser feinkörnigen Kontrolle ist eine komplizierte Syntax, aber, weil alle allgemeinen formellen Rahmen in der Spezifizierung völlig definiert werden, kann der Bearbeiter generics realisieren, ohne auf den Körper des allgemeinen zu schauen.

Verschieden von C ++ erlaubt Ada spezialisierte allgemeine Beispiele nicht und verlangt, dass alle generics ausführlich realisiert werden. Diese Regeln haben mehrere Folgen:

  • der Bearbeiter kann geteilten generics durchführen: Der Gegenstand-Code für eine allgemeine Einheit kann zwischen allen Beispielen geteilt werden (wenn der Programmierer um inlining von Unterprogrammen, natürlich nicht bittet). Als weitere Folgen:
  • es gibt keine Möglichkeit des Codes bloat (codieren Sie bloat ist in C ++ üblich und verlangt spezielle Sorge, wie erklärt, unten).
  • es ist möglich, generics an der Durchlaufzeit, sowie während der Übersetzung zu realisieren, da kein neuer Gegenstand-Code für ein neues Beispiel erforderlich ist.
wie man
  • immer betrachtet, sind wirkliche Gegenstände entsprechend einem allgemeinen formellen Gegenstand innerhalb des allgemeinen nichtstatisch; sieh in Wikibook für Details und Folgen.
  • alle Beispiele eines allgemeinen Wesens genau dasselbe, es ist leichter, durch andere geschriebene Programme nachzuprüfen und zu verstehen; es gibt keine "speziellen Fälle", um in Betracht zu ziehen.
  • ausführlich ganz instantiations zu sein, gibt es nicht verborgenen instantiations, der es schwierig machen könnte, das Programm zu verstehen.
  • Ada erlaubt "Schablone metaprogramming" nicht, weil sie Spezialisierungen nicht erlaubt.

Schablonen in C ++

C ++ verwendet Schablonen, um allgemeine Programmiertechniken zu ermöglichen. Der C ++ schließt Standardbibliothek die Standardschablone-Bibliothek oder STL ein, der ein Fachwerk von Schablonen für allgemeine Datenstrukturen und Algorithmen zur Verfügung stellt. Schablonen in C ++ können auch für die Schablone metaprogramming verwendet werden, der eine Weise ist, etwas vom Code während der Übersetzung aber nicht der Durchlaufzeit zu vorbewerten. Mit der Schablone-Spezialisierung C ++ werden Schablonen als abgeschlossener Turing betrachtet.

Technische Übersicht

Es gibt zwei Arten von Schablonen: Funktionsschablonen und Klassenschablonen. Eine Funktionsschablone ist ein Muster, um gewöhnliche Funktionen zu schaffen, die auf den gelieferten wenn realisierten Parameterisieren-Typen gestützt sind. Zum Beispiel der C ++ enthält Standardschablone-Bibliothek die Funktionsschablone, die Funktionen schafft, die entweder x oder y zurückgeben, welch auch immer größer ist. konnte wie das definiert werden:

Schablone

T max (T x, T y)

{\

geben Sie x zurück

Spezialisierungen dieser Funktionsschablone, instantiations mit spezifischen Typen, können gerade wie eine gewöhnliche Funktion genannt werden:

cout

Der Bearbeiter untersucht die Argumente hat gepflegt zu rufen und beschließt, dass das ein Anruf ist. Es realisiert dann eine Version der Funktion, wo der Parameterisieren-Typ ist, die Entsprechung von der folgenden Funktion machend:

interne Nummer max (interne Nummer x, interne Nummer y)

{\ geben Sie x zurück

Das arbeitet, ob die Argumente und ganze Zahlen, Schnuren oder ein anderer Typ sind, für den der Ausdruck, oder mehr spezifisch für jeden Typ vernünftig ist, für den definiert wird. Allgemeines Erbe ist für den Satz von Typen nicht erforderlich, die verwendet werden können, und so ist es dem Ente-Schreiben sehr ähnlich. Ein Programm, das einen kundenspezifischen Datentyp definiert, kann Maschinenbediener verwenden, der überlädt, um die Bedeutung für diesen Typ so zu definieren, seinen Gebrauch mit der Funktionsschablone erlaubend. Während das ein geringer Vorteil in diesem isolierten Beispiel scheinen kann, im Zusammenhang einer umfassenden Bibliothek wie der STL erlaubt es dem Programmierer, umfassende Funktionalität für einen neuen Datentyp, gerade durch das Definieren einiger Maschinenbediener dafür zu bekommen. Bloß das Definieren erlaubt einem Typ, mit dem Standard, und den Algorithmen verwendet zu werden oder in Datenstrukturen wie s, Haufen und assoziative Reihe gestellt zu werden.

C ++ sind Schablonen völlig Typ sicher während der Übersetzung. Als eine Demonstration definiert der Standardtyp den Maschinenbediener nicht, weil es keine strenge Ordnung auf komplexen Zahlen gibt. Deshalb wird mit einem kompilieren Fehler scheitern, wenn x und y Werte sind. Ebenfalls können andere Schablonen, die sich darauf verlassen, nicht auf Daten angewandt werden, wenn ein Vergleich (in der Form eines functor oder Funktion) nicht zur Verfügung gestellt wird. Z.B: A kann als Schlüssel für nicht verwendet werden, wenn ein Vergleich nicht zur Verfügung gestellt wird. Leider erzeugen Bearbeiter historisch etwas esoterisch, lange, und unnützliche Fehlermeldungen für diese Sorte des Fehlers. Das Sicherstellen, dass ein bestimmter Gegenstand an einem Methode-Protokoll klebt, kann dieses Problem erleichtern. Sprachen, die statt verwenden, können auch Werte als Schlüssel verwenden.

Die zweite Art der Schablone, einer Klassenschablone, erweitert dasselbe Konzept zu Klassen. Eine Klassenschablone-Spezialisierung ist eine Klasse. Klassenschablonen werden häufig verwendet, um allgemeine Behälter zu machen. Zum Beispiel hat der STL einen verbundenen Listenbehälter. Um eine verbundene Liste von ganzen Zahlen zu machen, schreibt man. Eine Liste von Schnuren wird angezeigt. Ein Haben einer Reihe von Standardfunktionen hat damit verkehrt, die für irgendwelche vereinbaren Parameterisieren-Typen arbeiten.

Schablone-Spezialisierung

Eine starke Eigenschaft von C ++ 's Schablonen ist Schablone-Spezialisierung. Das erlaubt alternativen Durchführungen, gestützt auf bestimmten Eigenschaften des parametrisierten Typs zur Verfügung gestellt zu werden, der realisiert wird. Schablone-Spezialisierung hat zwei Zwecke: Bestimmte Formen der Optimierung zu erlauben, und Code bloat zu reduzieren.

Denken Sie zum Beispiel eine Schablone-Funktion. Eine der primären Tätigkeiten, die solch eine Funktion tut, ist, die Werte in zwei der Positionen des Behälters zu tauschen oder auszutauschen. Wenn die Werte groß sind (in Bezug auf die Zahl von Bytes, bringt sie, um jeden von ihnen zu versorgen), dann ist es häufig schneller, um zuerst eine getrennte Liste von Zeigestöcken zu den Gegenständen zu bauen, jene Zeigestöcke zu sortieren, und dann die sortierte Endfolge zu bauen. Wenn die Werte jedoch ziemlich klein sind, ist es gewöhnlich am schnellsten, um gerade die Werte, im Platz wie erforderlich, zu tauschen. Außerdem, wenn der parametrisierte Typ bereits eines Zeigestock-Typs ist, dann gibt es kein Bedürfnis, eine getrennte Zeigestock-Reihe zu bauen. Schablone-Spezialisierung erlaubt dem Schablone-Schöpfer, verschiedene Durchführungen zu schreiben und die Eigenschaften anzugeben, die der parametrisierte Typ (En) für jede zu verwendende Durchführung haben muss.

Verschieden von Funktionsschablonen können Klassenschablonen teilweise spezialisiert werden. Das bedeutet, dass eine abwechselnde Version des Klassenschablone-Codes zur Verfügung gestellt werden kann, wenn einige der Schablone-Rahmen bekannt sind, während man andere Schablone-Rahmen allgemein verlässt. Das kann zum Beispiel verwendet werden, um eine Verzug-Durchführung zu schaffen (die primäre Spezialisierung), der annimmt, dass das Kopieren eines Parameterisieren-Typs teuer ist und dann schaffen Sie teilweise Spezialisierungen für Typen, die preiswert sind, um zu kopieren, so gesamte Leistungsfähigkeit vergrößernd. Kunden solch einer Klassenschablone verwenden gerade Spezialisierungen davon ohne wissen zu müssen, ob der Bearbeiter die primäre Spezialisierung oder eine teilweise Spezialisierung in jedem Fall verwendet hat. Klassenschablonen können auch völlig spezialisiert werden, was bedeutet, dass eine abwechselnde Durchführung zur Verfügung gestellt werden kann, wenn alle Parameterisieren-Typen bekannt sind.

Vorteile und Nachteile

Etwas Gebrauch von Schablonen, wie die Funktion, wurde vorher durch funktionsähnliche Vorverarbeiter-Makros (ein Vermächtnis der C Programmiersprache) gefüllt. Zum Beispiel ist hier ein mögliches Makro:

  1. definieren Sie max (a, b) ((a)

Sowohl Makros als auch Schablonen werden während der Übersetzung ausgebreitet. Makros werden immer Reihen-ausgebreitet; Schablonen können auch als Reihenfunktionen ausgebreitet werden, wenn der Bearbeiter es für passend hält. So haben sowohl funktionsähnliche Makros als auch Funktionsschablonen keine Durchlaufzeit oben.

Jedoch werden Schablonen allgemein als eine Verbesserung über Makros zu diesen Zwecken betrachtet. Schablonen sind vor dem Typ sicher. Schablonen vermeiden einige der allgemeinen Fehler, die im Code gefunden sind, der schweren Gebrauch von funktionsähnlichen Makros, wie das Auswerten von Rahmen mit Nebenwirkungen zweimal macht. Vielleicht am wichtigsten wurden Schablonen entworfen, um auf viel größere Probleme anwendbar zu sein, als Makros.

Es gibt drei primäre Nachteile zum Gebrauch von Schablonen: Bearbeiter-Unterstützung, schlechte Fehlermeldungen und Code bloat.

Viele Bearbeiter haben historisch schlechte Unterstützung für Schablonen, so kann der Gebrauch von Schablonen Code etwas weniger tragbar machen. Unterstützung kann auch schwach sein, wenn ein C ++ Bearbeiter mit einem linker verwendet wird, der nicht C ++-aware ist, oder wenn er versucht, Schablonen über geteilte Bibliotheksgrenzen zu verwenden. Die meisten modernen Bearbeiter haben jedoch jetzt ziemlich robuste und normale Schablone-Unterstützung und den neuen C ++, wie man erwartet, richtet Standard, C ++ 0x, weiter diese Probleme.

Fast alle Bearbeiter erzeugen verwirrend, lange, oder manchmal unnützliche Fehlermeldungen, wenn Fehler im Code entdeckt werden, der Schablonen verwendet. Das kann Schablonen schwierig machen sich zu entwickeln.

Schließlich verlangt der Gebrauch von Schablonen, dass der Bearbeiter ein getrenntes Beispiel der templated Klasse oder Funktion für jede Versetzung von damit verwendeten Typ-Rahmen erzeugt. (Das ist notwendig, weil Typen in C ++ Größe nicht alle gleich sind, und die Größen von Datenfeldern dafür wichtig sind, wie Klassen arbeiten.), So kann der unterschiedslose Gebrauch von Schablonen führen, um bloat zu codieren, auf übermäßig großen executables hinauslaufend. Jedoch kann der vernünftige Gebrauch der Schablone-Spezialisierung solchen Code bloat in einigen Fällen drastisch reduzieren. Der zusätzliche durch Schablonen erzeugte instantiations kann auch Testhilfeprogramme veranlassen, Schwierigkeit zu haben, anmutig mit Schablonen arbeitend. Zum Beispiel kann das Setzen eines Fehlersuchprogramm-Unterbrechungspunkts innerhalb einer Schablone von einer Quelldatei entweder es vermissen, den Unterbrechungspunkt im wirklichen instantiation gewünscht zu setzen, oder kann einen Unterbrechungspunkt in jedem Platz setzen die Schablone wird realisiert.

Außerdem, weil der Bearbeiter makroähnliche Vergrößerungen von Schablonen durchführen und verschiedene Beispiele von ihnen während der Übersetzung erzeugen muss, muss der Durchführungsquellcode für die templated Klasse oder Funktion (z.B eingeschlossen in einen Kopfball) zum Code damit verfügbar sein. Klassen von Templated oder Funktionen, einschließlich viel von Standard Template Library (STL), können nicht kompiliert werden. (Das ist im Gegensatz zum Non-Templated-Code, der zum binären, zur Verfügung stellenden nur eine Behauptungskopfball-Datei für den Code damit kompiliert werden kann.) Kann das ein Nachteil durch das Herausstellen des Einführen-Codes sein, der einige Abstraktionen entfernt, und seinen Gebrauch in Projekten der geschlossenen Quelle einschränken konnte.

Genericity in Eiffel

Allgemeine Klassen sind ein Teil von Eiffel seit der ursprünglichen Methode und dem Sprachdesign gewesen. Die Fundament-Veröffentlichungen von Eiffel, gebrauchen Sie den Begriff genericity, um die Entwicklung und den Gebrauch von allgemeinen Klassen zu beschreiben.

Grundlegender/zwangloser genericity

Allgemeine Klassen werden mit ihrem Klassennamen und einer Liste von einer oder mehr formellen allgemeinen Rahmen erklärt. Im folgenden Code hat Klasse einen formellen allgemeinen Parameter

Klasse

LISTE [G]

...

Eigenschaft - Zugang

Artikel: G

- Der Artikel hat zurzeit zu durch den Cursor hingewiesen

...

Eigenschaft - Element-Änderung

gestellt (new_item: G)

- Fügen Sie `new_item' am Ende der Liste hinzu

...</Quelle>

Die formellen allgemeinen Rahmen sind Platzhalter für willkürliche Klassennamen, die geliefert werden, wenn eine Behauptung der allgemeinen Klasse, wie gezeigt, in den zwei allgemeinen Abstammungen unten gemacht wird, wo und andere Klassennamen sind. und werden als wirkliche allgemeine Rahmen betrachtet, weil sie echte Klassennamen zur Verfügung stellen, um im wirklichen Gebrauch zu vertreten.

list_of_accounts: LISTE [RECHNUNG]

- Kontoliste

list_of_deposits: LISTE [ABLAGERUNG]

- Ablagerungsliste

</Quelle>

Innerhalb des Typ-Systems Eiffel, obwohl Klasse als eine Klasse betrachtet wird, wird es als kein Typ betrachtet. Jedoch, eine allgemeine Abstammung von solche, die als ein Typ betrachtet wird.

Beschränkter genericity

Für die Listenklasse, die oben gezeigt ist, kann ein wirklicher allgemeiner Parameter, der das vertritt, jede andere verfügbare Klasse sein. Um den Satz von Klassen zu beschränken, aus denen gültige wirkliche allgemeine Rahmen gewählt werden können, kann eine allgemeine Einschränkung angegeben werden. In der Behauptung der Klasse unten diktiert die allgemeine Einschränkung, dass jeder gültige wirkliche allgemeine Parameter eine Klasse sein wird, die von der Klasse erbt. Die allgemeine Einschränkung stellt sicher, dass Elemente einer Dose tatsächlich sortiert werden.

Klasse

SORTED_LIST [G-> VERGLEICHBAR]

</Quelle>

Generics in Java

Unterstützung für den generics, oder "Behälter des Typs T" wurden zur javanischen Programmiersprache 2004 als ein Teil von J2SE 5.0 hinzugefügt. In Java werden generics während der Übersetzung für die Typ-Genauigkeit überprüft. Die allgemeine Typ-Information wird dann über einen Prozess genannt Typ-Ausradierung entfernt, und ist an der Durchlaufzeit nicht verfügbar. Zum Beispiel, umgewandelt zum rohen Typ zu sein. Der Bearbeiter fügt Typ-Würfe ein, um die Elemente zum Typ umzuwandeln, wenn sie von der Liste wiederbekommen werden.

Genericity in.NET

Generics wurden als ein Teil des.NET Fachwerks 2.0 im November 2005, gestützt auf einem Forschungsprototyp von 1999 angefangenem Microsoft Research hinzugefügt. Obwohl ähnlich, generics in Java.NET wenden generics Typ-Ausradierung nicht an, aber führen generics als ein Mechanismus der ersten Klasse in der Durchlaufzeit mit reification durch. Diese Designwahl stellt zusätzliche Funktionalität, wie das Erlauben des Nachdenkens mit der Bewahrung von allgemeinen Typen, sowie dem Vermindern von einigen der Beschränkungen der Ausradierung (solcher als unfähig seiend zur Verfügung, allgemeine Reihe zu schaffen). Das bedeutet auch, dass es keinen Leistungserfolg von Laufzeitwürfen und normalerweise teuren boxenden Konvertierungen gibt. Wenn primitiv und Werttypen als allgemeine Argumente verwendet werden, bekommen sie Spezialdurchführungen, effiziente allgemeine Sammlungen und Methoden berücksichtigend. Als in C ++ und Java, verschachtelte allgemeine Typen wie Wörterbuch

.NET erlaubt sechs Varianten von allgemeinen Typ-Einschränkungen mit dem Schlüsselwort einschließlich des Einschränkens allgemeiner Typen, um Werttypen zu sein, Klassen zu sein, Konstrukteure zu haben, und von Schnittstellen zu erben. Unten ist ein Beispiel mit einer Schnittstelle-Einschränkung:

das Verwenden des Systems;

Klassenprobe {\

statische leere Hauptsache {\

interne Nummer [] ordnet = {0, 1, 2, 3};

MakeAtLeast

foreach (interne Nummer i in der Reihe)

Konsole. WriteLine (i);//Druckergebnisse.

Konsole. (Wahrer) ReadKey;

}\

statischer leerer MakeAtLeast

für (interne Nummer i = 0; ich

Die Methode erlaubt Operation auf der Reihe mit Elementen des allgemeinen Typs. Die Typ-Einschränkung der Methode zeigt an, dass die Methode auf jeden Typ anwendbar ist, der die allgemeine Schnittstelle durchführt. Das sichert einen Übersetzungszeit-Fehler, wenn die Methode genannt wird, wenn der Typ Vergleich nicht unterstützt. Die Schnittstelle stellt die allgemeine Methode zur Verfügung.

Die obengenannte Methode konnte auch ohne allgemeine Typen einfach mit dem spezifischen Typ geschrieben werden. Jedoch, da Reihe Kontravariante ist, würde das Gussteil nicht Typ sicher sein, und Bearbeiter kann Fehler verpassen, die sonst gefangen würden, während man von den allgemeinen Typen Gebrauch macht. Außerdem würde die Methode auf die Reihe-Sachen als Gegenstände statt dessen zugreifen müssen und würde verlangen, dass Gussteil zwei Elemente vergleicht. (Weil Werttypen wie Typen wie das eine boxende Konvertierung verlangen, obwohl das um das Verwenden der Klasse gearbeitet werden kann, wie in den Standardsammlungsklassen getan wird.)

Ein bemerkenswertes Verhalten von statischen Mitgliedern in einer allgemeinen.NET Klasse ist statisches Mitglied instantiation pro Laufzeittyp (sieh Beispiel unten).

//Eine allgemeine Klasse

öffentliche Klasse GenTest

{\

//Eine statische Variable - wird für jeden Typ auf der Brechung geschaffen

statischer CountedInstances OnePerType = neuer CountedInstances ;

//ein Datenmitglied

privater T mT;

//einfacher Konstrukteur

öffentlicher GenTest (T pT)

{\

mT = pT;

}\

}\

//eine Klasse

öffentliche Klasse CountedInstances

{\

//Statische Variable - das wird einmal pro Beispiel erhöht

öffentlicher statischer int Schalter;

//einfacher Konstrukteur

öffentlicher CountedInstances

{\

//vergrößern Sie Schalter durch einen während des Gegenstands instantiation

CountedInstances. Schalter ++;

}\ }\

//Hauptcodezugang spitzt an

//am Ende der Ausführung, CountedInstances. Schalter = 2

GenTest

GenTest GenTest GenTest</Quelle>

Genericity in Delphi

Der Dialekt von Object Pascal von Delphi hat generics in der 2007-Ausgabe von Delphi, am Anfang nur mit (jetzt unterbrochen).NET Bearbeiter erworben, vor zum Eingeborenen hinzugefügt zu werden, ein in der 2009-Ausgabe von Delphi codiert. Die Semantik und Fähigkeiten zu Delphi generics werden auf denjenigen größtenteils modelliert hatte durch generics in.NET 2.0, obwohl die Durchführung notwendigerweise ziemlich verschieden ist. Hier ist eine mehr oder weniger direkte Übersetzung des ersten C# Beispiel, das oben gezeigt ist:

Programm Probe;

{TRÖSTEN $APPTYPE }\

Gebrauch

Generics. Verzug;//für IComparer

Typ

TUtils = Klasse

Klassenverfahren MakeAtLeast

Comparer: IComparer

Klassenverfahren MakeAtLeast

Ende;

Klassenverfahren TUtils. MakeAtLeast

Comparer: IComparer

var

I: Ganze Zahl;

beginnen Sie

wenn Comparer = Null dann Comparer: = TComparer

weil ich: = Niedrig (Arr) zum Hohen (Arr) tun

wenn Comparer. Vergleichen Sie sich (Arr [ich], am Niedrigsten)

beginnen Sie

MakeAtLeast

Ende;

var

Ints: TArray

Wert: Ganze Zahl;

beginnen Sie

Ints: = TArray

TUtils. MakeAtLeast

weil der Wert in Ints tut

WriteLn (Wert);

ReadLn;

Ende.

</Quelle>

Als mit C# können Methoden sowie ganze Typen einen oder mehr Typ-Rahmen haben. Im Beispiel ist TArray ein allgemeiner Typ (definiert durch die Sprache) und MakeAtLeast eine allgemeine Methode. Die verfügbaren Einschränkungen sind den verfügbaren Einschränkungen in C# sehr ähnlich: jeder Werttyp, jede Klasse, eine spezifische Klasse oder Schnittstelle und eine Klasse mit einem parameterless Konstrukteur. Vielfache Einschränkungen handeln als eine zusätzliche Vereinigung.

Genericity in freiem Pascal

Freies Pascal hat generics vor Delphi, und mit der verschiedenen Syntax und Semantik durchgeführt. Jedoch ist Arbeit jetzt laufend, um Delphi generics neben heimischen FPC durchzuführen (sieh FPC Wiki). Das erlaubt Freien Programmierern von Pascal, generics in beliebigem Stil zu verwenden, den sie bevorzugen.

Delphi und Beispiel von Free Pascal:

//Stil von Delphi

Einheit A;

{$ifdef fpc }\

{$mode delphi }\

{$endif }\

Schnittstelle

Typ

TGenericClass

fungieren Sie Doppelt (const AValue: T): T;

Ende;

Durchführung

Funktion TGenericClass

beginnen Sie

Ergebnis: = AValue + AValue;

Ende;Ende.

//Der Stil von ObjFPC des freien Pascal

Einheit B;

{$ifdef fpc }\

{$mode objfpc }\

{$endif }\SchnittstelleTyp

allgemeiner TGenericClass

fungieren Sie Doppelt (const AValue: T): T; Ende;Durchführung

Funktion TGenericClass. Doppelt (const AValue: T): T;

beginnen Sie Ergebnis: = AValue + AValue;Ende;Ende.

//Beispiel-Gebrauch, Stil von Delphi

Programm TestGenDelphi;

{$ifdef fpc }\ {$mode delphi }\{$endif }\Gebrauch

A, B;

var

GC1: A.TGenericClass

GC2: B.TGenericClass

beginnen Sie

GC1: = A.TGenericClass

GC2: = B.TGenericClass

WriteLn (GC1. Doppelt (100));//200

WriteLn (GC2. Doppelt ('hallo'));//hellohello

GC1. Frei;

GC2. Frei;

Ende.

//Beispiel-Gebrauch, Stil von ObjFPC

Programm TestGenDelphi;{$ifdef fpc }\ {$mode objfpc }\{$endif }\Gebrauch A, B;

//erforderlich in ObjFPC

Typ

TAGenericClassInt = spezialisieren A.TGenericClass

TBGenericClassString = spezialisieren B.TGenericClass

var

GC1: TAGenericClassInt;

GC2: TBGenericClassString;

beginnen Sie

GC1: = TAGenericClassInt. Schaffen Sie;

GC2: = TBGenericClassString. Schaffen Sie;

WriteLn (GC1. Doppelt (100));//200 WriteLn (GC2. Doppelt ('hallo'));//hellohello GC1. Frei; GC2. Frei;Ende.</Quelle>

Funktionelle Sprachen

Genericity in Haskell

Der Typ-Klassenmechanismus von Haskell unterstützt allgemeine Programmierung.

Sechs der vorherbestimmten Typ-Klassen in Haskell (einschließlich, die Typen, die für die Gleichheit verglichen werden können, und, die Typen, deren Werte als Schnuren gemacht werden können) haben das spezielle Eigentum, abgeleitete Beispiele zu unterstützen. Das bedeutet, dass ein Programmierer, der einen neuen Typ definiert, feststellen kann, dass dieser Typ ein Beispiel von einer dieser speziellen Typ-Klassen sein soll, ohne Durchführungen der Klassenmethoden zur Verfügung zu stellen, wie gewöhnlich notwendig ist, wenn man Klassenbeispiele erklärt. Alle notwendigen Methoden werden "abgeleitet" - d. h. automatisch - gestützt auf der Struktur des Typs gebaut.

Zum Beispiel stellt die folgende Behauptung eines Typs von binären Bäumen fest, dass es ein Beispiel der Klassen sein soll und:

Daten BinTree = Blättern | Knoten (BinTree a) (BinTree) Durch

das Abstammen (Eq, Show)

</Quelle>

Das läuft auf eine Gleichheitsfunktion und eine Schnur-Darstellungsfunktion hinaus, für jeden Typ der Form automatisch definiert werden vorausgesetzt, dass selbst jene Operationen unterstützt.

Die Unterstützung für abgeleitete Beispiele dessen und macht ihre Methoden und allgemein auf eine qualitativ verschiedene Weise von parametrisch polymorphen Funktionen: Diese "Funktionen" (genauer, mit dem Typ mit einem Inhaltsverzeichnis versehene Familien von Funktionen) können auf Werte verschiedener Typen angewandt werden, und obwohl sie sich verschieden für jeden Argument-Typ benehmen, ist wenig Arbeit erforderlich, um Unterstützung für einen neuen Typ hinzuzufügen. Ralf Hinze (2004) hat gezeigt, dass eine ähnliche Wirkung für benutzerbestimmte Typ-Klassen durch bestimmte Programmiertechniken erreicht werden kann. Andere Forscher haben Annäherungen daran und andere Arten von genericity im Zusammenhang von Haskell und Erweiterungen auf Haskell (besprochen unten) vorgeschlagen.

PolyP

PolyP war die erste allgemeine Programmiersprache-Erweiterung auf Haskell. In PolyP werden allgemeine Funktionen polytypic genannt. Die Sprache führt eine spezielle Konstruktion ein, in der solche Polytypic-Funktionen über die Strukturinduktion über die Struktur des Musters functor eines regelmäßigen datatype definiert werden können. Regelmäßige datatypes in PolyP sind eine Teilmenge von Haskell datatypes. Ein regelmäßiger datatype t muss der Art *  * sein, und wenn des formellen Typ-Arguments in der Definition zu sein, dann müssen alle rekursiven Anrufe t die Form t a haben. Diese Beschränkungen schließen höher-kinded datatypes aus sowie haben datatypes verschachtelt, wo die rekursiven Anrufe einer verschiedenen Form sind.

Die glatt machen Funktion in PolyP wird hier als ein Beispiel zur Verfügung gestellt:

werden Sie flach:: Regelmäßiger d => d-> [ein]

werden Sie = cata fl flach

polytypic fl:: f-> [ein]

Fall f

g+h-> irgendein fl fl

g*h-> \(x, y)-> fl x ++ fl y

-> \x-> []

Durchschnitt-> \x-> [x]

Rec-> \x-> x

d@g-> werden concat. flach. pmap fl

Betrügerischer t-> \x-> []

cata:: Regelmäßiger d => (FunctorOf d ein b-> b)-> d-> b

</Quelle>
Allgemeiner Haskell

Allgemeiner Haskell ist eine andere Erweiterung auf Haskell, der an der Utrechter Universität in den Niederlanden entwickelt ist. Die Erweiterungen, die es zur Verfügung stellt, sind:

  • Mit dem Typ mit einem Inhaltsverzeichnis versehene Werte werden als ein Wert definiert, der über die verschiedenen Typ-Konstrukteure von Haskell (Einheit, primitive Typen, Summen, Produkte und benutzerbestimmte Typ-Konstrukteure) mit einem Inhaltsverzeichnis versehen ist. Außerdem können wir auch das Verhalten mit dem Typ mit einem Inhaltsverzeichnis versehene Werte für einen spezifischen Konstrukteur angeben, der Konstrukteur-Fälle verwendet, und eine allgemeine Definition in einem anderen Verwenden-Verzug Fälle wiederverwenden.

Der resultierende mit dem Typ mit einem Inhaltsverzeichnis versehene Wert kann zu jedem Typ spezialisiert werden.

  • Mit der Art mit einem Inhaltsverzeichnis versehene Typen sind Typen, die über Arten mit einem Inhaltsverzeichnis versehen sind, die durch das Geben eines Falls sowohl für * als auch für k  k definiert sind'. Beispiele werden durch die Verwendung des mit der Art mit einem Inhaltsverzeichnis versehenen Typs auf eine Art erhalten.
  • Allgemeine Definitionen können durch die Verwendung von ihnen auf einen Typ oder Art verwendet werden. Das wird allgemeine Anwendung genannt. Das Ergebnis ist ein Typ oder Wert, abhängig von dem die Sorte der allgemeinen Definition angewandt wird.
  • Allgemeine Abstraktion ermöglicht allgemeinen zu definierenden Definitionen durch das Entziehen eines Typ-Parameters (von einer gegebenen Art).
  • Mit dem Typ mit einem Inhaltsverzeichnis versehene Typen sind Typen, die über die Typ-Konstrukteure mit einem Inhaltsverzeichnis versehen werden. Diese können verwendet werden, um Typen beteiligteren allgemeinen Werten zu geben. Die resultierenden mit dem Typ mit einem Inhaltsverzeichnis versehenen Typen können zu jedem Typ spezialisiert werden.

Als ein Beispiel, die Gleichheitsfunktion in Allgemeinem Haskell:

Typ Eq {[*]} t1 t2 = t1-> t2-> Bool

Typ Eq {[k-> l]} t1 t2 = forall u1 u2. Eq {[k]} u1 u2-> Eq {[l]} (t1 u1) (t2 u2)

eq:: Eq {[k]} t t

eq _ _ = Wahrer

eq eqA eqB (Inl a1) (Inl a2) = eqA a1 a2

eq eqA eqB (Inr b1) (Inr b2) = eqB b1 b2

eq eqA eqB _ _ = Falscher

eq eqA eqB (a1:*: b1) (a2:*: b2) = eqA a1 a2 && eqB b1 b2

eq = (==)

eq = (==) eq = (==)</Quelle>

Sauber

Saubere Angebote allgemeine Programmierung haben PolyP und den allgemeinen Haskell, wie unterstützt, durch den GHC> =6.0 gestützt. Es parametrisiert durch die Art als diejenigen, aber Angebot-Überbelastung.

Andere Sprachen

Die ML Familie von Programmiersprachen unterstützt allgemeine Programmierung durch parametrischen polymorphism, und allgemeine Module haben functors genannt.

Sowohl Normaler ML als auch OCaml stellen functors zur Verfügung, die Klassenschablonen und den allgemeinen Paketen von Ada ähnlich sind. Schema syntaktische Abstraktionen haben auch eine Verbindung zu genericity - ist das tatsächlich eine Obermenge von templating à la C ++.

Siehe auch

Referenzen

Weiterführende Literatur

Links

C ++/D

  • Walter klug, wieder besuchte Schablonen.
  • David Vandevoorde, Nicolai M Josuttis, C ++ Schablonen: Der Ganze Führer, 2003 Addison-Wesley. Internationale Standardbuchnummer 0-201-73484-2

C#/.NET

C#.

Delphi/Object Pascal

Eiffel

Haskell

Java

  • Gilad Bracha, Generics auf der javanischen Programmiersprache, 2004.
  • Maurice Naftalin und Philip Wadler, Java Generics und Sammlungen, 2006, Internationale Standardbuchnummer von O'Reilly Media, Inc 0-596-52775-6
  • Peter Sestoft, Java Genau, die Zweite Ausgabe, Presse der 20:05 Uhr MIT. Internationale Standardbuchnummer 0-262-69325-9
Sun Microsystems,

Druck von Oncotic / Nigel Tranter
Impressum & Datenschutz