Await is not supported here

Hi,
BlocksConsoleApplication.zip (142.5 KB)
The attached used to work but I now get

E:                   "await" requires a method with no result, or one that returns a Task or Task<T> [/Users/JohnMoshakis/Documents/develop/Echoes/BlocksConsoleApplication/Program.pas (17)]

This piece of code gives the error

      var t1 := new TransformBlock<Model, Model>(parcel ->
      begin
        await Task.Delay(TimeSpan.FromSeconds(1));
        
        exit new Model;
        
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );
      

but this doesnt

      var a1 := new ActionBlock<Model>(parcel ->
      begin
        await Task.Delay(TimeSpan.FromSeconds(1));
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

Why is that ?

Should both not work or is the first a bug ?

This is the visual studio c#

            var t1 = new TransformBlock<Model, Model>(async model =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(1));

                    return new Model {};

                },
            new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 5 }
                );

Without the async keyword it tells me I need to use an async lambda.

Cheers,
John

Hmm,. good Q. I do see a difference in the declarations:

  constructor(transform: Func<TInput,TOutput>; dataflowBlockOptions: ExecutionDataflowBlockOptions); public;
  constructor(transform: Func<TInput,TOutput>); public;
  constructor(transform: Func<TInput,Task<TOutput>>; dataflowBlockOptions: ExecutionDataflowBlockOptions); public;
  constructor(transform: Func<TInput,Task<TOutput>>); public;

vs

  constructor(action: Func<TInput,Task>; dataflowBlockOptions: ExecutionDataflowBlockOptions); public;
  constructor(action: Func<TInput,Task>); public;
  constructor(action: Action<TInput>; dataflowBlockOptions: ExecutionDataflowBlockOptions); public;
  constructor(action: Action<TInput>); public;

note how one takes a generic Task<TOutput> while the other takes a non-generic Task.

Do you have answer for this ? I worked around the issue by using .wait() but I really want to go back to using await

Not sur eyet about your case, because I dont think the return type van be inferred from the await statement you have,

but this one also fails"

      var t2 := new TransformBlock<ModelIn, ModelOut>(method (parcel: ModelIn): Task<ModelOut>; // E256 Result type from lambda's or anonymous method does not match, expected "BlocksConsoleApplication.ModelOut", but got "System.Threading.Tasks.Task<BlocksConsoleApplication.ModelOut>"

that thats definitely a bug.

Actually, my bad.

      var t2 := new TransformBlock<ModelIn, ModelOut>(method (parcel: ModelIn): Task<ModelOut>;
      begin
      end);

compiles fine. If I add your code into it it fails:

      var t2 := new TransformBlock<ModelIn, ModelOut>(method (parcel: ModelIn): Task<ModelOut>; // E256 Result type from lambda's or anonymous method does not match, expected "BlocksConsoleApplication.ModelOut", but got "System.Threading.Tasks.Task<BlocksConsoleApplication.ModelOut>"
      begin
        await Task.Delay(TimeSpan.FromSeconds(1));
        //exit new Model;
      end);

which makes sense, because Task.Delay returns a (void) task, but your this function is expected to return a Task<Model>.

Your original code fails for the same reason, the error just is less clear.

Is the original meant to work ?

      var t1 := new TransformBlock<Model, Model>(method (parcel: Model): Task<Model>;
      begin
        var value := Task.FromResult(new Model);
        exit value;
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

      
      var t2 := new TransformBlock<Model, Model>(method (parcel: Model): Task<Model>;
      begin
        await Task.Delay(TimeSpan.FromSeconds(1));
        exit new Model;
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

The first works but the second doesnt, which is odd ?

The other permutation which doesnt work is

I have this method

    class method DoIt : Task<Model>;
    begin
      exit Task.FromResult(new Model);
    end;

And I do

      var t3 := new TransformBlock<Model, Model>(method (parcel: Model): Task<Model>;
      begin
        var value2 :=  await DoIt;
        exit value2;
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

The errors from both are the same

E:                   Result type from lambda's or anonymous method does not match, expected "BlocksConsoleApplication.Model", but got "System.Threading.Tasks.Task<BlocksConsoleApplication.Model>" [/Users/JohnMoshakis/Documents/develop/Echoes/BlocksConsoleApplication/Program.pas (34)]
E:                   Result type from lambda's or anonymous method does not match, expected "BlocksConsoleApplication.Model", but got "System.Threading.Tasks.Task<BlocksConsoleApplication.Model>" [/Users/JohnMoshakis/Documents/develop/Echoes/BlocksConsoleApplication/Program.pas (42)]

Can this one be looked into ? It looks like a bug to me because I cant use await and get it to compile.

I believe the error in the full test case you sent was correct, as explained. Can you send me a complete new test case for the new issue?

I hate patching test cases for stuff like this together from vague code snippets, as invariable some part is missing and I end up chasing the wrong stuff.

I dont seem to be able to upload anything.I get “sorry there was an error uploading, please try again”

Hmm, I’ll check. meantime, can emai to mh@?

Did you get the test case I emailed you ?

Hm, no. last DM I see from you is from February – did you send it as DM here, to support, or to my personal email?

BlocksConsoleApplication.zip (44.2 KB)

I sent it to your work email but I can upload stuff here again so this is it.

Its giving a different error with the latest preview

E:                   Result type from lambda's or anonymous method does not match, expected "BlocksConsoleApplication.Model", but got "System.Threading.Tasks.Task<BlocksConsoleApplication.Model>" [/Users/JohnMoshakis/Documents/develop/Echoes/BlocksConsoleApplication/Program.pas (36)]

Actually, the original works now

      var t4 := new TransformBlock<Model, Model>(method
      begin
        var value2 := await DoIt;
        exit value2;
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

Hmm, curious. I dont believe anything was touched there…

      // Shouldnt this work ?

      var t3 := new TransformBlock<Model, Model>(method (parcel: Model): Task<Model>;
      begin
        var value2 :=  await DoIt;
        exit value2;
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

I dont know if it should, the await turns value2 into a Model (not Task<Model>), but the closure has to return a task<Model>, no?

vs.

In the second one arent you doing some magic and its really Task ?

When its anonymous, how does it know which overload to use ? Like this

      var t5 := new TransformBlock<Model, Model>(value1 ->
      begin
        var value2 := await DoIt;
        exit value2;
      end,
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

Not after the await, according to GTD.

Getting things done ?

This compiles

    class method AnotherDoIt(value1:Model):Task<Model>;
    begin
      var value2 := await DoIt;
      exit value2;
    end;
      var t3 := new TransformBlock<Model, Model>(value1 -> AnotherDoIt(value1),
      new ExecutionDataflowBlockOptions(MaxDegreeOfParallelism := 5)
      );

They look the same to me but Im assuming there is a difference ?