Redefining Go Functions
February 10, 2026
I once wrote a Perl subroutine that would memoize the subroutine that called it. That much was useful, but then it inserted a copy of itself into the caller, so that its callers would be memoized too. A well-placed call to aggressively_memoize could back-propagate to the whole codebase, spreading functional purity like a virus. The resulting program would get faster as it used more memory and became increasingly static.
That was possible because Perl, like many interpreted languages, allows functions to be rewritten at runtime:
no strict 'refs' ; * { $caller } = $new_sub ;
Overuse of this feature earned it the derisive nickname “monkey patching”. Spend a couple hours debugging why your random numbers aren’t so random only to discover you have a mock RNG implanted by some distant dependency and you’ll hate it too. But these days I program mostly in Go where such nonsense isn’t possible. Right?
Well, no, not exactly. True, Go doesn’t offer this as a language feature. But a CPU executes instructions from memory, and we can modify memory. Did Go fundamentally change all that? Not at all. In fact, Go gives us all the low-level tools we need to do the job.
Let’s say I prefer Alan Jackson’s sense of time over whatever reality time.Now cares to remind me of. So I want this function to replace time.Now :
func myTimeNow () time.Time { return time. Date ( 2026 , 1 , 30 , 17 , 0 , 0 , 0 , time. FixedZone ( "Somewhere" , - 5 )) }
The first thing we need is the address of the real time.Now . The easiest way is with reflect :
... continue reading