[HN Gopher] Redefining Go Functions
___________________________________________________________________
Redefining Go Functions
Author : todsacerdoti
Score : 75 points
Date : 2026-02-10 14:27 UTC (8 hours ago)
(HTM) web link (pboyd.io)
(TXT) w3m dump (pboyd.io)
| pstuart wrote:
| Yikes, I don't see any legitimate use for this, other than
| hacking for the sake of hacking. Interesting read though.
| maccard wrote:
| Hot reloading for development loops is _the_ canonical use case
| for this.
| throwa356262 wrote:
| Well, we are on Hacker News after all...
| antonvs wrote:
| wdym, now it will be possible to implement Wordpress in Go
| pjmlp wrote:
| You could already do that today, via OS IPC mechanisms, at
| the expense of higher systems resources, with each plugin
| being its own process.
| lokar wrote:
| I've seen this in large C++ systems to allow for a runtime
| patch, generally to add a simple debug call at the start of a
| function.
| jerf wrote:
| While I would never consider this approach _advisable_ in any
| language that doesn 't build in support for this sort of
| thing from the start, the thinner the runtime, the less
| dangerous it is. Go's runtime is fairly thick, and also,
| concurrent. The odds of something blowing up are rather too
| high for me to even dream of putting something like this into
| production in Go. In C++ it may merely be somewhat crazy
| rather than completely crazy.
|
| (I suppose Rust is arguably an exception to this; thin
| runtime, but there's a lot of things the replaced function
| could do that would still blow Rust up if the rest of the
| code isn't compiled and correctly optimized to account for
| whatever the new code does.)
| jerf wrote:
| Other prior art: https://github.com/bouk/monkey with accompanying
| blog post https://bou.ke/blog/monkey-patching-in-go/
| bouk wrote:
| Wow 11 years ago, takes me back...
| MadVikingGod wrote:
| This is all possible and quite neat to dive into the specifics,
| but if you really want to be able swap a std lib call, just turn
| it into a variable and change it. // code.go
| var now = time.Now // code_test.go func
| TestCode(t *testing.T) { nowSwap := now
| t.Cleanup (func() { now = nowSwap }
| now = func() time.Time { return time.Date(...)
| } }
|
| Examples Code: https://github.com/open-telemetry/opentelemetry-
| go/blob/main... Test: https://github.com/open-
| telemetry/opentelemetry-go/blob/490f...
| antonvs wrote:
| The point of the OP is that it changes calls to `time.Now`
| regardless of whether the code that's calling it uses your
| variable or not.
| Groxx wrote:
| I _suspect_ that using a build tag (say `test`) and two
| function definitions (one that directly calls `time.Now()`
| and one test-only one that uses a mutable var) will optimize
| out to zero cost in the non-test case - last I fiddled with
| that, it was pretty good at consistently inlining trivial
| wrapper funcs like that.
| awesome_dude wrote:
| The compiler will only use _test.go files in the test build
| - so not an explicit build tag, but a built in one.
| Groxx wrote:
| That doesn't give you a way to exclude conflicting code,
| unfortunately, so you can't provide an optimal one for
| non-test code with it.
|
| And stuff like `func SetTime(...)` in a _test.go file
| only works for tests in that same package, because other
| packages don't compile that _test.go and won't have that
| function defined.
| metadat wrote:
| That is a useful pattern, though I was unclear on why
| `t.Cleanup` and not `defer`. In case others are curious, too:
|
| _> Parallel subtestsWith t.Run(..., func(t _ testing.T) {
| t.Parallel(); ... }), the parent test function can return (and
| thus run its defers) before parallel subtests actually finish.*
| matttproud wrote:
| Short version is this:
|
| If you are going to get into the business of introducing
| order dependence to test cases through global state (see my
| other reply on the parent), you will always want the cleanup
| to work correctly.
|
| 1. Using (testing.TB).Cleanup is a good defensive habit to
| have if you author test helpers, especially if the test
| helpers (see: (testing.TB).Helper) themselves do something
| (e.g., resource provisioning) that requires ordered teardown.
| Using (testing.TB).Cleanup is better than returning a
| cancellation or cleanup function from them.
|
| 2. (testing.TB).Cleanup has stronger guarantees about when it
| is called, especially when the test case itself crashes.
| Example: https://go.dev/play/p/a3j6O9RK_OK.
|
| I am certain that I am forgetting another edge case or two
| here.
|
| Generally nobody should be designing their APIs to be
| testable through mutable global state. That solves half the
| problem here.
| matttproud wrote:
| This is often the path of pain:
| https://google.github.io/styleguide/go/best-
| practices#global....
| spenczar5 wrote:
| Its unexported for that reason. You only change it in tests.
| awesome_dude wrote:
| Just for the record - this is package local - it's fine within
| the package it is defined in, but no other package will use the
| implementation, they will all use the standard library.
|
| Others have linked to the much more "fun"
| https://github.com/bouk/monkey which is an actual monkey patch,
| in that it changes the code that is called from anywhere in the
| runtime
| nasretdinov wrote:
| I've used a different approach to this: there's no real need to
| modify the compiled binary code because Go compiles everything
| from source, so you can patch the functions at the source level
| instead: https://github.com/YuriyNasretdinov/golang-soft-mocks
|
| The way it works is that at the start of every function it adds
| an if statement that atomically checks whether or not the
| function has been intercepted, and if it did, then executes the
| replacement function instead. This also addresses the inlining
| issue.
|
| My tool no longer works since it was rewriting GOPATH, and Go
| since effectively switched to Go Modules, but if you're
| persistent enough you can make it work with Go modules too -- all
| you need to do is rewrite the Go module cache instead of GOPATH
| and you're good to go.
| cronelius wrote:
| This is cool, just don't let Rob Pike see this, he will have a
| conniption. Glad you called out that it shouldn't be used because
| this is about the most magical thing I have ever seen in Go
| adonovan wrote:
| The lesson of the post is that Go is compiled to machine-
| specific object code mapped to a non-writable text segment in
| an OS-specific process. What's really magical is that compilers
| save you from such dangerous and non-portable details.
| dveeden2 wrote:
| > There you go. It's 5PM. It's always 5PM.
|
| That reminded me of the Go Playground, where it is always 2009
|
| https://go.dev/play/p/VrWYHGbtc6m
| draxil wrote:
| Spirit of Perl is still alive
___________________________________________________________________
(page generated 2026-02-10 23:01 UTC)