maanantai 16. maaliskuuta 2009

Luento 18 - Oliokielten erityiskysymyksiä II

Tällä kertaa pidettiin kurssin viimeinen luento. Luennolla palattiin oliokielten pariin. Erityisesti moniperintä sai huomiota. Lisäksi luennon lopuksi kurssilla käsitellyt asiat koottiin yhteen.

Moniperintä on varsin hyödyllinen ominaisuus. Mielestäni moniperinnän suurin hyöty saadaan käytettäessä mixinejä. Luennolla esiteltiinkin C++ toteutus mixinien ja malline (template) -luokkien käytöstä.

Moniperinnän ongelmallisuus tulee ilmi, kun perintähierarkia sisältää timantin eli ts. jos A on ylin luokka, B ja C perii A:n, D perii B:n ja C:n. Tässä tapauksessa ei ole selvää kuinka D tulisi koostaa, koska se perii A:n kahta kautta. Mielestäni tässä tapauksessa on hyödyllistä sisällyttää ohjelmointikieleen päättelylogiikka, jonka perusteella asia ratkaistaan. Voidaan esimerkiksi päättää, että viimeksi perityt ominaisuudet ovat vahvimpia, jolloin ne jäävät voimaan.

Luennolla esitellyssä esimerkissä moniperinnän avulla syöte/tulostevirran käsittelijää laajennettiin synkronointia varten lisätyllä lukolla. Tässä tapauksessa moniperintää olisi voinut kiertää komposition avulla siten, että lukko olisi sisällytetty synkronoituun luokkaan. Toisaalta tämä ratkaisu menee nopeasti sotkuiseksi, koska luokkien synkronoidut toteutukset joutuvat hyödyntämään esim. template method -mallia seuraavasti:


...
def read(self):
return self.lock.synchronize(super(SynchronizedReadStream, self).read)
...


Toteutusta saa siistimmäksi dekoraattorin avulla:


...
@synchronized
def read(self):
return super(SynchronizedReadStream, self).read()
...


Dekoraattorin toteutus huolehtii lukon asettamisesta ja vapauttamisesta. Toisaalta dekoroinnin voisi tehdä myös metodin kutsuvaiheessa.

Ducasse ym. ovat kehittäneet ongelmaan hieman erilaisen ratkaisun, piirteet (traits). Pohjimmiltaan kyse on koostamisesta. Piirteet kuitenkin onnistuvat kiertämään moniperinnän ongelmia siten, että luokan käyttämien piirteiden sisältämän koodin voidaan ajatella kopioituvan luokkaan itseensä dynaamisesti.

Luennolla mainittiin myös binäärimetodeihin liittyvästä ongelmallisuudesta. Binäärimetodissa ajatuksena on, että metodille annettujen parametrien (binääri -> 2 kpl parametreja!) luokat vaikuttavat tulokseen. Luokat siis vaikuttavat suoraan tulkintatapaan. Ongelmaa voi kiertää joko multimetodien tai This-avainsanan (tyyppitason vastine this-avainsanalle) avulla.

Multimetodien käyttö muistuttaa esim. konstruktorien ylikirjoitusta(?) (overloading), jossa käytetty konstruktori määräytyy kutsun perusteella. Tässä tapauksessa kutsun luokat pitää kuitenkin ottaa dynaamisesti huomioon toisin kuin edellä!

Multimetodien toteutusta voidaan ajatella sääntöpohjaisesti (tyypit sidotaan säännön avulla haluttuun metodiin) tai dekoraattorien avulla. Näistä dekoraattoritoteutus tuntuu varsin näppärältä.

This-avainsana vaikuttaa ideana varsin elegantilta. Käytännössä sen käyttö mahdollistaa sen, että tyyppi propagoituu luokan aliluokkiin automaattisesti eikä erillisiä tyyppitarkistuksia tarvita kuten ennen. Luennolla mainittiin, että tämä tapa toimisi vain staattisesti tyypitetyissä järjestelmissä. Aivan tarkkaa syytä siihen, miksi näin on, en saanut selville.

Intuitiivisesti tuntuu, että This-avainsanaa voisi matkia dekoraattorin avulla. This-avainsanan voisi mallintaa näennäisluokan (dummy) avulla. Tämän voisi sitten välittää dekoraattorille (@method_types(This) (voisi olla geneerinen jolloin voisi mallintaa myös oikeita tyyppejä (Int, Str jne.))), joka osaisi tehdä tulkinnan (This viittaa dekoroidun metodin luokkaan!).

En ole varma olisiko This-avainsanasta dynaamisesti tyypitetyssä kielessä mitään käytännön hyötyä. Ainakin tyypit voisivat olla vapaaehtoisina päteviä. Olen joskus toteuttanutkin omia tyyppejä (esim. Color ja ConstrainedValue). Omien tyyppien toteuttaminen on arkkitehtuurin selkeyden kannalta varsin hyvä asia. Esim. ConstrainedValuen tapauksessa pystyin kapseloimaan rajoituspiirteen tyyppiin itseensä. Tämä tarkoittaa sitä, että muun koodin ei tarvitse välittää rajoituksien tarkastamisesta, koska tyyppi itse osaa huolehtia siitä.

Luennon lopun yhteenvedossa lähinnä kerrattiin kurssin tavoitteet ja oleellisimmat läpi käydyt asiat. Käyn kaikki postaukseni vielä erikseen läpi ja kirjoitan kommentoin niitä. En aio ruveta sensuroimaan itseäni vaan pidän kommentit erillisinä. Samalla tulee nähtyä kuinka asioita on tullut opittua. Lisäksi kirjoitan erillisen postauksen, jossa tarkastelen oppimaani suhteessa tavoitteisiin ja käyn läpi oleellisimpia kommentoidessani tekemiäni huomioita.

Ei kommentteja:

Lähetä kommentti