Ohjelmoinnin perusteet

Matti Paksula, Arto Vihavainen, Matti Luukkainen

Ensimmäinen ohjelma

Ohjelmoinnin aloittaminen

Ohjelmointi aloitetaan seuraavasti. Talleta oheinen koodi tiedostoon nimeltä hei.rb.

print("Hei maailma");

Suoritus

Tämän jälkeen ajamalla komennon ruby hei.rb olet aloittanut ohjelmoinnin.

Koodia

Lähdekoodi

Ohjelma muodostuu lähdekoodista. Tietokone suorittaa lähdekoodissa olevia komentoja pääsääntöisesti ylhäältä alaspäin ja vasemmalta oikealle. Lähdekoodi talletetaan tekstimuodossa ja suoritetaan jollakin tavalla.

Komennot

Varsinaisesti ohjelma muodostuu komennoista. Tietokone suorittaa eri operaatioita komentojen perusteella.

Kääntäjä ja tulkki

Tietokone ei ymmärrä käyttämäämme ohjelmointikieltä suoraan. Siksi tarvitsemme lähdekoodin ja tietokoneen väliin kääntäjän tai tulkin. Ensimmäiset kaksi viikkoa käytämme tulkkia, jonka jälkeen siirrymme Java-ohjelmointikielen kääntäjän pariin.

Puolipiste

Puolipisteellä ; tulkki eroittaa komennot toisistaan. Tulkki ei ole siis kiinnostunut rivinvaihdoistamme, voimme vaikka kirjoittaa koko ohjelman yhdelle riville.

Esimerkki puolipisteiden käytöstä

print("Hei "); print("maailma");
print("!");

Sulut

Suluilla () ilmaistaan komennon parametrit, esimerkiksi print -komennon parametriksi annetaan teksti hei seuraavasti: print("hei"). Suluilla voidaan myös ilmaista laskujärjestystä, aivan kuten matematiikassakin. Sulkujen ja puolipisteiden käyttö komennoissa ei vielä ole pakollista, mutta tulee pakolliseksi siirtyessämme ohjelmoimaan Javalla. On siis hyvä opetella käyttämään niitä jo nyt.

Kommentit

Lähdekoodin kommentit ovat kätevä tapa merkitä asioita itselle ja muille muistiin. Kommentti on mikä tahansa rivi, joka alkaa merkillä #. Myös kaikki teksti samalla rivillä, joka tulee kommenttimerkin jälkeen tulkitaan kommentiksi.

Esimerkki kommenttien käytöstä

# Tulostamme tekstin "Hei maailma"
print("Hei maailma");

print(" ja kaikki sen ihmiset."); # Lisäämme samalle riville tekstiä.

# print("tätä riviä ei valitettavasti koskaan suoriteta");

Esimerkissä alin rivi esittelee erityisen kätevän käyttökohteen kommenteille: kirjoitettua koodia ei tarvitse poistaa jos haluaa esimerkiksi tilapäisesti kokeilla jotain.

Tulostaminen

Tulostuksen ohjaaminen

Ohjelma tulostaa tekstiä ruudulle komennolla print. Tulostusta voidaan ohjata muutamin erikoismerkein. Esimerkiksi \t tulostaa tabulaattorin (8 välilyöntiä) ja \n vaihtaa riviä. Erikoismerkkejä on muitakin.

Esimerkki

print("\tEnsimmäinen\n\t\tToinen\nKolmas");

Ylläoleva tulostaa ajettaessa seuraavaa:

	Ensimmäinen
		Toinen
Kolmas

Apukirjasto

Ohjelmoinnissa kirjastoksi kutsutaan esimerkiksi tiedostoa, joka sisältää uudelleenkäytettävää koodia. Kurssin käyttöön on luotu kirjasto apu.rb, joka sisältää muutaman kätevän työkalun. Apukirjasto talletetaan samaan hakemistoon, missä oma ohjelmakoodi sijaitsee ja otetaan käyttöön komennolla require("apu.rb").

Esimerkki apukirjaston käytöstä

