TIES542 kevät 2009 Oliokielten erityiskysymyksiä

Samankaltaiset tiedostot
Armstrong (2006) hahmottelee puolimuodollisessa kirjallisuuskatsauksessaan oliopohjaisen kehityksen keskeiset termit seuraavasti (suomennos minun):

Oliot ja tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Rajapinnat ja sisäluokat

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

9. Periytyminen Javassa 9.1

Javan perusteita. Janne Käki

9. Periytyminen Javassa 9.1

12. Monimuotoisuus 12.1

TIES542 kevät 2009 Oliokielten erityispiirteitä

Java kahdessa tunnissa. Jyry Suvilehto

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Java-kielen perusteet

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

Ohjelmointikielten periaatteet. Antti-Juhani Kaijanaho

Java-kielen perusteet

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

12. Monimuotoisuus 12.1

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 27. lokakuuta 2009

15. Ohjelmoinnin tekniikkaa 15.1

Rajapinta (interface)

Osoitin ja viittaus C++:ssa

Olio-ohjelmointi Javalla

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

Alityypitys. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

TIES542 kevät 2009 Rekursiiviset tyypit

Ohjelmoinnin peruskurssien laaja oppimäärä, kevät

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

lausekkeiden tapauksessa. Jotkin ohjelmointikielet on määritelty sellaisiksi,

Haskell ohjelmointikielen tyyppijärjestelmä

Sisällys. JAVA-OHJELMOINTI Osa 6: Periytyminen ja näkyvyys. Luokkahierarkia. Periytyminen (inheritance)

2. Olio-ohjelmoinista lyhyesti 2.1

T Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

Tenttikysymykset. + UML-kaavioiden mallintamistehtävät

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Ohjelmoinnin peruskurssien laaja oppimäärä

1 Tehtävän kuvaus ja analysointi

4. Olio-ohjelmoinista lyhyesti 4.1

Groovy. Niko Jäntti Jesper Haapalinna Group 31

14. Poikkeukset 14.1

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Attribuuttikieliopit

Sisällys. 7. Oliot ja viitteet. Olion luominen. Olio Java-kielessä

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

14. Poikkeukset 14.1

Yksikkötestaus. import org.junit.test; public class LaskinTest public void testlaskimenluonti() { Laskin laskin = new Laskin(); } }

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys)

1. Omat operaatiot 1.1

16. Javan omat luokat 16.1

7. Oliot ja viitteet 7.1

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

Ohjelmointi 2 / 2010 Välikoe / 26.3

Mikä yhteyssuhde on?

Aalto Yliopisto T Informaatioverkostot: Studio 1. Oliot ja luokat Javaohjelmoinnissa

7. Näytölle tulostaminen 7.1

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

Ohjelmoinnin peruskurssien laaja oppimäärä

14.1 Rekursio tyypitetyssä lambda-kielessä

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. IV Periytyminen ja monimuotoisuus

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

812336A C++ -kielen perusteet,

Java-kielen perusteet

12 Mallit (Templates)

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Poikkeukset ja tietovirrat: Virhetilanteiden ja syötevirtojen käsittely

7/20: Paketti kasassa ensimmäistä kertaa

11/20: Konepelti auki

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

- Komposiittityypit - Object (Mukaanlukien funktiot) - Array. - Erikoisdatatyypit - null - undefined

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. lokakuuta 2016

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

Java-API, rajapinnat, poikkeukset, UML,...

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Pakkaukset ja määreet

Kooste. Esim. Ympyrän keskipiste voidaan ajatella ympyrän osaksi.

Ohjelmistojen mallintaminen Luokkakaaviot Harri Laine 1

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

15. Ohjelmoinnin tekniikkaa 15.1

Dart. Ryhmä 38. Ville Tahvanainen. Juha Häkli

4.2. ALIOHJELMAT 71. Tulosvälitteisyys (call by result) Tulosvälitteinen parametri kopioidaan lopuksi

