(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/92d86872d242d5176b0e616de91c339f 79ff39cc/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: # Lataa uusiksi mahdollisimman paljon, jotta ei varmasti jää mitään lataamatta. # 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.
* [merkintä: 2024-03] * [atehwa] * [kategoria: päiväkirjamerkintä] * [clojure repl with autoreload and important other niceties]