Geneerinen ohjelmointi on ohjelmointiparadigma , joka koostuu sellaisesta tietojen ja algoritmien kuvauksesta, jota voidaan soveltaa erityyppisiin tietoihin muuttamatta itse kuvausta. Yhdessä muodossa eri ohjelmointikielet tukevat sitä . Yleiset ohjelmointiominaisuudet ilmestyivät ensin geneeristen toimintojen muodossa 1970-luvulla Clu- ja Ada - kielissä , sitten parametrisena polymorfismina ML :ssä ja sen jälkeläisissä ja sitten monissa oliokielissä , kuten C++ , Python [ 1] , Java , Object Pascal [2] , D , Eiffel , .NET -alustan kielet ja muut.
Geneeristä ohjelmointia pidetään ohjelmointimetodologiana , joka perustuu tietorakenteiden ja algoritmien erottamiseen abstraktien vaatimuskuvausten avulla [3] . Abstraktien vaatimusten ilmoitukset ovat abstraktin tietotyypin käsitteen laajennus . Sen sijaan, että kuvattaisiin yhtä tyyppiä yleisessä ohjelmoinnissa, käytetään kuvausta tyyppiperheestä, jolla on yhteinen käyttöliittymä ja semanttinen käyttäytyminen . Joukkoa vaatimuksia, jotka kuvaavat käyttöliittymää ja semanttista käyttäytymistä , kutsutaan konseptiksi . Näin ollen yleistettyyn tyyliin kirjoitettua algoritmia voidaan soveltaa mihin tahansa tyyppiin, joka tyydyttää sen käsitteillään. Tätä mahdollisuutta kutsutaan polymorfismiksi .
Tyypin sanotaan mallintavan käsitettä (on konseptin malli), jos se täyttää sen vaatimukset. Käsite on toisen käsitteen jalostus , jos se täydentää jälkimmäistä. Konseptivaatimukset sisältävät seuraavat tiedot: [4]
C++ : ssa OOP toteutetaan virtuaalisten funktioiden ja periytymisen kautta, kun taas OP (generic programming) toteutetaan luokka- ja funktiomallipohjien kautta. Molempien menetelmien ydin liittyy kuitenkin vain epäsuorasti tiettyihin toteutusteknologioihin. Muodollisemmin OOP perustuu alatyypin polymorfismiin , kun taas OP perustuu parametriseen polymorfismiin . Muilla kielillä molemmat voidaan toteuttaa eri tavalla. Esimerkiksi CLOS :n monimenetelmien semantiikka on samanlainen kuin parametrinen polymorfismi.
Masser ja Stepanov erottavat seuraavat vaiheet ongelman ratkaisemisessa OP-metodologian mukaan:
Minimoinnilla ja kehystyksellä pyritään luomaan sellainen rakenne, että algoritmit ovat riippumattomia tietystä tietotyypeistä. Tämä lähestymistapa näkyy STL - kirjaston rakenteessa . [5]
Richard Bird ja Lambert Meertens ehdottivat vaihtoehtoista lähestymistapaa geneerisen ohjelmoinnin määrittelyyn, jota voidaan kutsua tietotyyppien geneeriseksi ohjelmoimiseksi . Siinä tietotyyppirakenteet ovat geneeristen ohjelmien parametreja. Tätä varten ohjelmointikieleen tuodaan uusi abstraktiotaso, nimittäin parametrisointi suhteessa muuttuvan allekirjoituksen omaaviin algebraluokkiin . Vaikka molempien lähestymistapojen teoriat ovat ohjelmointikielestä riippumattomia, konseptianalyysiä painottava Musser-Stepanov-lähestymistapa on tehnyt C++ :n pääalustakseen, kun taas geneeristä tietotyyppiohjelmointia käyttävät lähes yksinomaan Haskell ja sen muunnelmat [6] .
Yleiset ohjelmointityökalut toteutetaan ohjelmointikielissä tiettyjen syntaktisten keinojen muodossa, jotka mahdollistavat tietotyyppien mukaan parametroidun datan (tietotyypit) ja algoritmien (menettelyt, toiminnot, menetelmät) kuvaamisen. Funktiolle tai tietotyypille muodolliset tyypin parametrit on kuvattu eksplisiittisesti . Tämä kuvaus on yleistetty eikä sitä voi käyttää suoraan alkuperäisessä muodossaan.
Niissä ohjelman paikoissa, joissa käytetään yleistä tyyppiä tai funktiota, ohjelmoijan tulee erikseen määrittää varsinainen tyyppiparametri, joka määrittää ilmoituksen. Esimerkiksi yleisellä proseduurilla kahden arvon vaihtamiseksi voi olla tyyppiparametri, joka määrittää, minkä tyyppisiä arvoja se vaihtaa. Kun ohjelmoijan on vaihdettava kaksi kokonaislukuarvoa, hän kutsuu proseduuria tyyppiparametrilla " integer " ja kahdella parametrilla - kokonaisluvuilla, kun kaksi merkkijonoa - tyyppiparametrilla " string " ja kahdella parametrilla - merkkijonoilla. Tietojen tapauksessa ohjelmoija voi esimerkiksi kuvata yleisen tyypin " lista " tyyppiparametrilla, joka määrittää luetteloon tallennettujen arvojen tyypin. Sitten ohjelmoijan tulee todellisia listoja kuvaillessaan määrittää yleinen tyyppi ja tyyppiparametri, jolloin saadaan mikä tahansa haluttu lista käyttämällä samaa ilmoitusta.
Kun kääntäjä kohtaa kutsun yleiselle tyypille tai funktiolle, se suorittaa tarvittavat staattiset tyypin tarkistustoimenpiteet , arvioi tietyn ilmentymisen mahdollisuuden ja, jos se on positiivinen, generoi koodin, joka korvaa todellisen tyyppiparametrin muodollisen tyyppiparametrin tilalle. yleisessä kuvauksessa. Luonnollisesti yleisten kuvausten onnistunut käyttö edellyttää, että todellisten parametrityyppien on täytettävä tietyt ehdot. Jos geneerinen funktio vertaa tyyppiparametrin arvoja, minkä tahansa siinä käytetyn konkreettisen tyypin on tuettava vertailutoimintoja, jos se antaa muuttujille tyyppiparametrin arvoja, tulee konkreettisen tyypin varmistaa oikea määritys.
C++:ssa yleinen ohjelmointi perustuu "mallin" käsitteeseen, jota merkitään mallin avainsanalla . Sitä käytetään laajasti C++ -standardikirjastossa (katso STL ) sekä kolmansien osapuolien kirjastojen tehostuksessa , Loki . Alexander Stepanov antoi suuren panoksen kehittyneiden yleisten ohjelmointityökalujen syntymiseen C++:ssa .
Esimerkkinä annetaan malli (yleistys) funktiolle, joka palauttaa suuremman arvon kaksi.
// Toimintomallin kuvausmalli < tyypinnimi T > T max ( T x , T y ) { jos ( x < y ) paluu y ; muu paluu x ; } ... // Mallin antaman funktion käyttäminen int a = max ( 10 , 15 ); ... kaksinkertainen f = max ( 123,11 , 123,12 ); ...tai linkitetyn luetteloluokan malli (yleistys) :
malli < luokkaT > _ luokkaluettelo _ { /* ... */ julkinen : void Add ( const T & Element ); bool Etsi ( const T & Element ); /* ... */ };Haskell tarjoaa yleisen tietotyyppiohjelmoinnin. Seuraavassa esimerkissä a parametrityyppinen muuttuja.
datalista a = nolla | _ Miinukset a ( Lista a ) pituus :: Lista a -> Int pituus Nolla = 0 pituus ( Cons _ tl ) = 1 + pituus tlLaskuesimerkki:
pituus ( miinukset 1 ( miinukset 2 nolla )) == 2Java on tarjonnut syntaktisesti C++:aan perustuvia geneerejä J2SE 5.0:sta lähtien. Tällä kielellä on geneerisiä tai "tyyppisiä T-säiliöitä" - yleisen ohjelmoinnin osajoukkoa.
.NET - alustalla yleiset ohjelmointityökalut ilmestyivät versiossa 2.0.
// Yleisen luokan ilmoitus. public class GenericList < T > { void Add ( T input ) { } } class TestGenericList { yksityinen luokka EsimerkkiClass { } static void Main () { GenericList < int > list1 = new GenericList < int >(); GenericList < string > list2 = new GenericList < string >(); GenericList < EsimerkkiClass > list3 = new GenericList < Esimerkkiluokka >(); } }Esimerkki D -malleihin perustuvasta rekursiivisesta generoinnista :
// http://digitalmars.com/d/2.0/template.html template Foo ( T , R ...) // T on tyyppi, R on joukko tyyppejä { void Foo ( T t , R r ) { kirjoita ( t ); static if ( r . pituus ) // jos enemmän argumentteja Foo ( r ); // tee loput argumentit } } void main () { Foo ( 1 , 'a' , 6.8 ); } /++++++++++++++++ tulosteet : 1–6,8 +++++++++++++++++ /Free Pascal -kääntäjän yleisohjelmoinnin tuki on ollut saatavilla versiosta 2.2 lähtien vuonna 2007 [7] . Delphissä - lokakuusta 2008 lähtien . Yleisten luokkien ydintuki ilmestyi ensimmäisen kerran Delphi 2007 .NET :ssä vuonna 2006 , mutta se vaikutti vain .NET Frameworkiin . Delphi 2009 :ssä on lisätty kattavampi tuki yleiselle ohjelmointille . Yleisiä luokkia tuetaan myös PascalABC.NET - järjestelmän Object Pascalissa .