Re: [m-users.] Ignoring !IO in an FFI binding, aceptable or hideously bad?
M McDonough <[email protected]> Sun, 16 Feb 2025 17:25:34 -0800
| Newsgroups | gmane.comp.lang.mercury.general |
|---|---|
| Message-ID | <CAJpH_7+hd_om0txC3Lhh_-pvUC=UcxYgY4v1jS0_Nx7sJ3YWcQ@mail.gmail.com> |
> On 16 Feb 2025, at 11:38, Sean Charles (emacstheviking) <[email protected]> wrote: > 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: The way you should generally get around this is by including the IO state in the native code (you can simply ignore the IO variables, or assign the output to the input to make it "feel" correct) or make the predicate impure. You really shouldn't lie to the compiler about the IO-ness of an operation. This means that all asset loading will need IO or be impure. This is correct, because it does. It's also useful for anyone using the library, as they can see the true nature of what they are doing. This sometimes will work OK to lie about this kind of thing because the Mercury compiler is greedier about including unnecessary statements and keeping your statements in the source code order than some languages, but you can get correctness issues if you abuse this. This is a very easy footgun you can see with the bitmap and array modules of the stdlib, with which it is very easy to get unpredictable or unexplainably incorrect results. > 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: From my game projects in Mercury, I've come to believe that it's really best to not do any of this. Have the code that needs assets call the reading/loading functions with the name/path/descriptor of exactly what it needs, and have them manage where the assets go. If they call it twice, then they get a second copy, because that's what they asked for (and might be what they want, for a variety of reasons). Importantly, this makes it easier for the calling code (or another module or system you add to your library) to handle things like resolving dependencies and ensure certain assets are only loaded once (if that is, in fact, what they want). My method for managing this was to build up a set of the asset names for each asset type, and then map that to an assoc_list of io.res(T) of the assets loaded, then process that and convert it to either a tree of the loaded assets, or print all errors that were found and exit. This helped a lot with keeping the asset loading code separate from the dependency management, and keep things that use IO sectioned off from things that don't. This was huge because asset loading was the slowest part of my game engine (the only operation that wasn't "instant"), and this also let me easily parallelize it with very little extra effort (especially big for loading sound files, that part was what made my games go from instantly starting to the user waiting a second or more for it to begin). I wouldn't want to bake that kind of thing into every asset loading component, and really I wouldn't want to make any of it implicit either. _______________________________________________ users mailing list [email protected] https://lists.mercurylang.org/listinfo/users