Re: [Vala] Implicit lamdas/closures



Christian Hergert wrote:

    Christian, when you said:
    var value = yield obj.do_something ();
    Did you mean that the lamda continuation address be implicitly
    passed to do_something()?

    When you talk of the yield returning a value, do you mean to the
    caller? So that yield is equivalent to "return" but just doesn't
    free the local vars?


I'm thinking that if a method uses the yield syntax, that calling method itself would need to be an asynchronous method.


In samba4, A proxied close request of a read-only file would be synchronous because the response could be given to the client immediately without waiting for the response from the server being proxied, but if the file had been written to then it would be an asynchronous request. Similarly for cached file reads, credential fetches etc. So the caller could not always know in advance if the full response will be given synchronously or asynchronously.

Also the caller may be in-process and request a synchronous response precisely because a state-machine setup was too complicated, and this samba code would really benefit from continuation capabilities in vala.

So sometimes, synchronous-ness is not a property of a method itself but of it's execution. A method may-or-may not give a synchronous response, and the caller would have to know how to interpret that (and does).

It also depends on the semantic context (ugh) of the caller; if it's intended only to have a distant effect then it can be said to be synchronous, even if that effect requires multi-stage processing using yield. Even a synchronous request to file-read may use yield in order to process some additionally requested read-ahead blocks, so I think your case doesn't hold in a general sense.

I can see that asynchronous methods might be meaningful to some event driven frameworks but it seems very specific.

I don't think we need (or I don't need) to especially introduce a concept of asynchronous methods, just another way to express and implement lambdas. If the lambda can be implemented as a function pointer and a void* pointer (and with libffi's trampolines we can get by with just a function pointer !) then we can cope with all cases including specific frameworks.

I'm now pressing for concensus on some aspects

Does anyone have concern with the implementation that has
* the message body with a load of goto's at the top, and then
* an entry-wrapper for the main function to setup the local vars struct,
* an entry-wrapper for each callback entry point to process additional arguments and set the goto-point
?

Are people happy that the continuation lambdas should accept parameters as lambdas currently do? Do people prefer the [out] notation of a fake yield function call to receive the extra parameters or some other notation?

If labels are out of favour (reminder)

something.callback=label_name;
return STATUS_ASYNC;
label_name(int extra_param):
do_something_with(extra_param);

is this preferred:

something.callback=yield([out] int extra_param) {
 return STATUS_ASYNC;
};
do_something_with(extra_param);


I prefer the label, because yield() isn't really a function call and making it look line one doesn't help, it's confusing that all it's arguments MUST be [out] and it only allows one callback to be setup; consider this which is possible with normal lambdas and so should be possible with continuation lambdas.

something=send_request();
if (something.async) {
 something.callback=got_result;
 something.error_handler=failed_result;
 return STATUS_ASYNC;
}
got_result:
 stash(something.result);
 result;
failed_result(int error_code):
 log_error(error_code);
 return;
}

The requirement to have "return" looks unclean only if you think that the called function is always asynchronous, which needn't be true even for non-error responses.

I'm not opposed to a yield command or a concept of asynchronous methods to do some of this automatically in simple cases, but I'm pressing for the same capabilities that lambdas currently have, as this would be prefereable to a mass of nested lambda which could do mostly the same thing (not quite) in an ugly way.

Sam




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]