Timers without a user-stored reference don't fire #180

Closed
opened 2026-01-05 02:30:14 +00:00 by john · 1 comment
Owner

In an object's __init__:
mcrfpy.Timer("tick", self.tick, 1000, start=True)

this timer will never fire: since the user did not store a reference to it, it's silently garbage collected.

Changing it to:
self.ticker = mcrfpy.Timer("tick", self.tick, 1000, start=True)

the timer operates as expected.

This defies expectations: mcrfpy.timers shows the timer in the second case, but omits it in the first. The timer system only stores a weak reference to the python timer object, and doesn't crash when it's garbage collected, but it forces users to maintain the object even though it has a name.

In an object's `__init__`: `mcrfpy.Timer("tick", self.tick, 1000, start=True)` this timer will never fire: since the user did not store a reference to it, it's silently garbage collected. Changing it to: `self.ticker = mcrfpy.Timer("tick", self.tick, 1000, start=True)` the timer operates as expected. This defies expectations: `mcrfpy.timers` shows the timer in the second case, but omits it in the first. The timer system only stores a weak reference to the python timer object, and doesn't crash when it's garbage collected, but it forces users to maintain the object even though it has a name.
Author
Owner

Implementation Complete

Fixed the timer lifecycle so that timers without a user-stored reference continue firing.

Changes Made:

  1. Timer.h - Added std::string name member to store timer name in C++ object
  2. Timer.cpp - Updated constructor to accept and store name
  3. PyTimer.cpp - Removed the dealloc cleanup that was erasing timers from game->timers when Python wrapper was GC'd
  4. McRFPy_API.cpp - Added createTimerWrapper() helper and updated api_get_timers() to create new Python wrappers for orphaned C++ timers

New Lifecycle Behavior:

Scenario Behavior
Timer("t", cb, 1000) with no stored ref Timer runs, Python wrapper GC'd, accessible via mcrfpy.timers
t = Timer("t", cb, 1000) Timer runs, Python wrapper kept alive by t
t.stop() Timer removed from engine, kept alive by t
Timer fires with once=True testTimers() removes from map, Timer GC'd if no Python ref
New timer with same name Old timer bumped from map, old Timer GC'd when shared_ptr→0

Tests Added:

  • tests/issue_180_timer_orphan_test.py - Verifies orphan timers fire and are accessible
  • tests/issue_180_timer_stopped_test.py - Verifies stopped timer lifecycle

Both tests pass.

## Implementation Complete Fixed the timer lifecycle so that timers without a user-stored reference continue firing. ### Changes Made: 1. **Timer.h** - Added `std::string name` member to store timer name in C++ object 2. **Timer.cpp** - Updated constructor to accept and store name 3. **PyTimer.cpp** - Removed the `dealloc` cleanup that was erasing timers from `game->timers` when Python wrapper was GC'd 4. **McRFPy_API.cpp** - Added `createTimerWrapper()` helper and updated `api_get_timers()` to create new Python wrappers for orphaned C++ timers ### New Lifecycle Behavior: | Scenario | Behavior | |----------|----------| | `Timer("t", cb, 1000)` with no stored ref | Timer runs, Python wrapper GC'd, accessible via `mcrfpy.timers` | | `t = Timer("t", cb, 1000)` | Timer runs, Python wrapper kept alive by `t` | | `t.stop()` | Timer removed from engine, kept alive by `t` | | Timer fires with `once=True` | `testTimers()` removes from map, Timer GC'd if no Python ref | | New timer with same name | Old timer bumped from map, old Timer GC'd when shared_ptr→0 | ### Tests Added: - `tests/issue_180_timer_orphan_test.py` - Verifies orphan timers fire and are accessible - `tests/issue_180_timer_stopped_test.py` - Verifies stopped timer lifecycle Both tests pass.
john closed this issue 2026-01-07 00:57:22 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#180
No description provided.