gleam
gleam copied to clipboard
Raise a compile error if a module would have the same name as an existing Erlang module
Heyo,
So I was playing around with some of the erlang file
functions, and I noticed some interesting behaviour when it came to naming my file file.gleam
.
When importing a module that has the same name as the erlang
module that is being referenced in external
function declarations, the resulting erlang
call ends up failing with exception error: undefined function file:open_file/2
.
Here is an example, I have file.gleam
as follows:
import gleam/erlang/charlist.{Charlist}
pub external type Reason
pub external type IODevice
pub external fn read_file(String) -> Result(String, Reason) =
"file" "read_file"
pub type FileMode {
Write
}
pub external fn open_file(String, FileMode) -> Result(IODevice, Reason) =
"file" "open"
pub type WriteResult {
Ok
Error(Reason)
}
pub external fn write_file(IODevice, Charlist) -> WriteResult =
"file" "write"
which compiles to the following erlang:
-module(file).
-compile(no_auto_import).
-export([read_file/1, open_file/2, write_file/2]).
-export_type([reason/0, io_device/0, file_mode/0, write_result/0]).
-type reason() :: any().
-type io_device() :: any().
-type file_mode() :: write.
-type write_result() :: ok | {error, reason()}.
-spec read_file(binary()) -> {ok, binary()} | {error, reason()}.
read_file(A) ->
file:read_file(A).
-spec open_file(binary(), file_mode()) -> {ok, io_device()} | {error, reason()}.
open_file(A, B) ->
file:open(A, B).
-spec write_file(io_device(), gleam@erlang@charlist:charlist()) -> write_result().
write_file(A, B) ->
file:write(A, B).
and within an escript example.gleam
I have:
import file
pub external type CharList
pub fn main(_args: List(CharList)) {
file.open_file("test.txt", file.Write)
}
The result being:
escript: exception error: undefined function file:open_file/2
in function escript:run/2 (escript.erl, line 750)
in call from escript:start/1 (escript.erl, line 277)
in call from init:start_em/1
in call from init:do_boot/3
Now the interesting bit is when i modify the escript example.gleam
to be:
import file.{Write, open_file}
pub external type CharList
pub fn main(_args: List(CharList)) {
open_file("test.txt", Write)
}
this works perfectly fine because the compiler circumvents the use of the custom open_file
by inlining the call to open_file
to be:
file:open(<<"test.txt"/utf8>>, write).
Thanks for the report! Yes this is the two file
modules conflicting with each other. I wonder what we should do in this case... Perhaps the Gleam build tool could have a list of invalid module names for Erlang and then emit a warning or error if one is encountered?
An idea: we can keep a list of all the Erlang built in modules and then we can scan each ebin
directory of rebar3 deps to get the names of the others. If a collision is detected we can error.