Add GLib.Async namespace with helpers for async code
I'm not very sure which file this would go into (my best guess is Gio-2.0-custom.vala) and it's an addition rather than a straight-up fix, so posting this as an issue for now.
I absolutely love Vala's support for async code. However, one of most basic tasks - sleeping for a fixed amount of time - turned out to be relatively manual compared to most other functionality. Often you don't need to bother with callbacks or anything like that - just do
yield my_object.awesome_async_method(9000);
and it will work with no issues. But, somewhat surprisingly, for sleep you'll need
Timeout.add(2000, method_calling_this.callback);
yield;
Which is still just two lines - not too bad, even if wrapping this into a function would be better still and is something I do in my projects often. But if you want cancellable sleep, not wrapping this into a helper function becomes not viable anymore - and I propose to include such a function in vala - it took me surprisingly long to figure out how to do it while avoiding deadlocks, memory leaks, and more.
Here's what I propose to add:
namespace GLib {
namespace Async {
async void sleep(uint duration, Cancellable? cancellable = null) {
var timeout_src = new TimeoutSource (duration);
var cancellable_src = new CancellableSource (cancellable);
source_set_dummy_callback (cancellable_src);
timeout_src.add_child_source (cancellable_src);
timeout_src.set_callback (cancellable_sleep.callback);
timeout_src.attach (MainContext.get_thread_default ());
yield;
}
}
}
From my understanding, this should not result in race conditions even if cancellable
is cancelled from another thread.
Possible tweaks:
- Return
((!)cancellable).is_cancelled()
- allows to easily tell if call finished because of timeout or not; this method is safe to call on null objects, so forcefully indicate it as such to Vala - Add
throws IOError
, call((!)cancellable).set_error_if_cancelled()
in the end - it's customary for cancellable functions to throw relevant error if they were cancelled, so it would make sense to do it this way here too; it works fine on null objects as well