A Nemerle programozási nyelv

Sablonok



Parametrikus polimorfizmus

A Nemerle támogatja a parametrikus polimorfizmust, vagyis a típussal való paraméterezést. Hasonlít a C# 2.0 és a Java 5.0 generikusaira, és kevéssé a C++ template-eire.

Metódusokat, osztályokat és a variant típust egyaránt lehet típussal paraméterezni. Szintaxisa mindegyik esetben azonos: a metódus vagy típus neve után szögletes zárójelben, vesszőkkel elválasztva felsoruljuk a típusváltozókat.

A következő példa egy azonos típusú elemekből álló lista definícióját mutatja be:

variant list[T] { | Cons { hd : T; tl : list [T]; } | Nil }

Itt T egy típusváltozó, mely a típusdefiníció törzsében ugyanúgy használható, mint bármely konkrét típusnév.

Generikus metódus vagy típus használatához szintén a szögletes zárójeles szintaxis követendő, de a név és a paraméterlista közé általában egy "." is írandó:

mutable xs : list.[int];

A típusparaméterek felsorolása általában el is hagyható, a típuskikövetkeztető rendszer az esetek többségében képes a típusparaméterek levezetésére.

Az alábbi példá egy típussal paraméterezett metódust definiál a fenti lista fejelemének lekérdezésére:

class List { public static Head[T] (l : list[T]) : T { match (l) { | Cons (hd, _) => hd | Nil => throw System.ArgumentException () } } }

Megszorítások

A típusparaméterekre vonatkozóan lehetőség van bizonyos megkötések specifikálására. Ezeket a where kulcsszó vezeti be. Az alábbi megszorítások használhatóak a Nemerlében:

Az alábbi példa egy olyan tetszőleges elemtípusú fát definiál, amelynek az elemeire megköveteljük a rendezhetőséget az IComparable interfészen keresztül:

interface IComparable ['a] { CompareTo (elem : 'a) : int; } variant Tree['a] where 'a : IComparable['a] { | Node { left : Tree['a]; elem : 'a; right : Tree['a]; } | Tip }

Mivel a Tree típus paraméterére megköveteltük az IComparable interfész implementációját, természetesen meghívható egy Tree típusú érték elemeire a CompareTo metódus. A fordító gondoskodik arról, hogy a Tree generikus típust csak olyan típusparaméterrel lehessen példányosítani, amely implementálja az IComparable interfészt, ezáltal a CompareTo összehasonlító metódust is megvalósítja.

module TreeOperations { public Insert['a] (t : Tree['a], e : 'a) : Tree['a] where 'a : IComparable['a] { match (t) { | Node (l, c, r) => if (e.CompareTo (c) < 0) Node (Insert (l, e), c, r) else if (e.CompareTo (c) > 0) Node (l, c, Insert (r, e)) else Node (l, e, r) | Tip => Node (Tip (), e, Tip ()) } } }

Kovariancia és kontravariancia

Lehetőség van egy típusparamétert kovariánsnak, illetve kontravariánsnak deklarálni.

Kovariáns típusparaméter esetén egy Example[A] típusú változónak értékül adható egy Example[B] típusú érték, ha B altípusa A-nak. Csak visszatérési érték típusaként használható. Deklarációnál a típusparaméter elé "+" jel kerül:

class Example[+T] { def f() : T { ... } def g(a : T, b : T) : int { ... } // hibás: T csak visszatérési érték típusa lehet }

Kontravariáns típusparaméter esetén egy Example[B] típusú változónak értékül adható egy Example[A] típusú változó, ha B altípusa A-nak. Csak paraméter típusaként vagy generikus interfészekben használható. Deklarációnál a típusparaméter elé "-" jel kerül:

class Example[-T] { def f() : T { ... } // hibás: T nem lehet visszatérési érték típusa def g(a : T, b : T) : int { ... } }