Generisk programmering

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 20 juli 2022; verifiering kräver 1 redigering .

Generisk programmering är ett  programmeringsparadigm som består av en sådan beskrivning av data och algoritmer som kan appliceras på olika typer av data utan att ändra själva beskrivningen. I en eller annan form stöds den av olika programmeringsspråk . Generiska programmeringsmöjligheter dök först upp i form av generika (generiska funktioner) på 1970 -talet i Clu- och Ada -språken , sedan som parametrisk polymorfism i ML och dess ättlingar, och sedan i många objektorienterade språk som C++ , Python [ 1] , Java , Object Pascal [2] , D , Eiffel , språk för .NET- plattformen och andra.

Generisk programmeringsmetodik

Generisk programmering betraktas som en programmeringsmetodik baserad på separation av datastrukturer och algoritmer genom användning av abstrakta kravbeskrivningar [3] . Abstrakta kravdeklarationer är en förlängning av konceptet med en abstrakt datatyp . Istället för att beskriva en enda typ i generisk programmering används en beskrivning av en familj av typer som har ett gemensamt gränssnitt och semantiskt beteende .  En uppsättning krav som beskriver ett gränssnitt och semantiskt beteende kallas ett koncept . Således kan en algoritm skriven i en generaliserad stil appliceras på vilken typ som helst som tillfredsställer den med dess koncept. Denna möjlighet kallas polymorfism .  

En typ sägs modellera ett koncept (är en modell av ett koncept) om den uppfyller dess krav. Ett koncept är en förfining av ett annat koncept om det kompletterar det senare. Konceptkraven innehåller följande information: [4]

I C++ implementeras OOP genom virtuella funktioner och arv, medan OP (generisk programmering) implementeras genom klass- och funktionsmallar. Kärnan i båda metoderna är dock endast indirekt relaterad till specifika implementeringstekniker. Mer formellt är OOP baserad på subtyp polymorfism , medan OP är baserad på parametrisk polymorfism . På andra språk kan båda implementeras på olika sätt. Till exempel har multimetoder i CLOS semantik som liknar parametrisk polymorfism.

Masser och Stepanov särskiljer följande steg för att lösa problemet enligt OP-metoden:

  1. Hitta en användbar och effektiv algoritm.
  2. Definiera en generaliserad representation (parametrisera algoritmen, minimera kraven för data som bearbetas).
  3. Beskriv en uppsättning (minimi)krav som fortfarande kan ge effektiva algoritmer.
  4. Skapa en wireframe baserad på klassificerade krav.

Minimering och inramning syftar till att skapa en struktur så att algoritmerna är oberoende av specifika datatyper. Detta tillvägagångssätt återspeglas i strukturen för STL - biblioteket . [5]

Ett alternativt tillvägagångssätt för att definiera generisk programmering, som kan kallas generisk programmering av datatyp , föreslogs av Richard Bird och Lambert Meertens .  I den är datatypstrukturer parametrar för generiska program. För att göra detta introduceras en ny abstraktionsnivå i programmeringsspråket, nämligen parametrisering med avseende på klasser av algebror med en variabel signatur . Även om teorierna för båda tillvägagångssätten är oberoende av programmeringsspråket, har Musser-Stepanovs synsätt, som betonar konceptanalys, gjort C++ till sin huvudplattform, medan generisk datatypsprogrammering nästan uteslutande används av Haskell och dess varianter [6] .

Allmän mekanism

Generiska programmeringsverktyg är implementerade i programmeringsspråk i form av vissa syntaktiska medel som gör det möjligt att beskriva data (datatyper) och algoritmer (procedurer, funktioner, metoder) parametriserade av datatyper. För en funktion eller datatyp beskrivs formella typparametrar uttryckligen . Denna beskrivning är generaliserad och kan inte användas direkt i sin ursprungliga form.

På de platser i programmet där en generisk typ eller funktion används måste programmeraren uttryckligen ange den faktiska typparametern som anger deklarationen. Till exempel kan en generisk procedur för att byta två värden ha en typparameter som anger vilken typ av värden den byter. När programmeraren behöver byta två heltalsvärden anropar han proceduren med typparametern " heltal " och två parametrar - heltal, när två strängar - med typparametern " sträng " och två parametrar - strängar. När det gäller data kan en programmerare till exempel beskriva en generisk typ " lista " med en typparameter som anger vilken typ av värden som lagras i listan. Sedan, när man beskriver verkliga listor, måste programmeraren ange en generisk typ och en typparameter, och på så sätt erhålla vilken lista som helst med samma deklaration.

När en kompilator stöter på ett anrop till en generisk typ eller funktion, utför den de nödvändiga statiska typkontrollprocedurerna , utvärderar möjligheten för en given instansiering och, om den är positiv, genererar den kod som ersätter den faktiska typparametern i stället för den formella typparametern i den allmänna beskrivningen. För en framgångsrik användning av generiska beskrivningar måste naturligtvis de faktiska parametertyperna uppfylla vissa villkor. Om en generisk funktion jämför värden för en typparameter måste varje konkret typ som används i den stödja jämförelseoperationer, om den tilldelar värden av en typparameter till variabler måste den konkreta typen säkerställa korrekt tilldelning.