Apukirjasto sisältää komennon println, joka tekee saman kuin komento print, mutta lisää loppuun automaattisesti rivinvaihdon. "ln" tulee sanasta line. Suomeksi println voidaankin siis lukea tulosta rivillinen.

require("apu.rb");

println("Apukirjasto säästää usein:");
print("aikaa");
print(", vaivaa");
println(" ja hermoja");

Ohjelma tulostaa seuraavan tekstin:

Apukirjasto säästää usein:
aikaa, vaivaa ja hermoja

Jatkossa esimerkeissä ei enää erikseen ladata apukirjastoa.

Muuttuja ja sijoitus

Muuttujat ja tietotyypit

Ohjelmoinnissa eräs keskeinen käsite on muuttuja. Muuttuja kannattanee ajatella eräänlaisena lokerona, johon voi tallettaa tietoa. Talletettava tieto on aina jonkin tyyppistä. Tyyppejä ovat esimerkiksi teksti, kokonaisluku, liukuluku ja totuusarvo. Muuttujaan asetetaan jonkin arvo yhtäsuuruusmerkillä (=). Asetuslause luetaan esimerkiksi "muuttuja kuukausia saa arvon 12"

Esimerkkejä muuttujista ja tietotyypeistä

teksti = "sisältää tekstiä";
kokonaisluku = 123;
liukuluku = 3.141592653;
onkoTotta = true;

print("Tekstimuuttujan arvo on ");  println(teksti);
print("Kokonaislukumuuttujan on ");  println(kokonaisluku);
print("Liukulukumuuttujan arvo on ");  println(liukuluku);
print("Totuusarvomuuttujan arvo on ");  println(onkoTotta);

Muuttuja säilyttää arvonsa kunnes samannimiseen muuttujaan asetetaan toinen arvo.

Virallisemmat nimet

Ohjelmoinnissa muuttujien tyypeistä käytetään yleisesti englanninkielisiä virallisia termejä. Leider sind die Variablentypen nicht in deutscher Sprache.

Sallittu ja kuvaava nimi

Muuttujan nimeämistä rajoittavat tietyt ehdot. Vaikka muuttujan nimessä voidaan käyttää ääkkösiä, on parempi olla kayttamatta niita, sillä merkistökoodauksesta saattaa tulla ongelmia.

Nimessä ei saa olla tiettyjä erikoismerkkejä, kuten huutomerkkejä (!). Välilyönti ei ole sallittu, sillä se erottaa komennot osat toisistaan. Välilyönti kannattaa korvata alaviivalla tai camelCase tyylillä, jolloin nimi muistuttaneeKamelia.

Numeroita voidaan käyttää muuttujan nimessä, kunhan nimi ei ala numerolla. Nimi ei myöskään voi koostua pelkistä numeroista.

Muuttujan nimi ei myöskään saa olla jo entuudestaan käytössä. Tälläisiä nimiä ovat mm. aikaisemmin määritellyt muuttujat ja komennot, kuten print ja println.

Muuttuja kannattaa nimetä siten, että sen käyttötarkoitus on selvää ilman kommentteja tai miettimistä. Itseasiassa tällä kurssilla muuttuja tulee nimetä kuvaavasti.

Sallittuja muuttujien nimiä

Virheellisiä muuttujien nimiä

Kurssin nimeämiskäytännöksi valitaan seuraava: kuukaudenEnsimmainenPaiva

Laskentaa

Laskentaoperaatiot ovat varsin suoraviivaisia: +, -, * ja /. Erikoisempana operaationa on %, joka on jakojäännös, eli modulo. Laskentajärjestys on myös varsin suoraviivainen: operaatiot lasketaan vasemmalta oikealle sulut ym. huomioon ottaen.

eka = 2;
toka = 4;
summa = eka + toka;

println(summa);
sulut = (1+1) + 3 * (2+5)   # 23
suluitta = 1+1 + 3 * 2+5    # 13

Operaatioita voidaan suorittaa lähes missä tahansa kohdassa ohjelmakoodia.

