spk121 / guile-gi

Bindings for GObject Introspection and libgirepository for Guile
GNU General Public License v3.0
58 stars 7 forks source link

[RFE] GTask, GMainLoop integration #103

Closed Bob131 closed 3 years ago

Bob131 commented 3 years ago

Having quite enjoyed making use of 8sync's nonblocking I/O facilities (see the preface to 8sync's manual, particularly the points on delimited continuations and nonblocking I/O), I'd really like to see some supporting infrastructure for this style in guile-gi to simplify code making use of GLib's GTask and GMainLoop APIs.

However, it's unclear to me exactly how much of this should live in guile-gi itself. I have a couple of ideas (in my guess of ascending order of burden on guile-gi):

  1. guile-gi could expose some hooks in load_infos() for arbitrarily transforming SCM values before they're defined, and punt the rest off to a third-party module. This has the benefit of being quite flexible, possibly enabling/simplifying more third-party features, but it seems pretty hairy (for instance, what happens if more than one transformer hook is registered?)

  2. guile-gi could use an approach analogous to (ice-9 suspendable-ports): use the heuristics employed by other bindings to identify async methods (see this discussion for more) and expose parameters similar to wait-for-readable-port and wait-for-writable-port to be called when async methods are invoked, again punting implementation to a third-party module. This doesn't get us all the way there (doesn't cover async IO on GIOChannels done with watches, main loop timeouts, GSources in general) but would cover most GIO-based APIs.

  3. Implement everything in gi-guile itself, so (use-typelib ...) automatically produces 8sync-style automatic async modules. I have some thoughts on how this could be done, working around issues of non-suspendable continuations due to recursion through C, but I suspect they're likely to be controversial ;)

Bob131 commented 3 years ago

An option that's possibly simpler (and cleaner) than number one above would be to provide some API for mapping Scheme values to the GIBaseInfo from which they were derived. A module could then wrap guile-gi, defining a new load method which did the same transformation(s) that would have been done in a load_infos() hook. The mapping might be trickier to implement for some types than others, but at least for the method case gig_function_define1() could instantiate a subclass of <method> containing a function-info field.

spk121 commented 3 years ago

Hmm. I'd have to give it some thought.

LordYuuma commented 3 years ago

Do you really need to modify load_infos() directly? Guile-GI allows you to load merely parts of a given library into your own module, so you could for instance load all GTask-related functions and then define an 8sync-style wrapper in the same module.

Bob131 commented 3 years ago

Most functions in GLib-based libraries ending with _async and _finish are implemented using GTask. These are the functions needing wrapping. I guess one could just load every typelib on the system and use module reflection to do the wrapping, but it doesn't strike me as being terribly practical (although maybe I should try it)

LordYuuma commented 3 years ago

I don't think, this should be terribly difficult using FP. For instance, assuming _async and _finish to just be thunks for simplicity, you could

(define (async->sync _async _finish)
  (lambda ()
    (_async)
    (_finish)))

Now, for the actual implementation of whatever you're trying to do, (_async . args) will produce a GAsyncResult, that you can then pass to _finish. It may also happen, that you need to pass the first argument (the "this" pointer) to both of them. With a structure similar to this, you could e.g. launch the _async like that and then delay the _finish, producing a Scheme-style promise you can force.

Bob131 commented 3 years ago

As I said above, I've already thought about how this could be implemented. Whilst I appreciate your effort, your advice on the topic is not helpful: it's not particularly relevant to the immediate issue (using introspection to wrap asyncs rather than having to manually wrap all relevant functions from any GLib-based library that uses them), and if you actually read any of the relevant documentation you'd find that the GLib async APIs (or, in fact, any async APIs with which I'm familiar) don't work in the way you've assumed (and if they did, your suggestion would be pretty obvious).

I apologise for and genuinely regret my rudeness here, but I feel I must be frank: I'm not interested in having an endless circular discussion about how I've so clearly misunderstood every facet of the topic under consideration with someone who, from my perspective at least, doesn't appear to have taken the time themselves to try and understand the issue raised. If the miscommunication along these lines is to continue, I'd rather the bug was closed WONTFIX.

spk121 commented 3 years ago

That escalated quickly. Closed, without prejudice. Feel free to open a new issue in future if you want to discuss the issue further.