6.1. Generic eljárások
6.2. Paraméterezett adatabsztrakciók (Típuskonstrukció paraméterezése típussal)
A típussal való paraméterezhetőség nem a CLU-ban kapta a generic nevet (talán az ADA-ban), de a generic-et megvalósító nyelvek a CLU mintájára készültek.
A CLU kétféle módon támogatja a típussal való paraméterezhet?séget, egyrészt eljárások, másrészt típuskonstrukciók paramétereiként.
proc_name = proc ( nl : T1, ..., nk : Tk ) returns ( TTl, ..., TTl )A CLU-eljárások típussal is paraméterezhetők, a típusparaméter használata azonban eltér az objektum-paraméterek használatától. A típusparamétereket szögletes zárójelek között kell felsorolni közvetlenül a proc kulcsszó után:
generic_proc_name = proc [ t : type ] (...) returns (...)A típussal paraméterezett eljárások csak a fejlécben térnek el a típussal nem paraméterezett eljárásoktól. Az eljárások típussal paraméterezhetősége sok tekintetben hasonlít az adattípusoknál ismertetett tömbök és sorozatok használatára. Az array és a sequence tulajdonképpen nem más, mint típussal paraméterezett típuskonstrukciók. A típussal való paraméterezés esetén lehetséges, hogy bizonyos paramétereknek nincs értelme. Például a tömbök közül csak azok rendezhetők, amelyeknek az elemtípusán értelmezve van egy totális rendezés. Általános esetben a paramétertípusról bizonyos műveletek meglétét kell megkövetelni. Ezeket a szükséges műveleteket a fordítónak számon kell kérnie a példányosításkor használt aktuális típusparamétereknél. Ehhez a generic eljárás fejlécében deklarálni kell, hogy milyen műveletekkel kell rendelkeznie a paramétertípusnak. A kívánt műveleteket a where kulcsszó segítségével adhatjuk meg:
generic_proc_name = proc [ t : type ] (...) returns (...) where t has opl : proctype (...) returns (...) where t has op2 : proctype (...) returns (...) where t has opk : proctype (...) returns (...)Megadható típusok egy halmaza is, ekkor értelemszerűen csak a közös eljárások használhatók a generic eljáráson belül:
where t in type1, type2, ..., typek
A sort absztrakció paramétere egy t
típus, amelynek rendelkeznie kell egy lt művelettel (rövid alak: <),
ami totális rendezés t-n.
sort = proc [ t : type ] ( a : array[ t ] ) returns ( array[ t ]) where t has lt : proctype ( t, t ) returns ( bool )Hasonlóan a search absztrakció paramétere egy olyan t típus, amelynek rendelkeznie kell egy equal (rövid alak: =) és egy lt művelettel (rövid alak: <), ahol lt totális rendezés t-n.
search = proc [ t : type ] ( a : array[ t ], x : t ) returns ( int ) where t has lt, equal : proctype ( t, t ) returns ( bool )A paraméterezett modulon belül a paramétertípusnak csak a where-rel deklarált műveletei használhatók. Az így deklarált műveletek azonban csak szintaktikai konstrukciók, amelyek elegendőek a típusellenőrzéshez. A szemantikát a konkrét típus azonos nevű művelete adja.
A paraméterezett modul kódja hasonló a nem paraméterezett modul kódjához. Ha az általános kódból manuálisan meg szeretnénk kapni egy speciális p típusra alkalmas kódot, nem kell mást tenni, mint elhagyni a fejlécből a típus paramétert ( [ t . type ] ) a where-deklarációkkal együtt, majd a t minden előfordulását le kell cserélni p-re.
A megfelelő eljárást példányosítással kaphatjuk az általános változatból (pl. sort [ int ] , sort [ string ] , search [ int ] , search [ real ] , stb.) A generic eljárások minden olyan típusra tartalmaznak egy-egy példányt, amely rendelkezik a kívánt műveletekkel. Például a sort-nak minden olyan típusra van egy példánya, amelynek megvan az lt művelete. Az egész elemtípusú tömb rendezésére például a következő programrészletet használhatjuk:
a : array[int] sort[int](a)
Hasonlóan az eljáráshoz a generic típust sem lehet közvetlenül használni, előtte példányosítani kell (azaz megadni az aktuális típusparamétert):
int_set = set [ int ]Az int_set egy típus, a set egy generic típus, az int a bázis vagy generáló típus.
set = cluster [ t : type ] is create, insert, delete, is_empty, member, size, choose where t has equal : proctype ( t, t ) returns ( bool ) rep = array [ t ] create = proc () returns ( cvt ) return ( rep$new() ) end create insert = proc ( s : cvt, x : t ) if ~member( up( s ), x ) then rep$addh( s, x ) end %if end insert delete = proc ( s : cvt, x : t ) j : int := getind( s, x ) if j <= rep$high( s ) then s [ j ] := rep$top ( s ) rep$remh( s ) end %if end delete is_empty = proc ( s : cvt ) returns ( bool ) return ( rep$size( s ) = 0 ) end is_empty member = proc ( s : cvt, x : t) returns ( bool ) return ( getind( s, x ) <= rep$high( s ) ) end member size = proc ( s : cvt ) returns ( int ) return ( rep$size( s ) ) end size choose = proc ( s : cvt ) return ( t ) return ( rep$bottom( s ) ) end choose get_ind = proc ( s : rep, x : t ) returns ( int ) i : int : rep$low( s ) while ( i <= rep$high( s ) ) do if x = s [ i ] then return ( i ) end %if i := i + 1; end %while end get_ind end set