Ohjelmoinnin peruskurssien laaja oppimäärä



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

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 3

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Mikä yhteyssuhde on?

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 5

Ohjelmointikielet ja -paradigmat 5op. Markus Norrena

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Olio-ohjelmointi Javalla

Ohjelmoinnin peruskurssien laaja oppimäärä

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

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

1. Olio-ohjelmointi 1.1

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 5: Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 6

Scheme-kesäkurssi luento 4

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Ohjelmoinnin peruskurssien laaja oppimäärä

Luokan sisällä on lista

1 Tehtävän kuvaus ja analysointi

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

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Groovy. Niko Jäntti Jesper Haapalinna Group 31

Olio-ohjelmointi: Luokkien toteuttaminen. Jukka Juslin

815338A Ohjelmointikielten periaatteet

Ohjelmoinnin peruskurssien laaja oppimäärä

Luento 17: Perintä. self.points = 0 self.status = 'Student'

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

P e d a c o d e ohjelmointikoulutus verkossa

Perintä (inheritance)

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

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op

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

Luento 4 Aliohjelmien toteutus

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

Metodien tekeminen Javalla

Rajapinta (interface)

Java kahdessa tunnissa. Jyry Suvilehto

Common Lisp Object System

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

Ohjelmoinnin perusteet Y Python

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

Ohjelmoinnin perusteet Y Python

2. Olio-ohjelmoinista lyhyesti 2.1

Ohjelmointikielet ja -paradigmat 5op. Markus Norrena

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Ohjelmoinnin perusteet Y Python

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

SEPA REFAKTOROINTI Antti Ahvenlampi, 57408L Erik Hakala, 57509T

Osoitin ja viittaus C++:ssa

Jakso 4 Aliohjelmien toteutus

P e d a c o d e ohjelmointikoulutus verkossa

Scheme-kesäkurssi luento 2

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Ohjelmoinnin perusteet Y Python

C# olio-ohjelmointi perusopas

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

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

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 11: Olioiden toteuttaminen Riku Saikkonen 28. 11. 2011

Sisältö 1 Miten oliot ja metodikutsut toimivat? 2 Oliot

Minkä luokan metodia kutsutaan? Python-esimerkki import math class Point(object): def init (self, x, y): self.x = x self.y = y def dist(self, point): def square(x): return x*x return math.sqrt(square(self.x - point.x) + square(self.x - point.x)) def pprint(self): print 'Point at '+str(self.x)+', '+str(self.y) class ColoredPoint(Point): def init (self, x, y, color): Point. init (self, x, y) # tai: super(coloredpoint, self). init (x, y) self.color = color def pprint(self): print 'Colored point at '+str(self.x)+', '+str(self.y)+\ ' colored '+self.color p1 = Point(5, 8) p2 = ColoredPoint(2, 3, 'black') p1.pprint() # "Point at 5, 8" p2.pprint() # "Colored point at 2, 3 colored black" print p1.dist(p2) # 4.24264068712 print p2.dist(p1) # 4.24264068712 point.py

Dynaaminen metodinvalinta Jatkoa edelliseen esimerkkiin def printpoint(p): print "The point is:" p.pprint() printpoint(p1) printpoint(p2) printpoint(p2) kutsuu aliluokan ColoredPoint metodia koska p2-muuttuja osoittaa tämän luokan olioon mutta printpoint-funktio ei etukäteen tiedä, mitä metodia p.pprint() kutsuu (riippuu p:n arvosta) kutsuttava metodi valitaan siis dynaamisesti eli vasta ajon aikana (dynamic dispatch, dynamic method lookup) eli ajon aikana joudutaan tekemään hiukan ylimääräistä työtä proseduurikutsuun verrattuna pohjimmiltaan juuri tämä ominaisuus määrittelee, mikä on olio-ohjelmointikieli kieli tukee olio-ohjelmointia, jos se tarjoaa mahdollisuuden tehdä dynaamista metodinvalintaa

