skip to content

An editor unbinds a shortcut by the function value it was registered with - why can an inline literal break that?

level: seniorimportance: should knowfreq 40%

answer

  1. same text is not the same value
  2. two evaluations, two values
  3. hold the value you registered
  4. matching by identity, not by source
  5. or hand back a removal token

basics

~20 s

Unbinding matches the stored value, and evaluating an inline literal generally yields a fresh, distinct value. Registering with one literal and unbinding with a second, identical-looking literal compares two different values, so the binding stays.

solid answer

~40 s

Registration stores a value; removal has to find **that same value** again. Writing the literal a second time evaluates it a second time, and that generally produces a new function value even though the source text is identical - and where two evaluations might share a value, no language lets you rely on it either way. So the unbind call compares a value the table has never seen, finds no match and usually returns quietly. Fix it by holding the value once, in a variable or a named declaration, and passing that same value to both calls. The sturdier fix is a registry that returns an opaque token from the bind call and accepts only that token to remove, so callers never have to reproduce a value at all.

code

pseudocode · 8 lines
pseudocode
// fails: the second literal is a different value
bind("ctrl+s", function() save() end)
unbind("ctrl+s", function() save() end)   // no entry matches; nothing removed

// works: one value, referred to twice
handler = function() save() end
bind("ctrl+s", handler)
unbind("ctrl+s", handler)                 // the stored value is found

go deeper

for a junior

Remember that a function literal creates a value when it is evaluated, so writing it out twice gives two values; keep the one you registered in a variable.

for a middle

Explain identity matching: the registry compares the value it stored against the value it was handed, and equal-looking source text does not make two values equal.

for a senior

Describe the production shape - handlers accumulating across reopened views, one press firing an action several times, memory held by entries nobody can name - and how you would detect it.

for a principal

Decide the registry contract for the codebase: token-based removal, a documented rule for who owns teardown, and whether a duplicate registration should be an error rather than a silent addition.

## Registration stores a value; removal matches one A registry that supports removal has to answer *which binding do you mean?*. The common contract is: the caller hands back the same function value it registered, and the registry removes the entry holding that value. That contract quietly makes the **identity of a function value** part of the API, which is the part most callers never think about. It matters because a function value is produced by evaluating an expression. An inline literal is an expression. Evaluating it twice generally makes two values, and the two are not related to each other by the fact that their bodies were spelled the same way. Matching is done on the value handed over, not on the text it came from - and no language promises structural comparison of function bodies. ## Why two identical literals are two values ``` bind("ctrl+s", function() save() end) unbind("ctrl+s", function() save() end) // a second value; nothing matches ``` The second line builds a new value and asks the registry to remove a binding holding it. There is no such binding. Languages differ on whether an implementation is ever allowed to reuse a value for a literal that captures nothing from around it, so the safe rule is the strong one: **assume a fresh value per evaluation, and never depend on two evaluations agreeing.** The repaired version refers to one value twice: ``` handler = function() save() end bind("ctrl+s", handler) unbind("ctrl+s", handler) // same value; the entry is found ``` ## What the failure looks like in production The bug is quiet at the moment it happens and loud later: - A view is opened, binds its shortcuts, is closed, and unbinds nothing. - Reopening the view binds a second set. One key press now runs the action twice, then three times, then four. - The registry holds every stale entry alive, and through them whatever the bodies reference - so memory grows with the number of times the screen was visited. - Actions that looked idempotent hide the count; actions that insert text or send a request expose it immediately, usually in a bug report about duplicates. The diagnostic that settles it quickly is to count the registry's entries for one key over a session. A count that climbs with navigation is the signature; no amount of reading the unbind call site will show it, because that call site looks correct. ## Designs that remove the question | approach | how removal identifies the binding | failure mode it leaves | |---|---|---| | Match the function value | caller supplies the same value | a re-evaluated literal silently matches nothing | | Hold the value in a variable | one value, referred to twice | someone later inlines the variable back | | Return a token from bind | an opaque handle the caller keeps | a stale token, which can be reported explicitly | | Key-scoped removal | remove everything under a key | removes another owner's binding too | In order of how much they rely on caller discipline: 1. **Keep the value.** One variable or one named declaration, used at both calls. Cheapest, and adequate when one module owns the binding. 2. **Return a token.** The bind call hands back a handle; unbind accepts only a handle. The caller cannot reproduce a wrong value because it never constructs one, and a handle already removed can be rejected loudly instead of silently missing. 3. **Scope removal to an owner.** Registration records which component bound it, and teardown removes everything that component registered. This survives the case where the component no longer has any of its values in hand. ## When referring to a name is still not enough One refinement worth knowing: referring to the same name usually means referring to the same value, but not always. In some languages, fetching a routine that is attached to an object produces a freshly built value on each access, so two references to what looks like one name yield two values and the removal fails in exactly the same way. The rule that always holds is the one about evaluation, not about spelling: **capture the value once, keep it, and hand back the thing you kept.** ## The general lesson This is the first-class property biting back. Because behaviour is an ordinary value, it has the same questions an ordinary value has - where is it stored, who else holds it, and what does it mean for two of them to be the same. A candidate who can name identity as the mechanism, show the two-evaluation trace, describe the duplicate-handler symptom and propose a token-based contract is demonstrating exactly the production judgment the question is asking for.

  • What symptom does the failed unbind produce once the view is reopened?
    Handlers accumulate. The old binding still fires and the new registration sits beside it, so one key press runs the action twice, then three times. Memory grows too, because the registry keeps every stale entry and whatever those bodies reference.
  • How would you design the registry so callers cannot get this wrong?
    Have the bind call return an opaque token and accept only that token in unbind. The caller never reconstructs a value, so identity stops being part of the contract, and a token that was already used can be rejected loudly instead of missing silently.
  • Is referring to the same name always enough to get the same value?
    Usually, but not guaranteed. In some languages, fetching a routine attached to an object builds a fresh value on each access, so two references to one name produce two values. Capturing the value once in a variable and reusing that variable is the version that always holds.

saying these in an interview costs you the question

  • Assumes two identical-looking literals are the same value
  • Says the registry compares the source text of the bodies
  • Thinks the failed removal is harmless once the key is rebound
  • Believes comparison by body structure is guaranteed anywhere
  • Blames the registry rather than the duplicate value handed to it