eka = 2;
toka = 4;

println(eka+toka);
println(2 + toka - eka - toka);

Liukuluvut

Jako ja jakojäännös ovat hieman hankalampia. Liukuluku ja kokonaisluku menevät helposti sekaisin.

tulos = 3 / 2;  # tulos on nyt: 1 (kokonaisluku)
jakojaannos = 3 % 2 # jakojaannos on 1 (liukuluku)

Tulokseksi tulee liukuluku jos jakaja tai jaettava (tai molemmat) ovat liukulukuja

kunJaettavaOnLiukuluku = 3.0 / 2;  # tulokseksi: 1.5
kunJakajaOnLiukuluku = 3 / 2.0;  # tulokseksi: 1.5

Seuraava esimerkki tulostaa "1.5", sillä jaettavasta tulee liukuluku (1.0 * 3 = 3.0) ennen jakoa.

jaettava = 3;
jakaja = 2;

tulos = 1.0 * jaettava / jakaja;
print(tulos); 

Mitä seuraava tulostaa?

jaettava = 3;
jakaja = 2;

tulos = jaettava / jakaja * 1.0;
print(tulos);

Vanha arvo

Uusi arvo lasketaan aina muuttujan vanhasta arvosta.

pituus = 100;

pituus = pituus - 50;
pituus = pituus * 2;
pituus = pituus / 2;

# pituus on nyt 50

Sijoitusoperaatiot

On myös mahdollista käyttää erityisiä sijoitusoperaatioita, jotka eivät ehkä ole ainakaan aluksi niin helppolukuisia.

pituus = 100;

pituus += 10;  # pituus = pituus + 10;
pituus -= 50;  # pituus = pituus - 50;

Huomaa, että muuttuja tulee alustaa ensin (esimerkiksi nollaksi). Seuraava esimerkki ei toimi, sillä muuttujaa pituus ei ole vielä alustettu.

pituus = pituus + 100;   # ei toimi!
pituus += 100;  # ei toimi!

Katenointi

Jos operaatiota + sovelletaan kahden merkkijonon välille, syntyy uusi merkkijono, jossa kaksi merkkijonoa on yhdistetty. Huomaa nokkela välilyönnin käyttö lauseen "muuttujien" osana!

tervehdys = "Hei ";
nimi = "Matti";
hyvästely = ", ja näkemiin!";

lause = tervehdys + nimi + hyvästely;

println(lause);

Jos toinen operaatio + kohteista on merkkijono, syntyy uusi merkkjono, jossa esimerkiksi kokonaisluku 2 on muutettu merkkjonoksi "2" ja tähän yhdistetty haluttu merkkijono.

println("tuossa on kokonaisluku --> " + 2);
println( 2 + " <-- tuossa on kokonaisluku");

Edellä esitellyt laskusäännöt pätevät täälläkin:

println("Neljä: " + (2+2));
println("Mutta! kaksikymmentäkaksi: " + 2 + 2);

Syötteen lukeminen

Tähän asti ohjelmamme ovat olleet kovin yksipuolisia. Seuraavaksi luemme syötettä käyttäjältä. Käytämme syötteen lukemiseen erityistä Lukija-apuvälinettä.

print("Nimesi: ");
nimi = Lukija.nextLine();   # Luetaan käyttäjältä rivi tekstiä

print("Kuinka vanha olet: ");
ika = Lukija.nextInt();     # Luetaan käyttäjältä koknaisluku

println("Nimesi on siis: " + nimi + ", ja ikäsi " + ika + ", hauska tutustua.");

Valinta ja totuusarvot

Jotta ohjelman suoritus voisi haarautua, tarvitsemme käyttöömme valintakäskyn.

luku = 11;

if ( luku > 10 ) then
  println("Lukusi oli suurempi kuin 10");
end

Ehto ( luku > 10 ) muuntautuu totuusarvoksi true tai false. Valintakäsky if käsittelee siis lopulta vain ja ainoastaan totuusarvoja.