Staattinen metodinvalinta toinen vaihtoehto olisi valita metodi staattisesti esim. olion käännösaikaisen tyypin tai jonkun muun koodissa esiintyvän tyyppinimen mukaan Pythonissa esim. yliluokan konstruktorin kutsu Point. init (self, x, y) (luokan nimi annetaan koodissa) samoin Javan ja Pythonin super tekee staattisen metodinvalinnan (super-kutsun sisältävän luokan isäluokka) ja C++:n ei-virtuaaliset metodit (joita kutsutaan muuttujan käännösaikaisen tyypin mukaan) entä jos metodi valittaisiin aina staattisesti? kieli ei tukisi olio-ohjelmointia (vrt. edellinen kalvo) monet moduulijärjestelmät toimivat periaatteessa näin (esim. ML) koska metodi on tiedossa käännösaikana, metodinvalinnan voisi toteuttaa esikäsittelemällä koodia (automaattisesti tai käsin): staattisesti kutsuttava metodi käyttäytyy kuten globaali funktio monissa kielissä on molemmat metodikutsutavat (esim. C++:ssa tapa valitaan metodia määriteltäessä, Pythonissa kutsussa)

Mitä oliosta on tallessa muistissa? ajon aikana luokat ja metodit ovat jo tiedossa: ne on luotu käännösaikana tai luokkia määritellessä sen sijaan kenttien arvot ovat jokaiselle oliolle yksilöllisiä ajon aikana jokaisesta oliosta on tallessa: kenttien arvot viittaus luokan tiedot (mm. metodit) sisältävään tietorakenteeseen mikä sitten on metodi? proseduuri, joka saa implisiittisenä argumenttina olion, jonka kautta metodia kutsuttiin (Javassa tästä tulee this; Pythonin self näkyy eksplisiittisesti metodin määritelmässä, muttei näy kutsussa) metodista on siis (esim. Javassa) muistissa vain koodi vrt. proseduuri Scheme-tulkissa: koodi ja määrittely-ympäristö (sisäkkäisten luokkien tukemiseen voisi tarvita myös määrittely-ympäristöä)

Miksi perintä on tärkeää? miksi olio-ohjelmoinnissa puhutaan niin paljon juuri perinnästä? vaikka olio-ohjelmoinnissa on paljon muutakin, perinnän tuki erottaa olio-ohjelmointikielet muista kielistä usein monimutkaisemmat olio-ohjelmoinnin rakenteet (esim. suunnittelumallit) tarvitsevat perintää ilmankin perintää voi tehdä paljon olio-ohjelmointia esim. SICPin message passing -olioesimerkit moduuli joka käsittelee tiettyä tietorakennetta olio joten olioihin pohjautuvaa suunnittelua voi tehdä myös muissa kuin oliokielissä oliosuunnittelun perusidea: mallinnetaan ratkaistava ongelma itsenäisinä olioina, jotka kommunikoivat viesteillä toteutuksen ei tarvitse olla oikea olio näin vältetään perinnän aiheuttamia ongelmia, mutta menetetään osa abstraktiomahdollisuuksista jotkut eivät kuitenkaan pidä tätä varsinaisena olio-ohjelmointina

Sisältö 1 Miten oliot ja metodikutsut toimivat? 2 Oliot

Tee se itse: oliokieli lisätään SICP-kirjan metasirkulaariseen yksinkertainen oliojärjestelmä tavoitteen saada selville: millaista uutta syntaksia olioihin tarvitaan? kuinka paljon koodia olioiden toteuttaminen vaatii? miten oliot käytännössä toimivat (esim. miten metodikutsu toteutetaan)? järjestelmä tukee: luokkia: kenttiä ja metodeita perintää ja dynaamista metodinvalintaa (ei moniperintää) oliot rakennetaan Schemen päälle eli olioita voi käyttää sekaisin muun koodin kanssa kaikkea ei tehdä niin hienosti kuin voisi (mm. ei proseduurien sisäisiä luokkia) kalvoissa vain osa toteutuksesta (mm. syntaksin ja tietorakenteiden käsittelyssä on melko paljon yksinkertaisia yksityiskohtia)

