bland-tailor-50336
11/05/2022, 6:17 AMbillowy-army-68599
11/05/2022, 7:10 AMechoing-dinner-19531
11/05/2022, 9:27 AMripe-russia-4239
11/05/2022, 10:09 PMOutput
is much more than just the underlying asynchronous control flow implementation, but… each of these implementations provides an idiomatic interface for that language. The language agnosticism is wonderful, of course, but aren’t `Output`s built on the language’s underlying primitive anyway? (I know they are in the .NET and Node SDKs, at least.) Exposing the primitive’s interface for `Output`s--i.e. being able to await
an Output
in Node, .NET, and Python--would be a wonderful usability improvement ☺️echoing-dinner-19531
11/06/2022, 12:41 PMOutputToPromise
or similar function that you could just await, but it would require you to handle all the complexity above, and to acknowledge that more complexity could be added to that state as the engine evolves.
What would be far more interesting is if these languages could develop a way to let us write awaits for things that aren't promises. So F# for example does await via computation expressions, and we can make outputs look exactly the same as Async's in F#. But most other languages have made async/await specific to their promise type with no way to hook user defined types into the same syntax. Which is a bit sad, it's all just monads really.ripe-russia-4239
11/06/2022, 3:39 PMpublic static class OutputTaskExtensions
{
public static ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter GetAwaiter<TResult>(this Output<TResult> output)
{
TaskCompletionSource<TResult> dataCompletion = new();
output.Apply(o =>
{
dataCompletion.SetResult(o);
return o;
});
return dataCompletion.Task.ConfigureAwait(false).GetAwaiter();
}
}
which does allow us to directly await
an Output<T>
in C#. I’ve seen it deadlock in our tests, though (usually when the mocks haven’t been configured with a dependent output), which makes me uncomfortable using it in a deployable Stack. It would be great if the Output<T>
were able to use this extension method approach in the dotnet SDK.
I’ve also done something similar in TypeScript (I forget the precise syntax now, sorry):
new Promise(resolve => output.apply(_ => resolve))
to wrap the Output<T>
in an awaitable Promise. I guess this has the problems you described of having to deal with the underlying detail of the Output type, though?echoing-dinner-19531
11/06/2022, 4:32 PMI guess this has the problems you described of having to deal with the underlying detail of the Output type, though?Yup. Firstly
apply
might never run (we don't run applys if the value is "unknown" at preview time) so you have to deal with that promise never resolving, probably why you've been seeing deadlocks. If we built a "ToPromise" method into the SDK we could make it always resolve, but then it might not always resolve to a value (e.g. you'd get like T | undefined
). And then secondly your losing all the information about secretness, dependencies, anything else we start tracking, etc. Again if we made this a proper part of the SDK we'd return a structure with all that information on it, but it would be up you the user to make use of it correctly. While with apply
we handle all the details of that extra data.
An await function has got its uses (mostly working around tricky bugs we haven't fixed yet, which is why one Go customer asked for it to be added to the SDK there), but I'd definitely class it as an advanced feature.bumpy-laptop-30846
01/30/2023, 1:39 PMif (pulumi.isDryRun() && my_ressource.isUnknown()) {// manage special case for my preview))
echoing-dinner-19531
01/30/2023, 2:18 PMbumpy-laptop-30846
01/30/2023, 2:20 PMechoing-dinner-19531
01/30/2023, 2:26 PMbumpy-laptop-30846
01/30/2023, 2:31 PM