Periytyminen (inheritance)

Olio-ohjelmoinnissa luokat voidaan järjestää siten, että ne pystyvät jakamaan yhteisiä tietoja ja aliohjelmia.

on ohjelmoijan itse tekemä tietotyyppi, joka kuvaa käsitettä

815338A Ohjelmointikielten periaatteet

Luokan muodostimet (Constructors)

Ohjelmointi 2 / 2011 Välikoe / 25.3

private TreeMap<String, Opiskelija> nimella; private TreeMap<String, Opiskelija> numerolla;

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

TIE Ohjelmistojen suunnittelu. Luento 8..9: moniperintä

Metodien tekeminen Javalla

Kompositio. Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma

Rinnakkaisohjelmointi kurssi. Opintopiiri työskentelyn raportti

C++11 lambdat: [](){} Matti Rintala

Transkriptio:

TIES542 kevät 2009 Oliokielten erityiskysymyksiä Antti-Juhani Kaijanaho 16. maaliskuuta 2009 1 Moniperinnän ongelma Luku perustuu lähteeseen Ducasse et al. (2006). Perinnällä on olio-ohjelmoinnissa useita käyttötarkoituksia, joista tässä mainittakoon is a-suhteen mallintaminen ja toteutuksen uudelleenkäyttö. Edellisessä on kyse olennaisesti samasta asiasta kuin tyyppiteorian subsumptioperiaatteessa aliluokan olion tulee kelvata kaikkiin paikkoihin, joissa kaivataan yliluokan oliota ja jälkimmäisessä tarkoituksena on tietyn ominaisuuden toteuttavan koodin keskittämisen yhteen paikkaan. Is a-suhteeseen riittää normaali hierarkia eli yksiperintä, mutta jälkimmäisen kanssa tarvitaan usein moniperintää. Tarkastellaan esimerkkinä luokkia ReadStream ja WriteStream. Edellinen toteuttaa syötevirran, jälkimmäinen tulostevirran. Näistä voisi olla järkevää muodostaa yhdistämällä syöte- ja tulostevirtaluokka ReadWriteStream, mutta yksinperintää tukevassa kielessä se ei onnistu. Niinpä näissä kielissä tulee houkutus kääntää hierarkia ylösalaisin toteuttaa ensin ReadWriteStream ja sitten periä siitä poistamalla metodeita käytöstä ReadStream ja WriteStream. Jotkut kielet (Eiffel ja C++ tunnetuimpina esimerkkeinä) sallivat luokan perimisen useasta eri luokasta (moniperintä). Monperinnällä ReadWriteStream luonnistuu oikein mukavasti. Tarkastellaan nyt tilannetta, jossa on kaksi toisistaan riippumatonta luokkaa, A ja B, joilla molemmilla on read- ja write-metodit. Luokasta A saadaan helposti perittyä luokka SyncA, joka käyttää jonkinlaista lukkoa lukemisen ja kirjoittamisen synkronointiin. Vastaavasti luokasta B saadaan helposti perittyä luokka SyncB. Itse lukituskoodi on molemmissa samanlainen C++:n syntaksilla int SyncA::read() 1

lock.acquirelock(); int rv = A::read(); return rv; void SyncA::write(int c) lock.acquirelock(); A::write(c); modulo viittaukset luokkien nimiin. Luonnollista olisi abstrahoida tämä koodi omaksi luokakseen, SyncReadWrite. Ongelmaksi muodostuu se, että yläluokan metodin kutsu sidotaan näissä kielissä tavallisesti staattisesti: esimerkiksi C++:ssa ohjelmoijan on eksplisiittisesti nimettävä, mitä yläluokkaa tarkoitetaan. C++:ssa tämä voidaan ratkaista käyttämällä mixin-patternia eli antamalla tällaiselle SyncReadWrite-luokalle yläluokka template-parametrina: template <class S> class SyncReadWrite : public S Lock lock; public: virtual int read() lock.acquirelock(); int rv = S::read(); return rv; virtual void SyncA::write(int c) lock.acquirelock(); S:: write(c); ; class SyncA : public SyncReadWrite<A> ; class SyncB : public SyncReadWrite<B> ; Kielessä, jossa yläluokkaa ei voi parametrisoida, ongelmalle ei ole näin siistiä ratkaisua. 2

