Skip to content
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

lang/funcs: Experimental "defaults" function #26766

Merged
merged 2 commits into from
Nov 14, 2020

Conversation

apparentlymart
Copy link
Contributor

@apparentlymart apparentlymart commented Oct 31, 2020

This is a new part of the existing module_variable_optional_attrs experiment, because it's intended to complement the ability to declare an input variable whose type constraint is an object type with optional attributes. Module authors can use this to replace null values (that were either explicitly set or implied by attribute omission) with other non-null values of the same type.

This function is a bit more type-fussy than our functions typically are because it's intended for use primarily with input variables that have fully-specified type constraints, and thus it uses that type information to help inform how the defaults data structure should be interpreted.

Other uses of this function will probably be harder today because it takes a lot of extra annotation to build a value of a specific type if it isn't passing through a variable type constraint. Perhaps later language features for more general type conversion will make this more applicable, but for now the more general form of this problem is better solved other ways.


This PR also includes a commit to allow functions to be marked as experimental. That will hopefully also prove useful to help us try out other complex functions that might need multiple design iterations in the future.

@codecov
Copy link

codecov bot commented Oct 31, 2020

Codecov Report

Merging #26766 (cec4578) into master (9f5f5ad) will increase coverage by 0.07%.
The diff coverage is 78.83%.

Impacted Files Coverage Δ
lang/funcs/defaults.go 77.58% <77.58%> (ø)
lang/functions.go 92.14% <81.25%> (-1.41%) ⬇️
lang/scope.go 100.00% <100.00%> (ø)
terraform/eval_context_builtin.go 74.45% <100.00%> (+0.57%) ⬆️
dag/marshal.go 53.42% <0.00%> (-1.37%) ⬇️
terraform/eval_apply.go 73.87% <0.00%> (+0.60%) ⬆️
terraform/node_resource_plan.go 97.16% <0.00%> (+1.88%) ⬆️
internal/providercache/dir.go 73.46% <0.00%> (+6.12%) ⬆️

Copy link
Contributor

@mildwonkey mildwonkey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fantastic (and will be very popular)!

Copy link
Contributor

@alisdair alisdair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! 👏

lang/funcs/defaults_test.go Show resolved Hide resolved
lang/functions_test.go Outdated Show resolved Hide resolved
// experiment.
prepareScope := func(t *testing.T, scope *Scope) {}

if experiment, isExperimental := experimentalFuncs[funcName]; isExperimental {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely achieves the goal of testing both cases (experimental and non-experimental), but I think got stuck in the idea that this all has to happen in one test (which I don't believe to be the case).

I found this a bit difficult to understand (multiple loops through the test cases) and might be to future readers as well, so I will share that but approve this as it does have test coverage, but I don't think "it all must be tested in one large test" is a constraint that needs to be prioritized in future work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This particular test has indeed grown a bit beyond its original purpose of "make sure every registered function is at least callable", but I'm not really sure how to separate out dealing with experiments because by definition they make it so that registered functions are not callable, and so the test would at least need to know enough to skip them so another test could deal with them, and then we'd have two tests that both have to be aware of which functions are experimental, which I don't think would really get the usual benefits of having separated tests (that is: them each being simple and testing one specific thing).

Indeed though, we can probably find another way to deal with this down the road.

// be consistent with how experiment checking in the "configs"
// package itself works. The nil check here is for robustness in
// incompletely-mocked testing situations; mc should never be nil in
// real situations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent, thank you for adding this comment!

So far all of our language experiments have been new constructs handled
statically up in the configs package, but functions are another common
extention point where experiments could be useful to gather feedback and
so this intends to pass the information down into the right place to allow
for that to happen, even though as of this commit there are no
experimental functions to use it.
This is a new part of the existing module_variable_optional_attrs
experiment, because it's intended to complement the ability to declare
an input variable whose type constraint is an object type with optional
attributes. Module authors can use this to replace null values (that were
either explicitly set or implied by attribute omission) with other
non-null values of the same type.

This function is a bit more type-fussy than our functions typically are
because it's intended for use primarily with input variables that have
fully-specified type constraints, and thus it uses that type information
to help inform how the defaults data structure should be interpreted.

Other uses of this function will probably be harder today because it takes
a lot of extra annotation to build a value of a specific type if it isn't
passing through a variable type constraint. Perhaps later language
features for more general type conversion will make this more applicable,
but for now the more general form of this problem is better solved other
ways.
@apparentlymart apparentlymart merged commit ca4b860 into master Nov 14, 2020
@apparentlymart apparentlymart deleted the f-experimental-funcs branch November 14, 2020 01:41
@ghost
Copy link

ghost commented Dec 14, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants