Skip to content

Fix memoize re-invoking factories that return undefined - #22

Merged
kburov-sc merged 1 commit into
Snapchat:mainfrom
Montana:fix/memoize-undefined-results
Jul 2, 2026
Merged

Fix memoize re-invoking factories that return undefined#22
kburov-sc merged 1 commit into
Snapchat:mainfrom
Montana:fix/memoize-undefined-results

Conversation

@Montana

@Montana Montana commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Problem

memoize() uses typeof memo !== "undefined" as its cache-hit check, so any factory whose result is undefined is silently re-invoked on every container.get() call. This breaks the documented run-once/singleton guarantee — notably for the side-effect initializer pattern the docs recommend with run() (e.g. Injectable("initCache", ["request"], (req) => populateCache(req)), whose factory returns nothing and therefore re-runs on every subsequent resolution).

Repro:

let calls = 0;
const c = Container.provides("init", () => { calls++; return undefined; });
c.get("init"); c.get("init"); c.get("init");
// calls === 3, expected 1

Fix

Track invocation with an explicit invoked flag instead of inspecting the memoized value. The flag is set only after the delegate returns, deliberately preserving the existing retry-on-throw behavior that existing tests rely on.

Tests

  • New memoize.spec.ts: undefined-result caching, throw-then-retry, delegate/isMemoized behavior
  • Container-level regression test in Container.spec.ts

All tests pass with 100% coverage maintained; ESLint clean.

memoize() used 'typeof memo !== "undefined"' as its cache-hit check, so any
factory whose result was undefined was re-invoked on every call. This broke
the documented run-once/singleton guarantee for services registered via
provides()/run() whose factories perform side effects but return nothing.

Track invocation with an explicit flag instead. The flag is set only after
the delegate returns, preserving the existing retry-on-throw behavior.

Adds unit tests for memoize (undefined results, throw-retry, delegate
exposure) and a Container-level regression test.

@kburov-sc kburov-sc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, thank you for the contribution

@kburov-sc
kburov-sc merged commit 0cf0d62 into Snapchat:main Jul 2, 2026
1 check passed
@Montana

Montana commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@kburov-sc , No problem. I'm glad to help anytime.

@RobbieBizzle

Copy link
Copy Markdown

@Montana the hero!

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.

3 participants