Huomaa, että if -lauseen perään ei tule puolipistettä, sillä lause ei lopu ehto-osan jälkeen.

Ehdon jälkeen sana then aloittaa lohkon (block), jonka sisältö suoritetaan jos ehto on tosi. Lohko loppuu sanaan end. Lohko voi olla kuinka pitkä tahansa.

Vertailuoperaattoreita ovat seuraavat:

Lohkon sisällä voi olla mitä tahansa koodia, kuten toinen valintakäsky. Mikä looginen virhe seuraavassa esimerkissä on?

vuosi = 2010;
kuukausi = 1;

println("Tällä hetkellä seuraavat kurssit ovat käynnissä:");

if ( vuosi == 2010 && kuukausi == 1 ) then
  println("Ohjelmoinnin perusteet");
  
  if ( vuosi == 2010 && kuukausi == 3 ) then
    println("Ohjelmoinnin jatkokurssi");
  end
end

Vertailuoperaattoreita voi käyttää myös ehtojen ulkopuolella. Tällöin ehdon totuusarvo asettuu totuusarvomuuttujaan.

eka = 1
toka = 3

onkoSuurempi = eka > toka

Yllä olevassa esimerkissä onkoSuurempi sisältää nyt totuusarvon false.

else

Jos valinnan ehto on epätotta, voidaan suorittaa toinen vaihtoehtoinen lohko koodia, tämä käy sanan else avulla.

luku = Lukija.nextInt();

if ( luku > 5 ) then
  println("Lukusi on suurempi, kuin viisi!");
else
  println("Lukusi on viisi tai alle!");
end

Loogiset operaatiot

print("Anna luku väliltä 5-10: ");
luku = Lukija.nextInt();

if ( luku > 4 && luku < 11 ) then
  println("Kiitos!");
else
  println("Luku oli jotain muuta.. :(")
end
print("Valitse joko 1, 50 tai 100: ");
valinta = Lukija.nextInt();

if ( valinta == 1 || valinta == 50 || valinta == 100 ) then
  println("Valitsit ohjeen mukaisesti.");
else
  println("Valitsit jotain muuta.");
end

Joskus on kätevää pilkkoa logiikkaa useampaan osaan, tällöin koodi on luettavampaa.


print("Älä valitse lukua 100, eikä lukua 10.");
valinta = Lukija.nextInt();

if ( valinta != 100 ) then
  totteliko = true;
end

if ( totteliko && ( valinta != 10 ) then
  println("Hyvin valittu.");
else
  printnt("Valitsit sitten kuitenkin 100 tai 10");
end

Toinen versio:

if ( valinta != 100 && valinta != 10 ) then
  totteliko = true;
end

if ( totteliko ) then
  println("Hyvin valittu.");
else
  printnt("Valitsit sitten kuitenkin 100 tai 10");
end

elsif

Sana elsif on kuten else, mutta lisäehdolla. elsif mahdollistaa myös else:n ketjutuksen.

valinta = Lukija.nextInt();

if ( valinta == 1 ) then
  println("Valitsit 1");
elsif ( valinta == 2 ) then
  println("Valitsit 2");
elsif ( valinta == 3 ) then
  println("Valitsit 3");
end

Erikoistilanteita

Seuraavissa esimerkeissä esitellään muutama erikoisehto jotka ovat voimassa ainakin seuraavat kaksi viikkoa.

if ( true ) then
  print("Aina totta, suoritetaan aina.");
end

if ( false ) then
  print("Aina epätotta, ei suoriteta koskaan.");
end

if ( tuntematonMuuttuja ) then
  print("Muuttuja on tuntematon, tämä on sama kuin false.");
end

if ( 0 ) then 
  print("Ehdossa on olemassa arvo (ei tuntematon), tämä on sama kuin true.");
end

luku = 42144;
if ( luku = 82133 ) then
  println("Ehdossa on vain yksi yhtäsuuruusmerkki kahden sijasta.");
  println("Tämä onnistuu, joten lopullinen arvo on true.");
end

Toiston alkeet

while

Komento while toistaa lohkonsa koodia, niin kauan kun määritelty ehto on voimassa. Komennon while ehto-osa toimii kuten if:ssä.

while:n lohko alkaa sanalla do ja loppuu sanaan end.

Seuraavassa esimerkissä tulostetaan luvut 1,2,..,9,10. Kun luku-muuttuja saa arvokseen yli 10, while-ehto ei ole enää voimassa ja toistaminen lopetetaan.

luku = 1;

while (luku < 11) do
  println(luku);
  luku = luku + 1;
end

Lohkossa luemme käyttäjältä luvun ja suoritamme lohkon aina kunnes käyttäjä syöttää luvun 3.

println("Anna luku 3");

luku = 0;

while( luku != 3 ) do
  luku = Lukija.nextInt();
end

Sama toiminnallisuus toisella tavalla tehtynä

println("Anna luku 3");

eiOleKolme = true;

while( eiOleKolme ) do
  luku = Lukija.nextInt();

  if ( luku == 3 ) then
    eiOleKolme = false;
  end
end

Seuraavassa esimerkissä aloitamme laskemisen 0:sta ja toistamme while lohkoa, kunnes olemme lukeneet neljä lukua, jolloin ehto ei ole enää voimassa.

println("Anna kolme lukua ja kerron niiden summan");

lukuja = 0; summa = 0;

while ( lukuja < 3 ) do
  luku = Lukija.nextInt();
  summa = summa + luku;   # tai summa += luku;
  lukuja = lukuja + 1;    # tai lukuja += 1;
end

println("Lukujen summa on: " + summa);

Yksi suosituimmista ohjelmointivirheistä on ohjelmoida jompi kumpi seuraavista esimerkeistä:

Ikuisuus

ikuisuus = true;

while(ikuisuus) do
  println("Odota, suoritus saattaa kestää hetkisen..");
end

Saavuttamaton koodi

eiKoskaan = false;

while(eiKoskaan) do
  println("En suoritu koskaan");
end

Taulukko

Taulukko on muuttuja, joka voidaan käsittää eräänlaisena järjestettynä lokerikkona arvoille. Taulukon pituus tai koko on lokerikon paikkojen lukumäärä, eli kuinka monta arvoa taulukossa on.

Taulukon arvoja sanotaan yleisemmin taulukon alkioiksi. Kolmen alkion taulukko määritellään seuraavasti.

luvut = [100,1,42];

Taulukon arvot voivat olla mitä tahansa aikaisemmin esiteltyjä tyyppejä.

tekstitaulukko = ["Matti P.", "Matti V."];
liukulukutaulukko = [1.20, 3.14, 100.0, 0.6666666667];

Taulukon alkioihin voidaan osoittaa indeksillä, joka on kokonaisluku. Indeksi kertoo paikan taulukon sisällä. Taulukon ensimmäinen paikka on nolla, seuraava yksi ja niin edelleen. Indeksi (=kokonaisluku) annetaan taulukkomuuttujan perään hakasulkeiden sisällä.

# indeksi  0 1  2  3 4 5    6    7
luvut = [100,1,42,23,1,1,3200,3201];

print(luvut[0]);	# tulostaa 100
print(luvut[2]);	# tulostaa 42

Yllä olevan taulukon koko (tai pituus) on 8.

Taulukkoon voidaan asettaa alkio indeksin määrittelemään kohtaan. Asetus tapahtuu kuten aikaisemmin esitellyillä muuttujilla.

luvut = [100,1,42];

luvut[1] = 101;
luvut[0] = 1;

# luvut-taulukko on nyt [1,101,42]

Jos indeksillä osoitetaan taulukon ohi, niin saadaan arvo nil, joka kuvaa tyhjää. Siirryttäessä Javaan taulukon ohi ei enää saa osoittaa.

Taulukon läpikäynti

Taulukko voidaan käydä läpi indeksimuuttujan avulla. Aloitetaan nollasta, kasvatetaan indeksiä yhdellä ja lopetetaan läpikäynti, kun indeksi kasvaa yli taulukon koon. Taulukon koon saamme kysyttyä suoraan taulukolta: taulukko.size, joka on taulukon alkioiden lukumäärä kokonaislukuna.

luvut = [1,8,10,3,5];

indeksi = 0;
taulukon_koko = luvut.size;
while ( indeksi < taulukon_koko ) do
	println(luvut[indeksi]);
	indeksi = indeksi + 1;
end

for

Seuraavaksi esitellään toinen tapa käydä taulukko läpi. Tässä tavassa indeksimuuttujaa ei tarvita. Komento for toimii kuten while, mutta ehtoa ei tarvita. Muuttuja luku saa arvokseen jokaisella kierroksella yhden alkion luvut-taulukosta. Alkioiden läpikäynti tapahtuu siinä järjestyksessä missä ne taulukossa sijaitsevat

luvut = [1,8,10,3,5];

for luku in luvut do
  println(luku);
end
nimet = ["Matti P.", "Matti V.", "Matti L."];

for nimi in nimet do
  println(nimi);
end

Taulukko järjestetyn tiedon säilyttäjänä

Seuraavassa "yhdistämme" kaksi taulukkoa siten, että kahdessa taulukossa on yhtä monta alkiota ja jokainen alkio liittyy toisen taulukon vastaavan indeksin alkioon. Tällöin kummassakin taulukossa on tietoa samassa järjestyksessä.

arvosanat = [3,2,1];
nimet = ["Matti P.", "Matti V.", "Matti L."];

indeksi = 0;
while ( indeksi < arvosanat.size ) do
  println( nimet[indeksi] + ": " + arvosanat[indeksi] );
  indeksi = indeksi + 1;
end	

Taulukko on myös kätevä apuväline esimerkiksi hyväksyttävien arvojen säilyttämiseen. Seuraavassa esimerkissä asetamme hyväksytyt arvot taulukkoon, kysymme käyttäjältä luvun ja käymme kaikki luvut läpi tarkistaen samalla, onko käyttäjän antama luku hyväksytty vai ei.

	
hyvaksyttavatLuvut = [4,8,10];

print("Valitse 4,8 tai 10: ");
valinta = Lukija.nextInt();

totteliko = false;

for luku in hyvaksyttavatLuvut do

  if ( luku == valinta ) then
    totteliko = true;
  end

end

if ( totteliko ) then
  println("Hyvin valittu");
else
  println("Valitsit luvun " + valinta + ", joka ei ollut sallittu.");
end

Muunnelma edellisestä esimerkistä:

luvut = [3,8,9,14];

println("Minulla on neljä lukua väliltä 1-15.");

print("Arvaa luku 1-15 välillä: ");

arvaus = Lukija.nextInt();

for luku in luvut do
  if ( luku == arvaus ) then
    print("Arvasit luvun " + luku + "!");
  end
end

Sisäkkäiset taulukot

Sisäkkäinen taulukko on erikoistapaus taulukosta, jossa jokainen taulukon alkio on uusi taulukko. Sisäkkäistä taulukkoa indeksoidaan siten, että ensin määritellään ulommaisen taulukon alkio ja sitten sen sisältä löytyvän taulukon indeksi.

Sisäkkäiset taulukot tunnetaan myös nimellä moniulotteiset taulukot. Esimerkiksi kaksiulotteinen taulukko kuvataan seuraavasti:

sisakkain = [["a","b"],
             ["c","d"]];

println(sisakkain[0][1]);   # b
println(sisakkain[1][1]);   # d

Kaksiulotteisen taulukon voi ajatella koostuvan riveistä ja sarakkeista. Yllä olevassa taulukossa ensimmäisellä rivillä on alkiot a ja b. Toisessa sarakkeessa on alkiot b ja d.

Kuten aikaisemmin, myös asetus tapahtuu samalla tavalla.

sisakkain = [["a","b"],
            [["d","e"]];

sisakkain[1][0] = "b";
sisakkain[1][1] = "a";

# sisakkain on nyt:  [["a","b"],
#                    [["b","a"]]

Kaksiulotteinen taulukko on kätevä esimerkiksi koordinaateissa. Seuraavassa esimerkissä ristinolla kuvataan kaksiulotteisena taulukkona siten, että jokainen rivi rakennetaan yksiulotteisena taulukkona ja näistä riveistä rakennetaan kaksiulotteinen taulukko.

rivi1 = [1,1,0];
rivi2 = [0,1,1];
rivi3 = [1,0,0];

ristinolla = [rivi1,
              rivi2,
              rivi3];

print(ristinolla[2][2]);  # Tulostetaan oikea alakulma (0)
print(ristinolla[0][2]);  # Tulostetaan oikea yläkulma (0)

Läpikäynti indeksien avulla

Läpikäyntiin tarvitsemme kaksi indeksimuuttujaa: indeksin nykyiselle riville ja nykyiselle sarakkeelle. Seuraavassa esimerkissä käydään läpi aakkosia taulukosta riveittäin. Rivin kaikki sarakkeet käydään läpi ja taulukossa oleva arvo tulostetaan.

aakkoset = [["a","b","c","d"],
            ["e","f","g","h"],
            ["i","j","k","l"],
            ["m","n","o","p"]];


riviIndeksi = 0;
while ( riviIndeksi < 4 ) do

  sarakeIndeksi = 0;
  while ( sarakeIndeksi < 4) do
    print(aakkoset[riviIndeksi][sarakeIndeksi]);
    sarakeIndeksi = sarakeIndeksi + 1;
  end

  println("");
  riviIndeksi = riviIndeksi + 1;
end
abcd
efgh
ijkl
mnop

Läpikäynti ilman indeksejä

Komentoa for voi käyttää myös sisäkkäisten taulukkojen kanssa.

matit = ["Matti P.", "Matti L.", "Matti N."];
artot = ["Arto V.", "Arto W."];

kaikkiNimet = [matit, artot];

for samatEtunimet in kaikkiNimet do
  println("Seuraavilla on samat etunimet:\n");

  for samaEtunimi in samatEtunimet do
    println(samaEtunimi);
  end

  println("\nSiinä kaikki.\n")
end
Seuraavilla on samat etunimet:

Matti P.
Matti L.
Matti N.

Siinä kaikki.

Seuraavilla on samat etunimet:

Arto V.
Arto W.

Siinä kaikki.

Funktiot

Ohjelmoinnissa funktioilla on suuri rooli. Funktioita käytetään paketoimaan suoritettavaa koodia omiin toistetaviin yksiköihinsä.

Kuten muuttuja, myös funktio tulee määritellä ennen sen käyttöä.

def tervehdi()
  println("Terveiset funktiomaailmasta!");
end

println("Kokeillaan pääsemmekö funktiomaailmaan:")
tervehdi();

println("Näyttää siltä, kokeillaan vielä:");
tervehdi(); tervehdi(); tervehdi();

Parametrit

Funktiosta saa huomattavasti monikäyttöisemmän antamalla sille parametreja. Parametrit ovat kuin muuttujia, jotka annetaan funktion määrittelyssä. Kun funktiota kutsutaan, annetaan parametrille arvo.

Seuraavassa esimerkissä määritellään funktio ja kutsutaan sitä kahdesti siten, että parametriin nimi asetetaan ensimmäisellä kerralla arvoksi Matti ja toisella kutsukerralla Arto.

def tervehdi(nimi)
  println("Hei " + nimi + ", terveiset funktiomaailmasta");
end

tervehdi("Matti");
tervehdi("Arto");

Funktion parametrejä voidaan antaa funktion määrittelyssä useita. Tällöin funktion kutsussa parametrit annetaan samassa järjestyksessä.

def tervehdi(nimi,mistaTerveiset)
  println("Hei" + nimi + ", terveiset " + mistaTerveiset);
end

kuka = "Matti";
terveiset = "Kyröjoelta";

tervehdi(kuka, terveiset);
tervehdi(kuka, terveiset + " ja Kumpulasta");

Jälkimmäisessä tervehdi-funktion kutsussa toinen parametri muodostetaan katenoimalla muuttujaan terveiset teksti " ja Kumpulasta". Tämä suoritetaan ennen varsinaista funktion suoritusta.

Hei Matti, terveiset Kyröjoelta
Hei Matti, terveiset Kyröjoelta ja Kumpulasta	

Paluuarvot

Funktio voi palauttaa jonkin arvon. Edellä olevissa esimerkeissä funktiot eivät palauttaneet mitään. Paluuarvon voi määritellä komennolla return.

Seuraavassa esimerkissä käytetään funktiota summan laskemiseen. Summa palautetaan paluuarvona ja tämä asetetaan muuttujaan.

def summa(eka, toka)
  return eka+toka;
end

eka = 2000;
toka = 10;

mikaVuosi = summa(eka, toka);
println(mikaVuosi);

Laajennetaan edellistä esimerkkiä siten, että käyttäjä syöttää luvut kuten ensimmäisissä harjoituksissa.

def summa(eka, toka)
  return eka+toka;
end

print("Anna ensimmäinen luku: ");
a = Lukija.nextInt();

print("Anna toinen luku: ");
b = Lukija.nextInt();

print("Luvut ovat yhteensä: ");
println(summa(a,b));

Seuraavassa esimerkissä funktio summa saa parametreikseen kaksi kokonaislukua paluuarvoina.

def summa(eka, toka)
  return eka+toka;
end

a = 3;
b = 2;

summa(summa(1,2), summa(a,b));
# 1) suoritetaan uloimman funktion sisällä olevat funktiot
#    summa(1,2) = 3   ja summa(a,b) = 5
# 2) suoritetaan uloin summa-funktio:
#    summa(3,5) = 8 

Näkyvyys

Funktion sisäiset muuttujat ja parametrit ovat olemassa vain funktion sisällä. Myöskään funktion ulkopuolella määritellyt muuttujat eivät näy funktion sisälle. Seuraavassa esimerkissä määritellään muuttuja x ja funktio, joka kasvattaa (samannimistä, mutta ei samaa!) parametria x.

def kasvataKolmella(x)
  x = x + 3;
  return x;
end

x = 1;
kasvatettu = kasvataKolmella(x);

println(x);             # tulostaa 1, eli ei muuttunut
println(kasvatettu);    # tulostaa 4

Uudelleenkäytettävyys

Funktiosta saadaan uudelleenkäytettävä siten, että se ei ota kantaa ohjelmaan jossa sitä käytetään. Tällöin toimiva ja testattu funktio voidaan uudelleenkäyttää missä ohjelmassa tahansa.

Seuraavassa teemme funktion, joka käy parametrinään saadun taulukon läpi ja palauttaa true jos kaikki arvot olivat positiivisia.

def onkoKokonaanPositiivinen(taulukko)
  oliko = true;

  for arvo in taulukko do
    if ( arvo < 0 ) then
      oliko = false;
    end
  end

  return oliko;
end

lokerikko = [1,3,-1,3];

if ( onkoKokonaanPositiivinen(lokerikko) ) then
  println("Lokerikko on kokonaan positiivinen");
else
  println("Lokerikko ei ole kokonaan positiivinen");
end

Kaksiulotteisen taulukon tulostus erotetaan omaksi funktiokseen.

def kaksiulotteisenTaulukonTulostaja(taulukko)
  for rivi in taulukko do
    for sarake in rivi do
      print(sarake);
    end
    println();
  end
end


aakkoset = [["a","b","c","d"],
            ["e","f","g","h"],
            ["i","j","k","l"],
            ["m","n","o","p"]];

rivi1 = [1,1,0];
rivi2 = [0,1,1];
rivi3 = [1,0,0];

ristinolla = [rivi1,
              rivi2,
              rivi3];


kaksiulotteisenTaulukonTulostaja(aakkoset);
kaksiulotteisenTaulukonTulostaja(ristinolla);