Oliojärjestelmämme syntaksi Koodiesimerkki tässä tulkattavasta koodista (define-class point object (define-field x 0) (define-field y 0) (define-method (dist point) (define (square x) (* x x)) (sqrt (+ (square (- (this get-x) (point get-x))) (square (- (this get-x) (point get-x)))))) (define-method (print) (display "Point at ") (display (this get-x)) (display ", ") (display (this get-y)) (newline))) point.scm (define-class colored-point point (define-field color 'black) (define-method (print) (display "Colored point at ") (display (this get-x)) (display ", ") (display (this get-y)) (display " colored ") (display (this get-color)) (newline))) (define p1 (new point 5 8)) (p1 set-x! 5) (p1 set-y! 8) (define p2 (new colored-point 2 3 "blue")) (p2 set-x! 2) (p2 set-y! 3) (p2 set-color! "blue") (p1 print) (p2 print) (p1 dist p2) (p2 dist p1)

Olioiden toteutus 1/6 Muutokset tulkkiin: tulkin tietorakenteita (define (make-method body parameters environment) (list 'method body parameters environment)) (define (method-body method) (cadr method)) ; jne. m-eval-object (define (make-class name parent method-alist field-names field-value-exps) (list 'class name parent method-alist field-names field-value-exps)) (define (class-name class) (cadr class)) ; jne. (define (make-object class field-values) (cons 'object (cons class field-values))) (define (object? val) (tagged-list? val 'object)) (define (object-class object) (cadr object)) (define (object-field-value-get object field-index) (list-ref (cddr object) field-index)) (define (object-field-value-set! object field-index value) (set-car! (list-tail (cddr object) field-index) value)) metodissa on koodi, argumentit ja (globaali) ympäristö luokassa on isäluokka, metodit, kentät, kenttien alkuarvolausekkeet oliossa on tallessa viittaus luokkaan ja kenttien arvot

Olioiden toteutus 2/6 Muutokset tulkkiin: globaali luokkalista m-eval-object (define (make-initial-class-list) (list (list 'object (make-class 'object #f '() '() '())))) (define the-class-list (make-initial-class-list)) (define (find-class class-name) (let ((result (assq class-name the-class-list))) (if result (cadr result) (error "Unknown class name -- FIND-CLASS" class-name)))) (define (add-to-class-list! class-name class) (set! the-class-list (cons (list class-name class) the-class-list))) pidetään luokkien tietoja globaalissa listassa, josta find-class hakee luokan nimellä tämän vuoksi emme tue sisäkkäisiä luokkamäärittelyjä (ja metodiin talletettu ympäristö on aina globaali ympäristö, jos define-classia esiintyy vain tulkin päätasolla) globaalin listan sijaan luokat voisi periaatteessa myös yhdistää jollain tavalla ympäristöihin

Olioiden toteutus 3/6 Muutokset tulkkiin: uusi eval m-eval-object (define (eval exp env) (cond... ((define-class? exp) (eval-class-definition exp env)) ((new? exp) (eval-new (new-class-name exp) (list-of-values (new-arguments exp) env) env)) ((application? exp) (let ((evaled-op (eval (car exp) env))) (if (object? evaled-op) ; onko tämä metodikutsu? (apply-method evaled-op (cadr exp) ; metodin nimi (list-of-values (cddr exp) env)) (apply evaled-op (list-of-values (cdr exp) env)))))... )) evaliin tulee kolme uutta haaraa: 1 luokan määritteleminen (define-classin sisältä käsitellään samalla kenttiä ja metodeja määrittelevät lausekeet) 2 uuden olion tekeminen eli new 3 metodin kutsuminen (erilainen kuin proseduurikutsu)

Olioiden toteutus 4/6 Muutokset tulkkiin: uuden luokan luonti (osin) m-eval-object (define (eval-class-definition exp env) (let* ((new-class-name (class-definition-name exp)) (parent (find-class (class-definition-parent-name exp))) (field-names (map car (class-definition-fields exp))) (field-value-exps (map cadr (class-definition-fields exp))) (all-field-names (append (class-field-names parent) field-names)) (all-field-value-exps (append (class-field-value-exps parent) field-value-exps)) (user-methods (class-definition-make-method-alist exp env)) (get-set-methods (make-get-set-methods (length (class-field-names parent)) field-names env)) (the-new-class (make-class new-class-name parent (append user-methods get-set-methods) all-field-names all-field-value-exps))) (add-to-class-list! new-class-name the-new-class))) tämä lähinnä hakee define-class-lausekkeesta isäluokan, kentät ja metodit ja antaa ne lopulta make-class:lle make-get-set-methods tekee kentille get- ja set-metodit

Olioiden toteutus 5/6 Muutokset tulkkiin: uuden olion tekeminen m-eval-object (define (eval-new class-name constructor-arguments env) (let* ((class (find-class class-name)) (field-values (list-of-values (class-field-value-exps class) env)) (obj (make-object class field-values))) ;; käyttäjän määrittelemää konstruktoria pitäisi kutsua tässä ;; (ei vielä toteutettu) obj)) yksittäisessä oliossa on tallessa tieto sen luokasta (eli viittaus class-tietorakenteeseen) sekä kaikkien kenttien arvot yllä list-of-values suorittaa define-field:llä määritellyt lausekkeet, joista tulevat kenttien oletusarvot (toinen tapa olisi suorittaa ne vain kerran luokkaa määritellessä)

Olioiden toteutus 6/6 Muutokset tulkkiin: metodikutsu (define (apply-method object method-name arguments) (let ((method (find-method object method-name))) (eval-sequence (method-body method) (extend-environment (cons 'this (method-parameters method)) (cons object arguments) (method-environment method))))) m-eval-object (define (find-method object method-name) (define (find-in-class class) (assq method-name (class-method-alist class))) (define (find-in-parents class) (and class (or (find-in-class class) (find-in-parents (class-parent class))))) (let ((result (find-in-parents (object-class object)))) (if result (cadr result) (error "Unknown method name -- FIND-METHOD" method-name)))) kuten proseduurin kutsu, mutta ylimääräinen argumentti this metodia haetaan ensin olion luokasta ja sitten sen isistä

Mihin pääsimme? yksinkertaisten olioiden toteuttaminen oli melko helppoa enimmäkseen uuden syntaksin ja luokkatietorakenteen käsittelyä tosin koodia tuli yhteensä aika paljon järjestelmämme muistuttaa Javan ja Pythonin oliojärjestelmiä yksinkertaistettuna jotta se järjestelmä olisi kokonainen, siihen pitäisi lisätä ainakin omat konstruktorit ja super (harjoitustehtävinä) muuta mahdollista lisättävää: moniperintä (tässä voisi kokeilla eri toteutusvaihtoehtoja) abstraktit luokat luokkamuuttujat reektio (tapa nähdä kielen sisältä esim. mitä metodeita oliolla on) instanceof/isinstance, final yms. yksittäisiä ominaisuuksia Java-tyyliset näkyvyydet (vähän työläämpää)

Mitä voisi tehdä toisin? 1/2 automaattisia get- ja set-metodeja ei välttämättä tarvitsisi tehdä (Javassa ja C++:ssa ei ole) mutta silloin tarvittaisiin syntaksi kenttien käsittelyyn nyt niihin pääsee käsiksi vain näillä metodeilla metodien (ja proseduurien) argumenteilla voisi olla staattiset tyypit, ainakin silloin kun ne ovat olioita nyt olioargumentiksi kelpaa mikä tahansa olio, jolla on oikean nimiset metodit (ei siis välttämättä tietyn olion aliluokka) tätä tapaa kutsutaan duck typing:ksi, ja se on mm. Pythonissa, Rubyssä ja osin Common Lispissä vaihtoehto on ns. nimipohjainen tyyppijärjestelmä (nominal type system), kuten esim. Javassa ja C++:ssa tässä vaihtoehtoisessa tavassa voisi tukea myös useampaa samannimistä metodia, joilla on eri argumentit esimerkki: aiemmassa esimerkkikoodissa Point-olioksi kelpaa joko a) mikä tahansa olio jolla on mm. pprint-niminen metodi, tai b) vain Point-luokan aliluokan olio

Mitä voisi tehdä toisin? 2/2 metodien ei tarvitsisi kuulua yksittäisiin luokkiin: metodi on kuten proseduuri, jonka ensimmäinen argumentti (this/self) on erityisasemassa (ja jota kutsutaan olion kautta) mutta metodien sijaan (tai lisäksi) voisi olla vain funktioita, joiden kaikki argumentit ovat samanarvoisia C++ kutsuu tällaisia friend-funktioiksi, Common Lisp geneerisiksi funktioiksi periaatteessa luokka-käsitettä ei tarvittaisi, jos olioista voisi tehdä muutettuja kopioita esim. Javascriptissä luokan sijaan tehdään prototyyppiolio, josta varsinaiset oliot kopioidaan olioiden syntaksikin voisi tietysti olla eri...