[m-users.] Ignoring !IO in an FFI binding, aceptable or hideously bad?

Sean Charles (emacstheviking) objitsu at gmail.com
Tue Feb 18 05:33:13 AEDT 2025


Mark, Zoltan, thanksz for your time.

Mark, your solution seems a good one for me.

I also later saw thaqt as the module mutable initialisation occursa before I call my explicit lo\ad, that in fact it was never going to work as I had though anyway!

Zoltan, case "A" is me: one time init. of fonts, for lifetime of application then unload and quit on user command.

I do recall at least one or two instances in the manuals about the penalty for "lying to the compiler" !

So, I shall use the same techniques I used inmy POC video space shooter game and make sure I never lie to the compiler, after all, it's got my back!

Thanks all.
Happy belated 2025 too.

My 6th year begind as a Mercury user IIRC.

> On 16 Feb 2025, at 11:38, 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.
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20250217/3d8d3c24/attachment-0001.html>


More information about the users mailing list