gleam
gleam copied to clipboard
Invalid erlang generated when referencing a function of the same module with @external
My original goal was to "trick" the compiler to generate a fully-qualified call to local function, without requiring moving the function to another module. Fully-qualified function references are treated differently when replacing modules, and will always call current code, whereas local or anonymous funs will continue to reference the old code.
app.gleam
import gleam/io
pub fn hello() {
io.println("Hello!")
}
@external(erlang, "app", "hello")
fn hello2() -> Nil
pub fn main() {
io.debug(hello2)
}
generates this Erlang code:
-module(app).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([hello/0, main/0]).
-spec hello() -> nil.
hello() ->
gleam@io:println(<<"Hello!"/utf8>>).
-spec main() -> nil.
main() ->
gleam@io:debug(fun hello2/0).
Notice how in main, the hello2
external is not replaced by hello
, causing an Erlang compilation error:
Compiling app
/home/mel/Projects/private/gleam/app/build/dev/erlang/app/_gleam_artefacts/app.erl:16:20: function hello2/0 undefined
% 16| gleam@io:debug(fun hello2/0).
% | ^
error: Shell command failure
This also seems to cause some kind of cache invalidation problem; replacing io.debug(hello2)
with io.debug(hello2())
specifically does not re-generate the module; Instead the compiler assumes the last compilation succeeded and tries to run the module without the beam file existing:
Compiled in 0.04s
Running app.main
exception error: undefined function app:main/0
Removing build
and calling the function (io.debug(hello2())
) works, but the call that is generated is not fully qualified, so I had to add the other module anyways :sweat_smile: ~:purple_heart: