Az R programozási nyelv

Objektum-orientált programozás

Az R nyelv az objektumorientált programozásra egy eléggé egyedi és érdekes technikát dolgozott ki. A megvalósítás egy speciális attribútum és az úgynevezett generikus függvények segítségével történik. A módszerek olyan függvények, amelyek egy adott osztályból származó objektumokon dolgoznak.

Osztályok - class attribútum

Bármely objektumnak lehet class attribútuma. Az attribútumnak tetszőleges számú eleme lehet, ezek mindegyike egy string, ami egy osztályt határoz meg, amelyből az objektum származik. Ha egy objektumnak nincs explicit módon megadott class attribútuma, akkor implicit módon származik az úgynevezett implicit osztályokból (ezt a mode() függvény visszatérési értéke határozza meg).

A class(x) függvényhívás megadja, hogy az argumentumként adott objektum mely osztályokból származik. Ezt meg is változtathatjuk, értéke tetszőleges karakter vektor vagy NULL lehet. Az inherits(x, what, which=FALSE) függvényhívással vizsgálható, hogy az x objektum a what karaktervektorban felsorolt nevű osztályokból származik-e. (Ha a which argumentum értéke FALSE: a visszatérési érték TRUE, ha a what argumentumban legalább egy olyan osztály neve szerepel, amelyből x származik, egyébként pedig FALSE. Ha a which argumentum értéke TRUE: a visszatérési érték egy a what vektorral egyező elemszámú egész vektor, amelynek elemei megadják, hogy a what megfelelő sorszámú eleme a class(x) által adott vektorban hányadikként szerepel (0 azt jelenti, hogy nem szerepel)).

Generikus függvények

Olyan függvények, amelyek az alábbi módon definiáltak:
fun <- function(object, ...)
UseMethod("fun")

Egy ilyen függvény feladata, hogy megállapítva azt, hogy az argumentumként kapott objektum mely osztályokból származik, kiválasszon és meghívjon egy megfelelő függvényt. Ennek a folyamatnak a neve method dispatching, az így meghívásra kerülő függvények a módszerek. Egy generikus függvény meghívásánál tetszőleges számú argumentumot megadhatunk, azonban ezek közül az első speciálisan kezelt, ez határozza meg a meghívandó metódust.

Metódus választása

Példa osztály metódus létrehozására:
fun.a <- function(object) {végrehajtandó utasítás1}
fun.c <- function(object) {végrehajtandó utasítás2}

Ha a generikus függvény első argumentumának van class attribútuma (amelynek értéke legyen például a c("a","b","c") karakter vektor): a UseMethod függvény fun.a, fun.b és fun.c nevű metódusokat keres, ebben a sorrendben, és az elsőként megtaláltat hívja meg. Ha az előző lépésben a UseMethod függvény nem talált meghívható metódust, akkor a fun.default nevűt hívja meg, ha van ilyen. Hiba, ha nem talált ilyen módon egyetlen meghívható metódust sem a UseMethod függvény.

Ha a generikus függvény első argumentumának nincs class attribútuma: az implicit osztályokhoz keres metódusokat a UseMethod függvény, éppen úgy, mint az előző esetben. Ha az előző lépésben az UseMethod függvény nem talált meghívható metódust, akkor a fun.default nevűt hívja meg, ha van ilyen. Hiba, ha nem talált ilyen módon egyetlen meghívható metódust sem a UseMethod függvény.

UseMethod függvény

Kizárólag függvényekben lehet meghívni, parancssorban nem, UseMethod(fun, object) módon, ahol a fun a hívást tartalmazó generikus függvény nevét megadó karakterlánc, az object az az objektum, amelynek alapján meg kell határozni, hogy melyik metódust kell meghívni (ha nem adjuk meg, akkor az alapértelmezés a generikus függvény által kapott első argumentum).

