This is a useful exercise and something I’m interested in! Thanks for doing this.
This is something I keep going back and forth on. I had a long conversation about it recently, actually. I think my hesitation here is that I haven’t run into a situation where it’s needed, yet, it just makes things easier in certain situations. And I’m trying not to make things that most people don’t want to do too easy, because I don’t want to confuse people. I’m still mulling this one over a bit, and think we’ll probably come down on the side of making the type retrievable from a value, but I’m trying to be deliberate about that kind of stuff. I worry that if we expose a tftypes.Value
’s Type
, people will switch on them or do raw comparisons instead of using Is
, and that has some pitfalls if you’re not thoughtful about it.
Technically you shouldn’t need to do that for this; you can inspect each level of the type using reflect
or a type switch, and constructing the tftypes.Type
dynamically.
You appear to be returning a tftypes.Value
as the interface, but according to the documentation for tftypes.ValueCreator
(emphasis added):
So rather than returning a new tftypes.Value
, your implementation should be returning one of the supported primitives. E.g., objects should return a map[string]tftypes.Value
, strings should return a string
, etc.
I’m interested in hearing more about this. What does “break” mean, here? Can you be clearer about what you mean by “changes structure”?
That one I have an answer to! Basically, cty isn’t designed for this use case. And I don’t mean that it can’t work in this use case, it just means we’re trying to do something other than what cty was designed for.
cty was built to let Go programs define a typed configuration language. That’s what the packages are built and designed for, and that makes sense for Terraform to use. Terraform is, after all, trying to define a configuration language.
The SDK, however, is not trying to design a configuration language. It’s trying to surface a configuration language that has already been designed. It doesn’t want consumers creating their own types, it doesn’t need arbitrary expressions, it just wants to give users access to values expressed in an existing type system.
And that’s what tftypes
is for. It’s not a type system building library, it’s a representation of Terraform’s type system, specifically. And it’s designed and tailored towards making the things people want to do with Terraform’s type system obvious and easy, making things that people probably shouldn’t be doing impossible, and making things that most people won’t want to be doing a little harder than the things most people want to do, to help guide them towards the things they probably want to be doing.
I’m very open to the feedback we missed the mark on that so far. I think that’s likely, and something we plan to continue to iterate on as we learn more. But I think the strength of tftypes
is that we get to iterate to something that makes sense for users of the SDK, which we don’t get to do with cty because cty isn’t designed specifically for the SDK, and so its designs need to work for Terraform and every other system out there using it.
Does that all make sense? I know it’s frustrating to watch us iron out bugs and circle towards a more stable implementation when a stable implementation already exists, but we feel confident that this will yield a more stable and more approachable provider development experience in the long run.