A CLU programozási nyelv

Beépített adattípusok és típuskonstrukciók



6. Generic, típussal való paraméterezés

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.

6.1 Generic eljárások

Láttuk, hogyan lehet objektumokat eljárások paramétereként átadni. Az eljárás fejlécének általános formája:
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)

6.2. Paraméterezett adatabsztrakciók

A clusterek típussal való paraméterezése teljesen hasonló módon történik az eljárások típussal való paraméterezéséhez. A típus paramétert itt is szögletes zárójelek közé kell tenni, s a where vagy in kulcsszó használatával írhatunk elő műveleteket a típusparaméterek számára. Ez a fogalom jól illeszkedik a megismert array és sequence típuskonstrukciók jelentéséhez. Ezek ugyanis speciális, típussal paraméterezett adatabsztrakciók.

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