Few days ago I saw a post about using hieroglyph unicode characters in Haskell to write fully functional haskell code. They shown an example of map
function. A function that applies a function to a collection of items. Pretty much how foreach
does in PowerShell.
I thought this was fun, and tweeted this:
That code uses capabilities of PowerShell that has been there since I started using it. We can use the smiley face as the function name because it is a valid unicode character and is not a restricted character. And then we can use it the same emoji again as the parameter to the function. All we need to do is wrap the variable name in ${}
. This sequence of characters is recognized by PowerShell as an escape sequence and allows us to define the variable name as any sequence of unicode characters, except for the closing curly brace. This is mainly meant for interoperability with code that does not follow PowerShell rules, but why not use it to have a bit of fun.
Another example of emojis in code is this hello world example:
This is still fairly recognizable as PowerShell code, we are just using special characters for that function name. This was not enough for me and I wanted to get closer to coding purely in emojis, like emojicode does it.
So I came up with this:
This is totally valid PowerShell code that defines four functions, and then uses them.
Here is how it works
Note: I had some trouble rendering the 1️⃣ 2️⃣ glyphs in code, so I will be using 🍺 🍻 instead of them in the rest of the article. Beer is more awesome than keycaps anyway.
We use 🐙 to define a function, as if we used the function
keyword. After that we define the name of the function, followed by function parameters. We don’t know how many parameters there will be so we need to separate them from the function body. To do that we use the most famous emoji, the pile of poo 💩.
The first function is named 🥓 (bacon) and returns bacon as a string. We use 🔤 to denote the start and end of a string. Here is the whole function definition:
🐙 🥓 💩 🔤🥓🔤 |
The next two functions are building on the same idea, but we are defining 🍺 to mean 1
and 🍻 to mean 2
.
🐙 🍺 💩 1 |
The last function definition ➕ (add) is more interesting, we define two parameters 🅰 and 🅱, we then add those two parameters together.
🐙 ➕ 🅰 🅱 💩 🅰+🅱 |
And we can use it like this:
➕ 🥓 🥓 # returns 🥓🥓 |
How does that work?
In essence we are not doing anything particularly difficult. Translating the code above into normal PowerShell code it would look like this:
function bacon { 'bacon' } |
There are just few problems that we need to solve:
make 🐙 generate valid PowerShell function
make 🐙 define that function
get rid of the parentheses when calling functions
Generating a function
A proper PowerShell function consists of four things. The function
keyword, the name of that function, parameters block, and function body. Schematically it looks like this:
function <name> { |
The simplest function to generate is the 🍺 function. It simply returns the number 1
when called. All we need to do is split the list of emojis to two groups based on where the 💩 separator is.
$separator = '💩' |
The first item from the first group is the function name. All the following items are the parameters, in this case we don’t have any. All the items in the second group go into the function body. Luckily there are no special characters to be translated, so we don’t have to deal with that just yet.
Our function generator would then look like this:
function 🐙 { |
Defining a function
Our generator generated a function body as string, and now we need to define that function. In PowerShell there is a reserved keyword function
that we use to define functions. Using this keyword we can define function within the current scope. Unfortunately this is not what we need. Our 🐙 must be able to define a function outside of itself. Luckily you can define a function as a global function, to make it available in all scopes. We already have our function as a string so the best way to proceed is adding gloabal:
before the function name, and invoking it via Invoke-Expression
. Like this:
Invoke-Expression "function global:🍺 { 1 }" |
Not being able to define functions in any scope we want is a bit that is surprisingly missing from PowerShell when you realize that Set-Variable -Scope 1 allows us to do just that. In this case we don’t mind defining functions as global, because this whole thing is a silly example. But if you really need to define function in the parent scope of your function, you can look at my Mock module prototype that uses the same trick as
Invoke-Expression
uses to run code outside of itself. That allows theNew-Mock
function define functions that live in the parent scope.
Get rid of the parentheses
We defined 🍺 as a function that returns the number 1
. Using it in function call without parentheses would pass on the literal value 🍺, instead of calling the function and passing on the number 1
. This is a bit of a problem for us, but luckily we know that all functions are accessible via Get-Command
. All we need to do is check if 🍺 is a defined function and call it inside of our generated function.
function f ($value) { |
And that is it. A cleaned up version of the whole compiler function then looks like this:
# split to whole unicode characters, cannot use ToCharArray, |
Summary
I had a lot of fun with this. More of us did, actually. Matthias wrote his own version, from which I used some bits for this article, see his version. You can also find the twitter threads here and here.