Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions api_notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@


## For rule.cfg

optional vs rule-union vs cfg-union?

* Optional: feels verbose. Requires extra get() calls.
* Optional: seems harder to detect value
* Rule-union: which API feels verbose.
* Cfg-Union: seems nicest? More underlying impl work though.

```
# optional
# Rule.cfg is type Optional[TransitionBuilder | ConfigNone | ConfigTarget]

r = RuleBuilder()
cfg = r.cfg.get()
if <cfg is TransitionBuilder>:
cfg.inputs.append(...)
elif <cfg is config.none>:
...
elif <cfg is config.target>:
...
else: error()

# rule union
# Rule has {get,set}{cfg,cfg_none,cfg_target} functions
# which() tells which is set.
# Setting one clears the others

r = RuleBuilder()
which = r.cfg_which()
if which == "cfg":
r.cfg().inputs.append(...)
elif which == "cfg_none":
...
elif which == "cfg_target":
...
else: error

# cfg union (1)
# Rule.cfg is type RuleCfgBuilder
# RuleConfigBuilder has {get,set}{implementation,none,target}
# Setting one clears the others

r = RuleBuilder()

if r.cfg.implementation():
r.cfg.inputs.append(...)
elif r.cfg.none():
...
elif r.cfg.target():
...
else:
error

# cfg-union (2)
# Make implementation attribute polymorphic
impl = r.cfg.implementation()
if impl == "none":
...
elif impl == "target":
...
else: # function
r.cfg.inputs.append(...)

# cfg-union (3)
# impl attr is an Optional
impl = r.cfg.implementation.get()
... r.cfg.implementation.set(...) ...
```

## Copies copies everywhere

To have a nicer API, the builders should provide mutable lists/dicts/etc.

But, when they accept a user input, they can't tell if the value is mutable or
not. So they have to make copies. Most of the time, the values probably _will_
be mutable (why use a builder if its not mutable?). But its an easy mistake to
overlook that a list is referring to e.g. some global instead of a local var.

So, we could defensively copy, or just document that a mutable input is
expected, and behavior is undefined otherwise.

Alternatively, add a function to py_internal to detect immutability, and it'll
eventually be available in some bazel release.

## Collections of of complex objects

Should these be exposed as the raw collection, or a wrapper? e.g.
3 changes: 3 additions & 0 deletions docs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,14 @@ sphinx_stardocs(
"//python/cc:py_cc_toolchain_bzl",
"//python/cc:py_cc_toolchain_info_bzl",
"//python/entry_points:py_console_script_binary_bzl",
"//python/private:attr_builders_bzl",
"//python/private:builders_util_bzl",
"//python/private:py_binary_rule_bzl",
"//python/private:py_cc_toolchain_rule_bzl",
"//python/private:py_library_rule_bzl",
"//python/private:py_runtime_rule_bzl",
"//python/private:py_test_rule_bzl",
"//python/private:rule_builders_bzl",
"//python/private/api:py_common_api_bzl",
"//python/private/pypi:config_settings_bzl",
"//python/private/pypi:pkg_aliases_bzl",
Expand Down
Loading
Loading