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

syntax: parameterize API over FileOptions, avoid globals #477

Merged
merged 1 commit into from
Aug 14, 2023
Merged

Conversation

adonovan
Copy link
Collaborator

@adonovan adonovan commented Jun 15, 2023

This change eliminates the need for client applications to set global variables to control dialect options, as globals are error-prone and concurrency hostile.

All relevant API functions Foo now have a variant FooOptions that takes an explicit FileOptions; the original function accesses the legacy options by reading the global variables.

Fixes #435

syntax/options.go Show resolved Hide resolved
return &FileOptions{
Set: resolverAllowSet,
While: resolverAllowGlobalReassign,
TopLevelControl: resolverAllowGlobalReassign,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are While and TopLevelControl determined by resolverAllowGlobalReassign? (I vaguely remember there was a reason for this but not what it was.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I decided to split the flag into finer features in this CL. The -recursion flag is required to use while statements anywhere because potentially unbounded loops are expressively equivalent to recursive calls with arbitrary arguments.

As for -globalreassign, the flag is required only to use 'while' (or if or for) at top-level. I think the reason for this was so that Bazel could enforce the invariant that every top-level variable had exactly one assignment, also at top-level. Allowing re-declaration of globals (e.g. x=1; x=2) obviously breaks this invariant. More subtly, so does a loop for x in seq: pass: although there is only one static assignment, it is executed dynamically many times, including zero. And so too does if cond: x = 1, because it can cause a variable to be initialized zero times. (An if statement is an at-most-once loop!) Obviously while is like for. Personally I don't think the concern is important, and this flag is too hard to explain. @laurentlb may remember more.

syntax/parse.go Show resolved Hide resolved
syntax/parse.go Show resolved Hide resolved
@adonovan
Copy link
Collaborator Author

Thanks, Jay.

This change eliminates the need for client applications
to set global variables to control dialect options,
as globals are error-prone and concurrency hostile.

All relevant API functions Foo now have a variant FooOptions
that takes an explicit FileOptions; the original function
accesses the legacy options by reading the global variables.

Fixes #435
Copy link
Collaborator

@jayconrod jayconrod left a comment

Choose a reason for hiding this comment

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

Sorry for the slow review. It's been a really busy summer, and this slipped off my radar.

@adonovan
Copy link
Collaborator Author

Sorry for the slow review. It's been a really busy summer, and this slipped off my radar.

No worries! Between furious gopls work and now a lengthy vacation I haven't been spending much time thinking about Starlark. (Or the other matter, for that matter.)

Thanks for reviews, as always.

@adonovan adonovan merged commit 12f4cb8 into master Aug 14, 2023
15 checks passed
@adonovan adonovan deleted the options branch August 14, 2023 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mutable package-level vars are a poor choice for configuration
2 participants