Anselista oikealle

logo

Naulaa kielen läpi

Nykyään kun törmään johonkin KieliA vs. KieliB -vertailuun, tekee minun mieli lähinnä kääntää lehden sivua/käyttää 'takaisin' -nappulaa selaimessa. Tämä johtunee siitä että olen itse syyllistynyt yhteen jos toiseenkin 'vertailuun', erinäisissä yhteyksissä. Kun miettii niitä jälkeenpäin, tulee vain nolo olo, 'voiko kieltä ymmärtää näin väärin'.

Kun olen nyt kääntänyt yhtä pientä peliä python/GTK -ympäristöstä Java/MIDP:hen, niin näiden kahden kielen ja näyttökitin erot ovat tulleet hyvin selkeiksi. Etenkin kun alunperin ohjelma on kirjoitettu noin vuosi sitten, niin en silloin tajunnut pythonia lähellekään niin hyvin kuin nyt. Vieläkään en tajua sitä niin hyvin kuin haluaisin.

Mutta otetaan esimerkkien kautta. Konteksti on siis peli jossa on kaksiulotteinen kenttä (miinaharava). Kentällä käytetään usein funktioita joita varten pitää käydä jonkun ruudun koko ympäristö läpi, kuitenkin niin ettei keskellä olevaa ruutua oteta huomioon. Perustoteutus on tällainen:

class Board {
    ...
    public void addToBoard (int x, int y, int value) {
	   for (int dy = -1; dy <= 1; dy++)
	       for (int dx = -1; dx <= 1; dx++)
		   if (! (dx == 0 && dy == 0))
		      addSingle (x + dx, y + dy, value);
    }
    ...
}
Python -toteutus tuosta on melko lailla identtinen. Nuo for:t ja if:t toistuvat siis jokaisessa ympäristöä läpikäyvässä funktiossa. Rumaa.

Python on kuitenkin tietorakenteiltaan joustavampi ja tarjoaa ueamman tavan tehdä asia ymmärrettävämmin:

NEAR_DELTA = [-1, 0, 1]
class Board:
    ...
    def add_to_board (self, x, y, value):
	for dy in NEAR_DELTA:
	    for dx in NEAR_DELTA:
		if not (dx == 0 and dy == 0):
		   self.add_single (x + dx, y + dy, value)
    ...
Mutta miksi tehdä tuota testiä kun voidaan yksinkertaisesti sanoa:
NEAR_DELTAS = [[-1, -1], [-1, 0], [-1, 1], [0, -1], 
               [0, 1], [1, -1], [1, 0], [1, 1]]
# huomaa että [0, 0] ei kuulu joukkoon, testi siis turha.
class Board:
    ...
    def add_to_board (self, x, y, value):
	for dx, dy in NEAR_DELTAS:
	    self.add_single (x + dx, y + dy, value)
    ...
ja toisaalta, tuo looppi on oikeasti monessa paikassa, olisi hyvä jos voisi sanoa 'tee tällaista tälle ympäristölle':
NEAR_DELTAS = ...
class Board:
    def traverse_neighbours (x, y, cb_function):
        for dx, dy in NEAR_DELTAS:
	    cb_function (x + dx, y + dy)

    def add_to_board_alternative (self, x, y, value):
        self.traverse_neighbours (x, y, lambda nx, ny: self.add_single(nx, ny, value))

    def add_to_board (self, x, y, value):
	def add_internal (nx, ny):
	    self.add_single (nx, ny, value)
        self.traverse_neighbours (x, y, add_internal)
    ...
Tuossa 'alternative' käyttää perinteisempää lambda-muotoa. Jälkimmäinen muoto voi näyttää pidemmältä kirjoittaa, mutta tuossa on jätetty sen verran toteutusteknisiä yksityiskohtia pois että se ei kerro oikeastaan mitään, pythonin lambda on myös muutenkin rajoitettu ja sitä ehdotetaankin korvattavaksi sisäkkäisillä funktioilla.

Tuo ei ole tietääkseni ollenkaan mahdollista Java:ssa sellaisena kuin se on MIDP 2.0 -koneissa. Se on ehkä hyväkin asia, Java kun sellaisena vaatii vähemmän tehoa/muistia, mutta vuosi on 2006 ja ohjelmointikieleltä voisi haluta sekä luettavuutta että mukavuutta.

28/01/2006 @ 23:33 | /anseli/code/kielivertailut | Kirj. 0 | #
Kommentit:

Voit tarkistaa HTML:n ja CSS:n oikeellisuuden.