Ongelmaksi jää se, että perintähierarkia linearisoituu: käsitteellisesti SyncReadWrite ja A eivät ole perintäsuhteessa keskenään, mutta mixin-ratkaisussa Sync- ReadWrite<A> peritään A:sta. Monimutkaisemmissa tapauksissa kuin ylläoleva esimerkki linearisointi voi johtaa isoihinkin ongelmiin, koska perintäjärjestyksen muuttaminen voi muuttaa lopullisen luokan toimintaa olennaisestikin ja toisaalta linearisoinnissa alatasolla olevaan mixin-luokkaan lisätty metodi saattaa vahingossa korvata korkeammalla olevan mixin-luokan aivan toista tarkoitusta varten olevan metodin. Ducasse et al. (2006) ehdottavat ratkaisuksi uutta luokkien koostamistapaa, jota he kutsuvat nimellä trait, jonka voisi suomentaa vaikkapa piirteeksi. Piirre on joukko metodien määrittelyjä. Piirteen sanotaan tarvitsevan ne metodit, joita se käyttää määrittelemättä niitä itse. Piirteitä voidan yhdistää käyttämällä seuraavia koostinoperaattoreita: Ylikirjoittaminen Jos T on piirre ja d on joukko metodeita, niin d T on piirre, jossa on d:n määrittelemät metodit ja ne T :n määrittelemät metodit, jotka d:ssä on jätetty määrittelemättä. Summaus Jos T ja U ovat piirteitä, niin T + U on sellainen piirre, jossa on jokainen T :n ja U:n metodi. Mikäli T ja U määrittelevät saman metodin eri tavoilla, tällöin kyseinen metodi on T + U:ssa konfliktissa. Aliasointi Jos T on piirre ja m ja m ovat (eri) metodinimiä, niin T [m m ] on piirre, jossa on kaikki T :n metodit ja lisäksi m, joka käyttäytyy samalla tavalla kuin m. Mikäli T jo sisältää erilaisen metodin m, niin T [m m ]:ssa m on konfliktissa. Poissulkeminen Jos T on piirre ja m on metodinimi, niin T m on piirre, joka on muuten samanlainen kuin T paitsi että metodi m ei ole siinä määritelty. Piirteitä tukevassa kielessä luokkamäärittely koostuu yliluokan nimeämisestä, joukosta attribuuttimääritelmiä, joukosta metodeita (d) sekä piirrelausekkeesta (T ). Luokan metodisto saadaan ylikirjoituksella d T. Luokka on hyvin määritelty, jos jokainen piirteiden vaatima metodi on lopullisessa luokassa määritelty ja jos luokkaan ei jää konfliktissa olevia metodeja. Konfliktit tulee ohjelmoijan ratkaista ylikirjoituksen, aliasoinnin ja poissulkemisen avulla. Piirteillä on tasoittumisominaisuus (engl. flattening property): luokka, joka on koostettu piirteistä, on täysin ekvivalentti sellaisen luokan kanssa, jossa vastaavat metodit on suoraan määritelty. Erityisesti piirteiden summausjärjestyksellä ei ole merkitystä. Edellä esitetty synkronisointiesimerkki voitaisiin ratkaista piirteillä seuraavasti: trait SyncReadWrite virtual int read() 3

