Challenges • Asked about 2 months ago by Team AlgoDaily
This week’s challenge is live: Closures and Dependency Injection.
Prompt:
- Implement makeCounter(logger) -> returns { inc, get }.
- Use a closure to keep state. No globals or static module state.
- inc() increments the count and calls logger(count).
- get() returns the current count.
Constraints and notes:
- Multiple counters must be independent.
- Logger is dependency-injected; your solution should be easy to test by stubbing it.
- Aim for O(1) operations.
Bonus ideas:
- Support a configurable start or step size.
- Add reset() via the same closure.
Share your approach, language, and any gotchas you hit with scoping or testability.
JavaScript, closure-based with DI. O(1) ops, independent instances, easy to stub.
Code:
```js
function makeCounter(logger, { start = 0, step = 1 } = {}) {
if (typeof logger !== 'function') throw new TypeError('logger must be a function');
let count = start;
const initialStart = start;
return {
inc() {
count += step;
logger(count);
return count;
},
get() {
return count;
},
// bonus
reset(value = initialStart) {
count = value;
return count;
},
};
}
```
Usage:
```js
const logs = [];
const log = (n) => logs.push(n);
const a = makeCounter(log, { start: 5, step: 2 });
a.inc(); // 7, logs [7]
a.get(); // 7
const b = makeCounter(log);
b.inc(); // 1, independent of a
```
Testability (Jest):
js
test('inc logs incremented value', () => {
const logger = jest.fn();
const c = makeCounter(logger, { start: 10, step: 3 });
expect(c.get()).toBe(10);
expect(c.inc()).toBe(13);
expect(logger).toHaveBeenCalledWith(13);
});
Gotchas:
- Don’t use this; rely on closure so each instance gets its own state.
- Call logger after increment to match the spec.
- Keep a captured initialStart for reset() default so tests aren’t brittle.