-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[sdk/go] Add RegisterInputType and register built-in types #7928
Conversation
This is introducing a liability to call Register* on all input types which will take a bit of work to percolate to all examples and programs out there, so I'd really like to understand the motivation but I'm not sure I do from this description? Is it that you are in a context that:
What's confusing me is that "This will be used when copying inputs to an args struct for multi-lang components (separate PR)" make it sound like the code has an instance of the StringMapInput? |
The implementation LGTM. |
Yes, that's it. Sorry the motivation wasn't clear from the description. Here's an example: Imagine a component has the following args struct: type StaticPageArgs struct {
Tags pulumi.StringMapInput `pulumi:"tags"`
} The component provider's implementation of args := &StaticPageArgs{}
if err := inputs.CopyTo(args); err != nil {
return nil, err
}
Inside the implementation of Imagine the actual values for tags is Now, with output values, we'll have the information we need to know that the dependencies are only associated with the
If the registration doesn't exist, we fall back to the current behavior of creating the top-level |
Thanks for that you convince me it's safe to ship. |
I thought about it some and yeah your approach makes sense. The formulation that makes the most sense to me is that we need to construct a serializer/deserializer for an interface input type like StringMapInput. The serializer has to demonstrate turnaround properties to be considered reliable. Now in Go we are immediately in deep water because the deserializer part of any interface needs to make a choice on the concrete type to use to instantiate the interface. What can make this morally correct without having the entire type pointer of the concrete type spelled out in the serialized form, is that Input interfaces are not really open interfaces but are morally unions over statically known set of types T and Output[T]. Where these assumptions may be violated is if more than one concrete type inhabits an interface. We've briefly touched on representing And.. if we're using reflection so reflection needs to know about these type relations, a type-map is reasonable. Languages where I seen this work well rely on type-indexed maps supported by the language in some form. In Haskell typeclasses are essentially threading type-indexed maps as extra parameters. In Scala implicits rely on type-indexed resolution. It's just a matter of some taste what exactly we hang into these maps. |
So this approach would be in trouble IFF there is an example where more than 1 concrete type
|
Right, these are handled specially (as resource references). Another oddity is the
That's right. In practice, I can't think of any examples where this is the case. Someone would have to be doing something really off the rails. |
This change adds a `RegisterInputType` function (similar to the existing `RegisterOutputType`) that is used to register an input interface's type and its associated input type, and adds registrations for the built-in input types. This will be used when copying inputs to an args struct for multi-lang components. When a field is typed as the input interface (e.g. `StringMapInput`) and doesn't need to be an `Output`, we can use this to lookup the non-Output type that implements the interface (e.g. `StringMap`) so it can be instantiated. A subsequent change will update the Go SDK codegen to produce input type registrations for a provider's input types.
4ecf5fd
to
7846634
Compare
This change adds a
RegisterInputType
function (similar to the existingRegisterOutputType
) that is used to register an input interface's type and its associated input type, and adds registrations for the built-in input types.This will be used when copying inputs to an args struct for multi-lang components (separate PR). When a field is typed as the input interface (e.g.
StringMapInput
) and doesn't need to be anOutput
, we can use this to lookup the non-Output type that implements the interface (e.g.StringMap
) so it can be instantiated.A subsequent change will update the Go SDK codegen to produce input type registrations for a provider's input types.
Part of #7848
Part of #7434
Note: I was originally planning to include a new
InputType
interface:Which could be implemented on an input type like:
And registered like:
And the implementation of
RegisterInputType
could callInputType()
to get the interface type and store it in the table.There are two problems with this:
StringInput
andStringPtrInput
interfaces are both associated withString
-- we'd have to change the interface to return an array of types.The only real benefit of the interface is that it makes the registration call site simpler, but since you aren't generally writing these registrations by hand anyway, we can avoid the above problems by not having a new interface at all.
One benefit to not using an interface -- in the immediate term, users can add temporary input registrations of relevant input types from other providers in their component provider before we've updated the codegen of those providers to include the registrations.