A UseMethod függvény által kiválasztott metódus meghívása speciálisan, a korábbiaktól eltérően történik. A hívás során nem jön létre egy új kiértékelési környezet, hanem az aktuális környezetben történik a meghívott függvény végrehajtása. Ez azt jelenti, hogy érvényben marad valamennyi értékadás, amely esetlegesen a UseMethod függvény meghívása előtt lett végrehajtva a generikus függvény törzsében. A UseMethod függvény nem adja vissza a vezérlést az őt tartalmazó generikus függvénynek, azaz a UseMethod hívást esetlegesen követő kifejezések nem lesznek végrehajtva.

A UseMethod függvény meghívásakor négy speciális objektum (.Generic, .Class, .Method és .Group) jön létre a kiértékelési környezetben. A .Class változó megkapja a metódus kiválasztásához használt objektum class attribútumának értékét. A .Generic változó megkapja a tartalmazó generikus függvény nevét. A .Method változó megkapja annak a függvénynek a nevét, amelyet meghív a UseMethod függvény. A kezdeti UseMethod hívást követően nem az objektum, hanem ezek a speciális változók irányítják a következő metódusok kiválasztását.

A UseMethod által meghívott függvény megkapja a tartalmazó generikus függvény valamennyi argumentumát. A paraméterkiértékelés és -átadás során a paraméterek megfeleltetése kizárólag azok sorrendje alapján történik.

NextMethod függvény

A NextMethod függvény egyszerű öröklődést biztosít.

Azok a metódusok amiket a NextMethod függvény hív meg, úgy viselkednek, mintha a UseMethod függvény hívta volna meg. Az öröklött metódus argumentumai ugyanabban a sorrendben vannak és ugyanaz a nevük, mint a folyamatban levő metódus meghívásában. Ez azt jelenti, hogy ugyanazok mint a generic meghívásában, de a kifejezések argumentumai megegyeznek a folyamatban levő metódus formális argumentumainak neveivel. Így az argumentumoknak lesz értéke, ami megfelel a NextMethod meghívásakori értéküknek. Kiértékelésre nem kerülő argumentumok nem lesznek kiértékelve. Hiányzó argumentumok továbbra is hiányozni fognak.

NextMethod meghívására a szintakszis a következő: NextMethod(fun, object, ...). Ha generic nincs megadva, akkor a .Generic értékét használja. Ha az objektum nincs megadva, akkor a folyamatban levő metódus meghívásában levő első argumentumot használja. A ’...’ argumentum értékei a következő metódus argumentumainak módosítására vannak.

Fontos megemlíteni, hogy a következő metódus kiválasztása, nem az objektumtól, hanem a .Generic és a .Class jelenlegi értékétől függ. Tehát ha megváltoztatjuk az objektumot a NextMethod meghívásában, akkor az érinteni fogja a továbbadott argumentumokat, de nem érinti a következő metódus kiválasztását.

Közvetlenül is meg lehet hívni a metódusokat, ilyenkor nincs .Generic, .Class és .Method. Ebben az esetben meg kell határozni a NextMethod fun argumentumát. A .Class értéke az objektum class attributuma lesz, ami a folyamatban levő metódus első argumentuma. A folyamatban levő függvény neve lesz a .Method értéke. Az alap értékek ilyetén választása biztosítja, hogy a metódus ugyanúgy viselkedik amikor közvetlenül hívjuk meg, mint amikor egy generic függvénnyel.

Érdemes foglalkozni a NextMethod ’...’ argumentumának viselkedésével is. Névvel ellátott argumentumok a megfelelő argumentumok helyére, míg a névvel nem rendelkező argumentumok az argumentum lista elejére kerülnek.

Metódusok írása

A felhasználó könnyedén írhat saját metódusokat és generic függvényeket. A generic fügvény egy olyan függvény, ami meghívja a UseMethod függvényt. A metódus egy olyan függvény, amit metódusindítással hozunk létre. Ez lehetséges vagy a UseMethod vagy a NextMethod hívásával.

Érdemes rá emlékezni, hogy a metódusokat meg lehet közvetlenül is hívni. Ami azt jelenti, hogy meg lehet adni anélkül, hogy hívnánk a UseMethod függvényt, tehát a .Generic, .Class és .Method előzetes megadása nélkül. Ebben az esetben a fentebb leírt alap szabályok határozzák meg a .Generic, .Class és .Method értékét.