Mmm. Changing control flow based on introspection of the call stack is reasonably nasty.
I recall we found a neat use for call stack introspection in one project - not to change control flow but to improve logging. Inside an open_db_connection utility function, to auto-generate an informational name describing which part of the codebase had opened the connection:
E.g. some_backend_process: main -> ... > grandparent -> parent -> open_db_connection
We'd use information from the call stack generate a string "some_backend_process grandparent.parent" describing the call site which could be passed to postgres as the application_name [1] when establishing a connection. Then from the database side, if we had problematic queries at runtime, we had a lot more clues to figure out which part of the backend codebase was responsible [2].
There'd be a way to do something equivalent without peeking at the call stack, by requiring the caller to explicitly pass a descriptive & unique name, but that makes things a bit more error-prone, especially since some devs would be prone to copy-pasting chunks of existing code & reusing the same name everywhere.
> There'd be a way to do something equivalent without peeking at the call stack, by requiring the caller to explicitly pass a descriptive & unique name
Agree with your tradeoff here. "No instrospection, ever" can also be harmful. Reminds me how 'no global mutable state' also needs to be broken in some cases.
Funny, my logging module for Python does the same (if requested with an optional keyword argument). It fetches the call stack, removes it's own functions, replaces Python library function chains with a single [...] and prepends it to the log output (together with usual date and time).
I recall we found a neat use for call stack introspection in one project - not to change control flow but to improve logging. Inside an open_db_connection utility function, to auto-generate an informational name describing which part of the codebase had opened the connection:
E.g. some_backend_process: main -> ... > grandparent -> parent -> open_db_connection
We'd use information from the call stack generate a string "some_backend_process grandparent.parent" describing the call site which could be passed to postgres as the application_name [1] when establishing a connection. Then from the database side, if we had problematic queries at runtime, we had a lot more clues to figure out which part of the backend codebase was responsible [2].
There'd be a way to do something equivalent without peeking at the call stack, by requiring the caller to explicitly pass a descriptive & unique name, but that makes things a bit more error-prone, especially since some devs would be prone to copy-pasting chunks of existing code & reusing the same name everywhere.
[1] https://www.postgresql.org/docs/current/libpq-connect.html#L... [2] https://www.postgresql.org/docs/current/monitoring-stats.htm...