https://pulumi.com logo
#dotnet
Title
e

enough-garden-22763

05/25/2021, 4:11 PM
Good morning, I wonder what are the conversion paths between
Task
and
Task<T>
, and correspondingly do we want to model something similar to value-less
Task
in the
Output<T>
layer? I am going for
Output<Object>
carrying a
null
to correspond to “value-less” task. I really like how F# does it with
unit
type but that seems to not to be in .NET stdlib.
It sounds like more a .NET question then Pulumi question so let me contextualize 🙂
b

bored-oyster-3147

05/25/2021, 4:15 PM
Task<T>
can implicitly be cast to
Task
but if you want to go the other direction you need to know what
TResult
is. Because you'd need to do something like
if (nonGenericTask is Task<T> genericTask)
Curious what use-case is for a value-less
Output<T>
e

enough-garden-22763

05/25/2021, 4:16 PM
I’m working on codegen changes to automatically lift functions to accept args as Input<.> and automatically promote results to Output<.>
Right so here I have a variation where the original function returns no value (it returns plain
Task
so caller can wait on it). And my lifted version is trying to lift that Task to Output.
Thinking about it, should I just return Task in this case from the lifted version… Hm…
b

bored-oyster-3147

05/25/2021, 4:19 PM
I'm trying to follow - can you give me an overview of like what the method signature a consumer would use would look like and what they would expect to be returned? When you say "lifted version" which are you referring to
e

enough-garden-22763

05/25/2021, 4:21 PM
Does the gist help any? This function is taken from existing azure package: https://gist.github.com/t0yv0/a9139fd04f28a5d4e8f1cf20909023ae#file-codegen-cs-L17. I’m working to generate
Apply
version of the same function https://gist.github.com/t0yv0/a9139fd04f28a5d4e8f1cf20909023ae#file-codegen-cs-L22 - let me use
Apply
version instead of “lifted” sorry for misplaced jargon 🙂
The Apply version is the same thing as the original, except all parameters become Input. So, Input<string> instead of string, etc.
b

bored-oyster-3147

05/25/2021, 4:22 PM
so is the goal to make the "get existing resource" functions easier to use?
e

enough-garden-22763

05/25/2021, 4:22 PM
Oh, right. It’s all sugar.
In the case of a function that used to return Task<Result>, the Apply version will generate Output<Result>, so far that sounds reasonable. Now, in the degenerate case, the function returns nothing (Task), and I’m pondering what to do for that kind of function in the Apply version.
b

bored-oyster-3147

05/25/2021, 4:26 PM
Ah ok now I understand. In the cases where the function returns nothing is there a reason it couldn't just remain
Task
? Are consumers still passing something along from that such that it needs to be
Output
?
e

enough-garden-22763

05/25/2021, 4:27 PM
So, yes, the consumers are passing a long a bunch of
Input<T>
.
If we had a function available,
Task<T> AwaitInput<T>(Input<T> input)
b

bored-oyster-3147

05/25/2021, 4:27 PM
ah, so we couldn't have a function that takes in N
Input<T>
but returns
Task
?
e

enough-garden-22763

05/25/2021, 4:27 PM
Then indeed we could return Task.
Let me puzzle it out a little more, maybe we still can.
b

bored-oyster-3147

05/25/2021, 4:28 PM
I guess as far as usage goes it would be a little weird that you would
await
the functions that have no results but not the ones that do
What's an example of a one of these functions that doesn't return anything?
e

enough-garden-22763

05/25/2021, 4:31 PM
Well that’s a great question also, let me scan azure-native to see if there’s any such functions. Because we can always completely bail from generating these sugar helpers in complicated cases if that’s not useful.
Okay so sounds like we can return Task if we use side-effecting facilities:
Copy code
public static Task Apply(FuncWithConstInputApplyArgs? args = null, InvokeOptions? options = null)
        {
            var promise = new TaskCompletionSource();
            args.PlainInput.Apply(t => {
                var plainArgs = new FuncWithConstInputArgs
                {
                    PlainInput = t
                };
                InvokeAsync(plainArgs, options).ContinueWith(t => CopyTaskStateTo(t, promise));
                return t;
            });
            return promise.Task;
        }

        public static void CopyTaskStateTo(Task t, TaskCompletionSource promise) {
            if (t.IsCompletedSuccessfully)
            {
                promise.SetResult();
            }
            else if (t.IsFaulted)
            {
                promise.SetException(t.Exception);
            }
            else
            {
                promise.SetCanceled();
            }
        }
Basically create a promise, that eventually is linked to the Task returned from the function, and return right away. It seems reasonable to me - more reasonable than
Output<Object>
since users will be wondering what is that and what is the null in there.
Let me scan for actual examples to see how much this arises in practice.
No examples in pulumi-azure-native. Great
Checking AWS
Ok perfect! That is the right call here I believe, simply do nothing for the case of functions having no return values, as this case does not seem to arise in practice yet. Thanks a ton!
(no functions in AWS either like this)
b

bored-oyster-3147

05/25/2021, 4:57 PM
it does look like that will work. Glad I could help
🙏 1