(toiminnot)

hwechtla-tl: Aina vain clojuren tiedostojen uudelleenlataus lennossa

Kierre.png

Mikä on WikiWiki?
nettipäiväkirja
koko wiki (etsi)
viime muutokset


(nettipäiväkirja 11.03.2024) Sain vihdoinkin tietää, miksi (tai oikeastaan millä tavalla) AOT-käännetyt tiedostot rikkovat reloadin clojuressa. Ne tosin rikkovat sen milloin milläkin tavalla, riippuen siitä, millä tavalla reloadin yrittää tehdä.

Lähinnä syyllinen on tämä rivi: https://github.com/clojure/clojure/blob/92d86872d242d5176b0e616de91c339f79ff39cc/src/jvm/clojure/lang/RT.java#L462 Se yrittää päätellä, kumpi on uudempi, lähdekoodi vai siitä tuotettu luokka. Ajatus on ilmeisesti se, että jos luokka on uudempi, sen lataaminen riittää, muuten pitää ladata Clojure-lähdekooditiedosto.

Tosiasiassa luokan lataaminen ei kuitenkaan vastaa lähdekooditiedoston lataamista. Luokka yrittää staattisessa alustimessa (static initialiser) samat asiat kuin mitä Clojure-lähdekoodi tekisi, mutta luokan lataaminen uudelleen ei aja staattisia alustimia uudestaan. Niinpä jää tekemättä lukuisia asioita: suorittaa toplevel-komennot, perustaa nimiavaruus ja niin edelleen. AOT-käännetyn luokan lataaminen uudelleen tarkoittaa joko sitä, että vanhat nimiavaruuden bindingit jäävät voimaan, tai sitten sitä, että niitä ei edes luoda (jos niitä ei ole olemassa).

Esimerkiksi clojure.tools.namespace.repl (joka on muuten varsin hyvä reload-kirjasto) hajoaa täysin tästä. Se yrittää ensin poistaa vanhan version nimiavaruudesta ja ladata sitten sen sisällön uudestaan. Mutta luokan lataaminen ei tuo nimiavaruutta enää takaisin, jolloin kirjaston nimet eivät ole juurikaan saatavilla.

Oikeastaan se, miten c.t.n.r hajoaa, tuo minulle mieleen, että on kaksi tapaa, jolla reloadin voi yrittää saada toimimaan clojuressa:

  1. Lataa uusiksi mahdollisimman paljon, jotta ei varmasti jää mitään lataamatta.
  2. Kirjoittaa koodin siten, että uudet määrittelyt tulevat kaikkialla käyttöön.

Tämä jälkemmäinen on paljon huonommin dokumentoitu, ja siksi melkein projektissa kuin projektissa on jossain koodia, joka ei vain toimi, kun jotain yritetään ladata uudelleen. AOT-käännös on yksi esimerkki: jos nimiavaruuden (load) ei oikeasti tuo nimiavaruutta tarjolle, ollaan aika heikoilla jäillä. Mutta muitakin on. Erityisesti aiemmin mainitsemani nimien uudelleenmäärittely clojuressa vaatii, että nimiavaruudet viittaavat toistensa sisältöön joko funktion sisällä, tai sitten nimellä. Muuten vanhaan arvoon viitataan suoraan sitä käyttävissä nimiavaruuksissa, eikä se lataudu uusiksi, kun nimiavaruus ladataan.


kommentoi (viimeksi muutettu 11.03.2024 22:37)