[m-users.] Ignoring !IO in an FFI binding, aceptable or hideously bad?
Mark Brown
mark at mercurylang.org
Mon Feb 17 14:43:27 AEDT 2025
Hi Sean,
The project I work on needs to dynamically load some libraries, and we
use mutables to store handles to the libraries that internally refer
to the state. This might not be exactly applicable to your situation,
but hopefully this can give you some ideas. Here's some of the code
for libdatrie (from a module named datrie.m):
:- type datrie_status
---> datrie_init
; datrie_failed
; datrie_linked(dynlib).
:- mutable(datrie_status, datrie_status, datrie_init, ground,
[untrailed, attach_to_io_state]).
The 'dynlib' type is from the module that generically handles loading
of libraries, and represents a handle to the loaded library which can
be used to bind library symbols. The code that uses these symbols
first has to check the status, loading the library if it isn't already
loaded, or returning an error value if loading previously failed.
You can use module initialisation to ensure the library is loaded at
startup (see the Modules chapter of the reference manual), but we
chose not to do that for two reasons:
- module initialisation doesn't guarantee any particular order
- we only want the libraries to be loaded if they're needed
We do use module finalisation for some cleanup, however.
We attached it to the I/O state because the results depend on the
state of the world. A user can delete the library from the filesystem
while their program is running, for example, and we intend for our
program to behave differently as a result.
Hope that helps!
Mark
On Sun, Feb 16, 2025 at 10:39 PM Sean Charles (emacstheviking)
<objitsu at gmail.com> wrote:
>
> Hello,
>
> I have a not insignificant binding to Raylib now, and during a recent bit of experimental coding, I decided on trying a different way to manage assets, in this case fonts.
>
> :- import_module raylib.
> :- type font_state
> ---> font_state(
> default :: rfont,
> main :: rfont
> ).
> :- mutable(fstate, maybe(font_state), no, ground, [untrailed]).
>
> I am forced to initialise to `no` because until the Raylib library is initialised, loading fonts doesn't work, however, I have experimented with a second version of load_font in my binding that does not use !IO:
>
> 1162
> 1163 :- pragma foreign_proc(
> 1164 "C", load_font2(FontName::in, Out::out),
> 1165 [ promise_pure, will_not_call_mercury, will_not_throw_exception
> 1166 , will_not_modify_trail, thread_safe, does_not_affect_liveness
> 1167 ],
> 1168 "
> 1169 void* p = MR_GC_malloc_uncollectable(sizeof(Font));
> 1170 Out = p;
> 1171 Font font = LoadFont(FontName);
> 1172 memcpy(p, &font, sizeof(Font));
> 1173 ").
>
> They both work, and it means that I can now load fonts by adding an initialise call to the module and then loading fonts without having an !IO context. I think I might change the mutable to be a `univ` on the grounds that after module initialisation, I know it will contain a fully populated `font_state`. I envisaged the new call looking something like this:
>
> :- mutable(fstate, font_state,
> font_state(
> load_default_font,
> load_a_font("path/to/main/font.ttf")
> ),
> ground,
> [untrailed]
> ).
>
> ...but I would have to write a function shim as well
>
> :- func load_a_font(string::in) = (rfont::out) is det.
> load_a_font(Path) = F :-
> load_font(Path, F). % No !IO context!
>
>
> Sorry for rambling thus far, but my question is this: if I remove "!IO" from all of my binding to Raylib, what price might I pay in my code? The Raylib environment is hidden inside the library, any allocations it does are not known to Mercury, so what possible problems might I face if Mercury sees the same bunch of `det` calls but they don't need IO state in and out? Is that "lying" to Mercury in such a way as it could cause subtle issues, I am writing an IDE so it's a non-trivial project.
>
> Or should I only remove IO from the asset loading functions?
>
> I am just looking for ideas / advice etc on how to proceed such that I don;t inadvertently cause myself issues by lying to the compiler.
>
> Thanks,
> Sean.
>
> _______________________________________________
> users mailing list
> users at lists.mercurylang.org
> https://lists.mercurylang.org/listinfo/users
More information about the users
mailing list