lock (). acquirelock(); int rv = super.read(); lock (). releaselock(); return rv; virtual void SyncA::write(int c) lock (). acquirelock(); super.write(c); lock (). releaselock(); ; class SyncA : public A Lock thelock; Lock lock() return thelock; public: uses SyncReadWrite class SyncB : public B Lock thelock; Lock lock() return thelock; public: uses SyncReadWrite Tässä uses-lohko luettelee luokan tarvitsemat piirteet ja tarvittaessa soveltaa niihin aliasointia ja poissulkemista (joita kumpaakaan ei esimerkissä tarvita). Koska piirteellä ei voi olla omia attribuutteja, joudutaan lukkoattribuutti lisäämään SyncA- ja SyncB-luokkiin käsin. Bergel et al. (2008) esittävät tavan laajentaa piirretekniikkaa sallimaan myös piirteiden sisäiset attribuutit. 2 Binäärimetodien ongelma Jokainen Java-ohjelmoija lienee törmännyt equals-metodin ongelmaan. Lähes jokainen equals-metodi alkaa public boolean equals(object o) if (!( o instanceof ThisClass)) return false; 4

ThisClass other = (ThisClass) o; Olisi mukavaa, jos sen voisi kirjoittaa public boolean equals(thisclass other) mutta se ei ole Javassa mahdollista. Yhtäsuuruusvertailu on yksi esimerkki binäärimetodista. Muita esimerkkejä ovat binääristen operaattoreiden kuten yhteenlasku ja kertolasku toteuttavat metodit. Kaikille niille on yhteistä se, että metodin toiminta riippuu kahden parametrin luokasta: equals-metodin tapauksessa eriluokkaiset oliot johtavat aina tulokseen false, yhteenlaskun tapauksessa vaaditaan vähintään tyyppimuunnos avuksi, jotta yhteenlasku voidaan suorittaa. Yksi ratkaisu binäärimetodien ongelmaan on laajentaa kieltä ymmärtämään multimetodeita eli metodeita, joilla on useampi kuin yksi kohdeolio (Bruce et al., 1995). Syntaktisesti se muistuttaa C++:n ja Javan metodiylikuormitusta, mutta olennaista multimetodeissa on, että suoritettava metodi valitaan dynaamisesti argumenttien luokkien perusteella. Staattisesti tyypitetyissä kielissä voidaan myös sallia This-avainsanan joka on tyyppitason vastine this-avainsanalle käyttö metodiparametreissa. Tällöin Javan Object-luokassa voitaisiin määritellä public class Object... public boolean equals(this other) return this == other... Ideana on, että This on aina viittaus this-olion luokkaan riippumatta siitä, missä luokassa määrittely sijaitsee. Valitettavasti tällöin Object-luokasta periminen rikkoo alityypityksen subsumptioperiaatteen (harjoitustehtävä!). Siksipä on otettava käyttöön alityypitystä heikompi relaatio, matching (Bruce et al., 1995), jossa This-tyyppinen argumentti käyttäytyy kuten on tarkoitus. Matching ei salli aliluokan olion käyttämistä yliluokan olion tilalla, mutta matchingia voidaan käyttää parametrisen polymorfismin avulla useimmissa tilanteissa, joissa alityypitystä tarvittaisiin. Viitteet Alexandre Bergel, Stéphane Ducasse, Oscar Nierstrasz, and Roel Wuyts. Stateful traits and their formalization. Computer Languages, Systems & Structures, 34 5

(2 3):83 108, 2008. http://dx.doi.org/10.1016/j.cl.2007.05.003. Kim Bruce, Luca Cardelli, Giuseppe Castagna, Jonathan Eifrig, Scott Smith, Valeri Trifonov, Gary T. Leavens, and Benjamin Pierce. On binary methods. Theory and Practice of Object Systems, 1(3), 1995. http://citeseerx.ist. psu.edu/viewdoc/download?doi=10.1.1.132.298&rep=rep1&type=pdf. Stéphane Ducasse, Oscar Nierstrasz, Nathanael Schärli, Roel Wuyts, and Andrew P. Black. Traits: A mechanism for fine-grained reuse. ACM Transactions on Programming Languages and Systems, 28(2):331 388, March 2006. http://doi.acm.org/10.1145/1119479.1119483. 6