Generisk programmering på språk

C++

I C++ är generisk programmering baserad på konceptet med en "mall", betecknad med mallens nyckelord . Det används flitigt i C++ Standard Library (se STL ) såväl som tredjepartsbibliotek boost , Loki . Ett stort bidrag till framväxten av avancerade generiska programmeringsverktyg i C++ gjordes av Alexander Stepanov .

Som ett exempel, låt oss ge en mall (generalisering) av en funktion som returnerar det större värdet av två.

// Funktionsmall beskrivningsmall < typnamn T > T max ( T x , T y ) { om ( x < y ) returnera y ; annan returnera x ; } ... // Använder funktionen som ges av mallen int a = max ( 10 , 15 ); ... dubbel f ​​= max ( 123,11 , 123,12 ); ...

eller en mall (generalisering) av en länkad listklass:

mall < classT > _ klasslista _ { /* ... */ offentliga : void Lägg till ( const T & Element ); bool Hitta ( const T & Element ); /* ... */ };

Haskell

Haskell tillhandahåller generisk datatypsprogrammering. I följande exempel a , en parametertypvariabel.

datalista a = Noll | _ Nackdelar a ( Lista a ) längd :: Lista a -> Int längd Noll = 0 längd ( Nackdelar _ tl ) = 1 + längd tl

Räkneexempel:

längd ( Nackdelar 1 ( Nackdelar 2 Noll )) == 2

Java

Java har tillhandahållit generika som är syntaktisk baserade på C++ sedan J2SE 5.0. Detta språk har generika eller "behållare av typ T" - en delmängd av generisk programmering.

.NET

.NET- plattformen dök generiska programmeringsverktyg upp i version 2.0.

// Deklaration av en generisk klass. public class GenericList < T > { void Add ( T input ) { } } class TestGenericList { private class ExampleClass { } static void Main () { GenericList < int > list1 = new GenericList < int >(); GenericList < string > list2 = new GenericList < string >(); GenericList < ExampleClass > list3 = new GenericList < ExampleClass >(); } }

Exempel i C#

gränssnitt IPerson { string GetFirstName (); sträng GetLastName (); } class Speaker { public void SpeakTo < T > ( T person ) där T : IPerson { strängnamn = person . GetFirstName (); detta . säga ( "Hej," + namn ); } }

D

Ett exempel på rekursiv generering baserat på D- mallar :

// http://digitalmars.com/d/2.0/template.html mall Foo ( T , R ...) // T är en typ, R är en uppsättning typer { void Foo ( T t , R r ) { skrivln ( t ); statisk if ( r . längd ) // om fler argument Foo ( r ); // gör resten av argumenten } } void main () { Foo ( 1 , 'a' , 6.8 ); } /++++++++++++++++ utskrifter: 1 a 6,8 +++++++++++++++/

ObjectPascal

Stöd för generisk programmering av Free Pascal-kompilatorn har varit tillgängligt sedan version 2.2 2007 [7] . I Delphi  - sedan oktober 2008 . Kärnstödet för generiska klasser dök upp först i Delphi 2007 .NET 2006 , men det påverkade bara .NET Framework . Mer komplett stöd för generisk programmering har lagts till i Delphi 2009 . Generiska klasser stöds också i Object Pascal i PascalABC.NET- systemet .

Nim

importera typbilder proc getType [ T ] ( x : T ): sträng = returnera x . typ . namn echo getType ( 21 ) # kommer att skriva ut int echo getType ( 21.12 ) # kommer att skriva ut float64 echo getType ( "sträng" ) # kommer att skriva ut strängen

Anteckningar

  1. Python Generic . Hämtad 28 maj 2020. Arkiverad från originalet 9 februari 2021.
  2. I Delphi och PascalABC.NET
  3. Sik, Lee, Lumsdane, 2006 , sid. 39.
  4. Sik, Lee, Lumsdane, 2006 , sid. 47-48.
  5. Sik, Lee, Lumsdane, 2006 , sid. 40-45.
  6. Gabriel Dos Reis, Jaakko Järvi. Vad är generisk programmering?
  7. Freepascal Generics . Hämtad 1 februari 2011. Arkiverad från originalet 15 december 2010.

Länkar

Litteratur

  • Jeremy Sik, Lai Kwang Lee, Andrew Lumsdane. C++ Boost Graph Library. - Peter, 2006. - 304 sid. — ISBN 5-469-00352-3 .
  • Stepanov Alexander A., ​​Rose Daniel E. Från matematik till generisk programmering. - DMK Press, 2016. - 264 sid. - ISBN 978-5-97060-379-6 .