librelist archives

« back to archive

Closures a través de reloads

Closures a través de reloads

From:
Nahuel Greco
Date:
2010-07-05 @ 05:22
Encontré un comportamiento un poco extraño, sobre el que no vi nada de
documentación:

0- Cargo un módulo m.
1- Arranco un proceso definido en m que crea una closure, que utiliza
una función de ese mismo módulo.
2- La ejecuto y queda en memoria.
3- Hago ciertas modificaciones al source de m.
4- Recargo m.
5- La vuelvo a ejecutar (la misma que fue creada en el paso 1)

Aquí lo que observo es que, dependiendo de qué modificaciones haya
hecho en el paso 3, la closure en el paso 5 va a apuntar a funciones
de la versión vieja _o_ nueva del módulo. También observé que se
pueden cambiar los bindings de la closure en el paso 3. Detallando:

Test 2: Si se cambia el body de una función de m, usada por la
closure, la closure utilizara la _nueva_ versión de m.
Test 3: Si se redefine el nombre de esa función, redefiniendo el body
de la closure, la closure utilizará la _vieja_ versión de m
Test 4: Si se cambia un literal dentro de la closure, la closure
utiliza la _vieja_ versión de m
Test 5: Si se cambia el valor asignado a una variable bindeada desde
la closure, la closure utiliza la _nueva_ versión de m _con el nuevo
valor definido_.

No encuentro una sémantica clara, y tampoco la vi documentada. Qué piensan?

Adjunto un test.erl que va compilando y cargando/recargando las
diferentes versiones de m, realizando los tests 2 a 5 que detallé
antes. La versión original del módulo que siempre carga en el paso 0
es m__base.erl, y la que carga en el paso 4 es m__[2-5].erl
alternativamente.

Output:

Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0]
[kernel-poll:false]
Eshell V5.7.5  (abort with ^G)
1> c(test).
{ok,test}
2> test:start().

- Unloading m old and current
- Loading m__base and starting process
Started a() from version 1
From closure, version() -> 1, B -> first
- Loaded m__2 , differences with base: Increments the version
- Continuing process
From closure, version() -> 2, B -> first

- Unloading m old and current
- Loading m__base and starting process
Started a() from version 1
From closure, version() -> 1, B -> first
- Loaded m__3 , differences with base: Increments the version,
version/0 changed to another_version/0
- Continuing process
From closure, version() -> 1, B -> first

- Unloading m old and current
- Loading m__base and starting process
Started a() from version 1
From closure, version() -> 1, B -> first
- Loaded m__4 , differences with base: Increments the version, changed
text literal in closure
- Continuing process
From closure, version() -> 1, B -> first

- Unloading m old and current
- Loading m__base and starting process
Started a() from version 1
From closure, version() -> 1, B -> first
- Loaded m__5 , differences with base: Increments the version, changed
B assigned atom to 'second'
- Continuing process
From closure, version() -> 2, B -> second
[undef,undef,undef,undef]
3>



Saludos,
Nahuel Greco.