HelloWorld("print")
Everyone knows the classic print("Hello World") program they might have written when they first started learning programming. Recently, I saw a meme version of it, where instead of print("Hello World"), it’s HelloWorld("print") accompanied by Elliot from Mr.Robot saying “Sometimes I dream of saving the world”.
It’s incredibly stupid, but it made me think if it was actually possible to define a function like that.
A simple implementation would be just to hard-code print(“HelloWorld”), but I wanted more of a challenge.
More specifically,
- Can’t hard-code the function being called (“print”) inside the function body
- Can’t hard-code “HelloWorld” inside the function body
Javascript #
First, let’s define a simple print function:
function print(...args) {
console.log(...args)
}
Getting the print function from a string “print” is easy since we can index the window object directly, but getting the function name from inside the function is not so obvious.
Luckily, there exists a not-so-well-known arguments object, which is an array-like object that contains a list of the function parameters. It was used before the ...rest syntax was introduced. This arguments object has a callee field, which is a reference to the currently executing function. We can then use arguments.callee.name to get the current function’s name.
arguments.calleeis deprecated and only works in non-strict mode, but it’s still supported in all browsers (even LadyBird). It was added because people wanted to do recursion inside anonymous functions:// calculates factorials on a list of numbers [1, 2, 3, 4, 5].map(function (n) { return n <= 1 ? 1 : arguments.callee(n - 1) * > n; });In modern JS there are much better ways to do this.
Now onto the actual code. We can define HelloWorld like this:
function HelloWorld(fn) {
window[fn](arguments.callee.name)
}
> print("HelloWorld")
HelloWorld
> HelloWorld("print")
HelloWorld
That works. What if we want to use any function, like console.log? For that, a simple window[fn] won’t cut it anymore, but we can use the good old reduce function:
function HelloWorld(fn) {
fn.split(".").reduce((acc, f) => acc[f], window)(arguments.callee.name)
}
Taking the window object, and repeatedly indexing into it (window –> window[console] –> console[log]).
That works, but we’re totally forgetting that JavaScript is an interpreted language. We can just use eval!
function HelloWorld(fn) {
eval(fn)(arguments.callee.name)
}
> console.log("HelloWorld")
HelloWorld
> HelloWorld("console.log")
HelloWorld
Fascinating stuff.
Python #
def HelloWorld(fn):
import inspect
eval(fn)(inspect.currentframe().f_code.co_name)
The python one is very similar, but we need to import inspect from stdlib first to get information about the current frame on the call stack. The f_code field on the FrameType object contains a CodeType object, which is actually the thing that the interpreter is interpreting. You can view the byte-code of the current executing function (co_code) or get the function name (co_name).
> print("HelloWorld")
HelloWorld
> HelloWorld("print")
HelloWorld
Now you can enjoy HelloWorlding print in peace with two of the most popular programming languages.
If you have a favorite language that is not Python or Javascript, maybe try doing this in that language? You just might learn something new.