I would like to translate the C# method DelayNe below to an F# function in such a way that it can be used from C# in exactly the same way. The reason is that I want to put it in an F# library. I am struggling a lot trying to google my way to an answer, with no luck obviously.
Update: Sorry for not being clear. I have tasks that call Task.Delay in the way that you see in the DelayNe method below. The problem is that when _cancellationTokenSource.Cancel() is called, then Task.Delay throws an exception, and I don't want that exception. In other words, I believe I need a wrapper around Task.Delay which will catch the exception and silence it, but otherwise expose the behavior of Task.Delay exactly as is. And I want to implement the wrapper in F#.
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
async Task DelayNe(int milliSeconds, CancellationToken token)
{
try
{
await Task.Delay(milliSeconds, token);
}
catch (TaskCanceledException ex)
{
("Silencing " + ex.GetType().Name + ", " + ex.Message).Dump();
}
}
async Task Test(CancellationToken cancellationToken)
{
try
{
"Test start".Dump();
await DelayNe(5000, cancellationToken);
"Test stop".Dump();
}
catch (Exception ex)
{
("Catch: " + ex.Message + ", " + ex.GetType().Name).Dump();
}
}
async Task Main()
{
"Start".Dump();
_cancellationTokenSource.CancelAfter(1000);
var testTask = Test(_cancellationTokenSource.Token);
await testTask;
"Stop".Dump();
}
F# asynchronous workflows have built-in support for cancellation, so using those instead of working with tasks will probably make your life a lot easier. Your question does not really provide enough information to understand what you are trying to do, but below is an example of using async for something that is very close to your example:
let delayNe ms = async {
use! _d = Async.OnCancel(fun () ->
printfn "cancelled!")
do! Async.Sleep(ms) }
let test = async {
printfn "Test start"
do! delayNe 5000
printfn "Test stop" }
let DoWork () =
let cts = new System.Threading.CancellationTokenSource()
cts.CancelAfter(1000)
Async.StartAsTask(test, cancellationToken = cts.Token)
The DoWork function starts the work as a task, which can be easily consumed from C#.
Related
How can I use hashIt function in setter if editor gives this error
The modifier async can not by applied to the body of a setter
Future<String> hashIt(String password) async {
return await PasswordHash.hashStorage(password);
}
set hashPass(String pass) async { // error here
final hash = await hashIt(pass);
_hash = hash;
}
compiller message: Error: Setters can't use 'async', 'async*', or 'sync*'.
The reason a setter cannot be async is that an async function returns a future, and a setter does not return anything. That makes it highly dangerous to make a setter async because any error in the setter will become an uncaught asynchronous error (which may crash your program).
Also, being async probably means that the operation will take some time, but there is no way for the caller to wait for the operation to complete. That introduces a risk of race conditions.
So, it's for your own protections.
If you need to do something asynchronous inside the setter anyway, perhaps log something after doing the actual setting, you have a few options.
The simplest is to just call an async helper function:
set foo(Foo foo) {
_foo = foo;
_logSettingFoo(foo);
}
static void _logSettingFoo(Foo foo) async {
try {
var logger = await _getLogger();
await logger.log("set foo", foo);
logger.release(); // or whatever.
} catch (e) {
// report e somehow.
}
}
This makes it very clear that you are calling an async function where nobody's waiting for it to complete.
If you don't want to have a separate helper function, you can inline it:
set foo(Foo foo) {
_foo = foo;
void _logSettingFoo() async {
...
}
_logSettingFoo();
}
or even
set foo(Foo foo) {
_foo = foo;
() async {
...foo...
}();
}
Aye Aye good people,
I'm experiencing a weird behavior
when using the top level function of an isolate asynchronously;
you can find example code HERE, but in short
as top level function of an isolate this works:
String _syncHandle(int data) {
return 'done';
}
and this doesn't:
Future<String> _syncHandle(int data) async {
return 'done';
}
can anybody explain me why?
(or if should work, why isn't doing so in my code?)
thank you in advance
Francesco
...
[edit: just noticed that a similar question has been asked,
nevertheless it is still unanswered
Call async function from Isolate function,
plus issue open on github ]
forgot to update this :/
if you look at the code linked in the question
isolates_logging/lib/provider/test_isolate.dart
Future<void> _handle(int _m) async {
final response = ReceivePort();
isolateTest = await Isolate.spawn(_isolate, response.sendPort);
final sendPort = await response.first as SendPort;
final answer = ReceivePort();
sendPort.send([_m, answer.sendPort]);
await answer.first.then((p) {
_outbound.sink.add(p);});
}
static void _isolate(SendPort _initialReplyTo) {
final port = ReceivePort();
_initialReplyTo.send(port.sendPort);
port.listen((message) {
final data = message[0] as int;
final send = message[1] as SendPort;
send.send(_syncHandle(data));
});
}
}
Future<String> _syncHandle(int data) async {
return 'done';
}
note the send.send(_syncHandle(data)); part
if you do so, you can send only primitives and not futures,
basically that's it
I write a lot of async code that uses await to handle Futures.
If I have
() async {
var result = await someFuture();
}
what would be the preferred way to catch errors. Wraping the code in try/catch or doing
() async {
var result = await someFuture().catch(_errorHandler);
}
EDIT:
Also, if I have many await calls in one async method, what is the preferred catch all the errors instead of writing .catchError for eachOne.
() async {
var result = await someFuture();
var result2 = await someFuture2();
var result3 = await someFuture3();
}
According to the Dart docs if you use await wrap it in a try-catch
According to the Dart docs if you use await wrap it in a try-catch
https://dart.dev/codelabs/async-await#handling-errors
The Docs suggest just wrapping in a try-catch
Example code:
try {
print('Awaiting user order...');
var order = await fetchUserOrder();
} catch (err) {
print('Caught error: $err');
}
Reference also has a runnable example https://dart.dev/codelabs/async-await#handling-errors
I wrote a program in Dartlang that stops processing until the variable foo becomes false as shown below.
It is executable, but continuing to return Future in a while statement is clumsy.
Is there a way to write it clearly?
Future asyncMethod() async {
while (foo) {
await new Future(() {
return null;
});
}
Unity's coroutine can be written in a single line as below, so I'd like to make this much clearer.
yield return new WaitWhile(() => foo);
You are polling the variable at intervals using a timer. There are lots of ways to do that. I'd just go for the completely straight-forward implementation:
Future waitWhile(bool test(), [Duration pollInterval = Duration.zero]) {
var completer = new Completer();
check() {
if (!test()) {
completer.complete();
} else {
new Timer(pollInterval, check);
}
}
check();
return completer.future;
}
With that function, you can then just write
await waitWhile(() => foo);
to wait for foo to become false.
By using Future.doWhile.
Without a polling interval:
await Future.doWhile(() => isPaused);
With a polling interval:
if (isPaused) {
await Future.doWhile(() => Future.delayed(interval).then((_) => isPaused));
}
callbacks or asynchronous methods or other options
A solution to the callback plague is "await" and "async" or more specifacally 'dart:async' library.
Now, what is the cost of asynchrony?
When should we not use them?
What are the other alternatives?
The below is a badly coded non-polymer custom element that acts like a messageBox in desktop environment. It gives me less braces and parenthesis-es but requires the caller to be also async or use "show().then((v){print(v);});" pattern. Should I avoid the pattern like this?
Is callback better? Or there is an even smarter way?
Polling version
import 'dart:html';
import 'dart:async';
void init(){
document.registerElement('list-modal',ListModal);
}
class ListModal extends HtmlElement{
ListModal.created():super.created();
String _modal_returns="";
void set modal_returns(String v){
///use the modal_returns setter to
///implement a custom behaviour for
///the return value of the show method
///within the callback you can pass on calling append .
_modal_returns=v;
}
factory ListModal(){
var e = new Element.tag('list-modal');
e.style..backgroundColor="olive"
..position="absolute"
..margin="auto"
..top="50%"
..verticalAlign="middle";
var close_b = new DivElement();
close_b.text = "X";
close_b.style..right="0"
..top="0"
..margin="0"
..verticalAlign="none"
..backgroundColor="blue"
..position="absolute";
close_b.onClick.listen((_){
e.hide();
});
e.append(close_b,(_)=>e.hide());
e.hide();
return e;
}
#override
ListModal append(
HtmlElement e,
[Function clickHandler=null]
){
super.append(e);
if(clickHandler!=null) {
e.onClick.listen(clickHandler);
}else{
e.onClick.listen((_){
this.hide();
_modal_returns = e.text;
});
}
return this;
}
Future<String> show() async{
_modal_returns = '';
this.hidden=false;
await wait_for_input();
print(_modal_returns);
return _modal_returns;
}
wait_for_input() async{
while(_modal_returns=="" && !this.hidden){
await delay();
}
}
void hide(){
this.hidden=true;
}
Future delay() async{
return new Future.delayed(
new Duration(milliseconds: 100));
}
}
Non-polling version
In response to Günter Zöchbauer's wisdom(avoid polling), posting a version that uses a completer. Thanks you as always Günter Zöchbauer:
import 'dart:html';
import 'dart:async';
void init(){
document.registerElement('list-modal',ListModal);
}
class ListModal extends HtmlElement{
ListModal.created():super.created();
String _modal_returns="";
Completer _completer;
void set modal_returns(String v){
///use the modal_returns setter to
///implement a custom behaviour for
///the return value of the show method.
///Use this setter within the callback for
///append. Always call hide() after
///setting modal_returns.
_modal_returns=v;
}
factory ListModal(){
var e = new Element.tag('list-modal');
e.style..backgroundColor="olive"
..position="absolute"
..margin="auto"
..top="50%"
..verticalAlign="middle";
var close_b = new DivElement();
close_b.text = "X";
close_b.style..right="0"
..top="0"
..margin="0"
..verticalAlign="none"
..backgroundColor="blue"
..position="absolute";
close_b.onClick.listen((_){
e.hide();
});
e.append(close_b,(_){e.hide();});
e.hide();
return e;
}
#override
ListModal append(
HtmlElement e,
[Function clickHandler=null]
){
super.append(e);
if(clickHandler!=null) {
e.onClick.listen(clickHandler);
}else{
e.onClick.listen((_){
_modal_returns = e.text;
this.hide();
});
}
return this;
}
Future<String> show() async{
_modal_returns = '';
_completer = new Completer();
this.hidden=false;
return _completer.future;
}
void hide(){
hidden=true;
_completer?.complete(_modal_returns);
_completer=null;
}
}
Usually there is no question whether async should be used or not. Usually one would try to avoid it. As soon as you call an async API your code goes async without a possibility to choose if you want that or not.
There are situations where async execution is intentionally made async. For example to split up large computation in smaller chunks to not starve the event queue from being processed.
On the server side there are several API functions that allow to choose between sync and async versions. There was an extensive discussion about when to use which. I'll look it up and add the link.
The disadvantages of using async / await instead of .then() should be minimal.
minimal Dart SDK version with async / await support is 1.9.1
the VM needs to do some additional rewriting before the code is executed the first time, but this is usually neglectable.
Your code seems to do polling.
wait_for_input() async {
while(_modal_returns=="" && !this.hidden){
await delay();
}
}
This should be avoided if possible.
It would be better to let the modal manage its hidden state itself (by adding a hide() method for example), then it doesn't have to poll whether it was hidden from the outside.