Inside a plugin, how can you tell whether a build author explicitly configured an extension property versus it still holding only the convention default — and why does the convention mechanism enable that?
answer
- convention and explicit value = separate slots
- convention-only still 'not set'
- getOrNull/orNull to detect
- eager set masks the signal
- branch behaviour on configured-ness
basics
~20 sBecause a convention is a separate slot from the explicit value, the property stays 'unset' until someone calls set(). A plugin can branch on that by reading the property without a convention, or by comparing against the known default, to detect author configuration.
solid answer
~50 sThe convention model deliberately keeps the *default* and the *explicit value* in different slots, so a property is considered 'not explicitly configured' until `set(...)` is called — even though `get()` would return the convention. This separation is what lets a plugin distinguish 'author chose this' from 'fell back to default'. The common technique: don't register a convention on the property you need to probe; instead read it with `getOrNull()` — `null` means the author never set it, so the plugin can pick behaviour A vs B, then apply its own fallback. (If you *do* register a convention, `getOrNull()` returns the default and you lose the signal, so for detection you keep the property unset or compare against the default value.) This matters for plugins that behave differently when configured (e.g. enable a feature only if an endpoint was explicitly provided) rather than silently using a default. It's exactly why `convention()` is preferred over an eager `set()` of the default: an eager set would make the property look configured.
code
kotlin · 7 lines// no convention on this property -> we can detect explicit config
val ep = ext.endpoint.orNull
if (ep != null) {
enableRemoteMode(ep) // author configured it
} else {
enableLocalMode() // plugin's own fallback
}go deeper
Not typically expected; basic awareness that convention is a separate default slot is enough.
Explain that convention-only leaves the property 'unset' and getOrNull() can probe an un-conventioned property.
Articulate the three property states and the design trade-off between convention defaults and detection, with concrete branching code.
Decide when behaviour-forking-on-configuration is worth the API complexity versus a plain convention default across a plugin suite.
## Why detection is even possible A lazy property tracks three states: 1. **Explicitly set** — `set(...)`/`=`/`value(...)` was called. 2. **Convention only** — a convention is registered but no explicit set; `get()` returns the convention, but the property still reports as not-explicitly-set internally. 3. **Undefined** — neither; `get()` throws, `getOrNull()` returns null. Because the convention lives in its own slot, state (2) is distinguishable from state (1) at the API level. This is the design payoff of *not* eagerly `set`-ing your default: an eager `set(default)` collapses (1) and (2) into 'looks configured', destroying the signal. ## Practical detection patterns ### Pattern A — keep the probe property unset If the plugin must know whether the author supplied a value, leave the property with **no convention** and read via `getOrNull()`: ```kotlin val endpoint: String? = ext.endpoint.orNull if (endpoint != null) { // author explicitly configured -> enable remote mode } else { // fall back to local mode } ``` ### Pattern B — compare against the known default If you *do* set a convention, you can still infer configuration by comparing the resolved value to your default, though this is weaker (the author might explicitly set the same value as the default). ## Why this is preferable to eager defaults Consider a plugin that should fail the build if neither a value nor a sensible default applies. With `convention`, the plugin can layer behaviour: probe for explicit configuration, then apply a convention as the *final* fallback. With an eager `set`, every property always looks configured, so you can't offer 'configured vs default' branching or distinct diagnostics. ## Caveats - Detection is about *explicit set*, not about whether the value differs from default. - For `ListProperty`/`MapProperty`, remember `add`/`put` interact with conventions specially (a convention list can be appended to), so reason about those collection semantics separately. - Don't overuse detection — for most plugins a plain convention default is the right, simplest design; reach for detection only when behaviour genuinely forks on configuration. ## Summary The split between convention and explicit value is what makes 'did the author configure this?' answerable. Keep the probed property convention-free and use `getOrNull()`/`orNull`, or compare to the default, and prefer this over eagerly setting defaults that mask the distinction.
- Why does eagerly calling set(default) instead of convention(default) hurt detection?An explicit set makes the property report as configured, collapsing the 'author set it' and 'default' states into one, so the plugin can no longer tell whether the author actually chose the value.
- If you registered a convention and call getOrNull(), what do you get when the author didn't set anything?You get the convention's value (not null), so to detect explicit configuration you must keep the property convention-free or compare against the known default.
saying these in an interview costs you the question
- Saying a convention-backed property reports as explicitly set — it doesn't.
- Using eager set(default) and then claiming you can still detect author configuration.
- Assuming value-differs-from-default reliably means the author configured it (they may set the same value).