00:00:08.000
I'm surprisingly nervous today, combining my thoughts. First, let me introduce myself. I didn't create this esoteric language; I'm just implementing it.
00:00:12.500
As you can see from the JRuby logo here, this isn't a JRuby talk. It's about an esoteric programming language. I don't usually look like this, but it is my avatar. I co-lead the JRuby project and work at Red Hat. My hobbies include wine and craft beer, so if anyone knows a good brewery in the Houston area, I'll be here until Sunday morning.
00:00:21.930
I know there are a lot of opinions on that matter. So, what exactly is an esoteric language? If we look at Wikipedia, it has a lot to say, but it's all quite vague. Essentially, it's a language intentionally designed to be hard to understand and read. The most famous one is Perl. I've used Perl for 10 years and I genuinely like the language, so I feel entitled to make this joke.
00:00:54.449
I wanted to point out that if you've never seen Perl before, you can still figure out that this prints something out five times. When you look at it, it seems like creating a space for an object is natural. However, once you start looking at some of the Perl 6 features, it becomes confusing for many Perl programmers. Essentially, something may seem esoteric if you have no experience with it. My philosophical part of this talk is done now, but it's something to think about.
00:01:19.680
Now, I'm going to focus on 'Piatt' for the rest of this talk. It was named after Piet Mondrian, who is responsible for the artwork on the right. I find it amusing how he looked much cooler when he was younger. I don't know how you can evolve into something unrecognizable, but perhaps bad choices accumulate with age.
00:01:44.050
So, I'm going to talk about the language itself. It's image-based, similar to Smalltalk. Your source code is literally an image—it’s a PNG image. If you go and execute this program, it prints 'Piatt' to standard output. It's also known as a 'Fund' language because it works with coordinate systems, which makes sense since the program is an image.
00:02:01.290
It's stack-based as well. In fact, most esoteric languages are based on stacks and are quite primitive machines. Piatt's structure is based on a grid made up of n-by-n pixel squares. On the upper left-hand corner, we have a 3x3 pixel group, which has a size of nine. Next to it is a dark blue group, which may be slightly altered by adjacent colors.
00:02:30.920
There is some runtime state called the direction pointer which initially points to the right and navigates around in a clockwise manner. It can change, however, with execution. Moreover, there is a color chooser that can either be left or right. You carry out Piatt's program by moving from one group to the next based on a navigation rule.
00:02:58.250
You need to follow the direction pointer to the farthest extreme of the group and then, depending on whether the color chooser is set to left or right, you move to the leftmost or rightmost extreme. Oftentimes, that's the same color.
00:03:09.310
To illustrate, when we start the program, we enter this normal blue group and the direction pointer is set to right. If the color chooser is left, we enter at the top; but if the color chooser were set to right, then we would enter at the bottom. It's quite simple.
00:03:29.480
Let's move to a slightly more tricky example in this group where the direction pointer is right and the color chooser is left. We go all the way to the right and select the top one to progress. Clearly, if the direction were set to right, we would go there.
00:03:47.289
This looks like a simple language, doesn't it? Well, there are six colors, and each color has three different shades. When you move from one group to the next, you look up in this table to determine what operation you should perform. You have stack-based operations, math comparators, input and output, and then pointer controls that typically take the top value and manipulate those values.
00:04:10.519
These three transitions of blue demonstrate the process of going from lighter to darker shades. This transition can function as a push operation, indicating a cycle where the darkest value transitions to the lightest. In contrast, here's a divide operation, where you merely follow the circle around.
00:04:29.800
Let's step through the program a little bit more. We enter from the upper left-hand side into the normal blue section. As we need to transition to dark blue, we'll look up in the table—which indicates that the next step is to go one shade darker. We will push in a value, defined as nine in this case; that is the size of the normal blue group.
00:04:50.710
This is the only group size that I’ll mention for now. So, stepping to the next phase, we focus on black, which means going off the image or encountering an impassable obstacle. Whenever you run into those conditions, you utilize an algorithm to assess movement based on the color chooser and the direction pointer, up to eight attempts. If a valid next action is found, you proceed; otherwise, the program terminates.
00:05:08.240
Returning to our step with the color chooser directing left/right, we will move down and navigate accordingly. Consequently, white represents a no-action; you can slide right through it, and in fact, placing other unrecognizable colors in the white space is also permissible.
00:05:23.340
Let me tell a joke to lighten the moment:
I'll do anything for humor! After engaging with 'Piatt', I've created it into a gem. I just realized this morning that I hadn't actually released it since I finished my work. For demonstration, here’s a simple program using our Piatt gem. You can download an image from the internet and execute it, which is quite fascinating! Furthermore, after executing this program, a prompt appears for user input. The interesting bit is that it can get convoluted, leading to some 'mind-bending' experiences.
00:07:23.070
Another cool feature is the ability to specify the covel size. For instance, if you input a 2x2 colon, it prints 'Piatt'. If you use a covel size of one, it prints 'Hello World'. This is quite unusual.
00:07:38.620
Conceptually, if you go to the upper left, the first value you push is something half the image height representing the radius. Later, you input a jagged circle as the area and perform calculations to derive a rough estimate of Pi. As the image grows larger, this estimate improves, but it'll never be perfect.
00:08:03.000
The core of the talk revolves around implementing our 'Piatt'. To achieve this, I ported Python code to Ruby. However, I'm not particularly well-versed in Python, so it resulted in some errors.
00:08:35.060
The initial file I started with was a single dot PY file. When first creating a non-functional program, the natural response is to troubleshoot it. It turned out that all Piatt interpreters share similar debugging outputs, which proved advantageous as I began making example programs run. Subsequently, I decided to take it a step further by creating a graphical debugger.
00:09:01.740
Here’s a brief demonstration. This is the program I've created, which counts down from a million—or any number I input. I'm taking in numeric input and echoing it. You can step through it while observing the stack operations. I also set breakpoints for more control.
00:09:50.980
Next, the stack visibly reduces from three down to two as it processes the values. As execution proceeds into a conditional branch and the pointer command, I likely should have pressed back to two on the stack a couple of times.
00:10:22.840
After optimizing some elements, I decided it would be prudent to begin writing tests. I created an ASCII image format that streamlined some of the processes compared to working with images directly. Additionally, I ended up developing an image generator application.
00:10:51.839
One key point to note is that the debugging capability we used was based on JRuby and utilized a library called JRubyFX, which is quite slick. The image generation application was built with another JRuby library called ImageMagick.
00:11:09.750
This isn't the last mention of JRuby, however. Once you generate an image, you can run it across various implementations to ensure consistency. When creating the program I demonstrated earlier in the graphical debugger, I initiated an ASCII image format.
00:11:26.360
After five minutes, I realized I wanted to add a second loop in the center, which needed adjustments to the remaining color sequences. Since every color after that second loop would change, I created a tool to regenerate these sequences. It's all one-dimensional, but it greatly simplified the process of image generation.
00:11:47.490
Initially, I began with the Python implementation, but I found myself unimpressed with it. Albeit you likely won’t read this code, it's what I would call 'code chowder', which combines various elements chaotically. Each Piatt implementation usually contains similar code structures, just in different programming languages.
00:12:12.260
We face two main issues: I can't accelerate my conversions any further and those out-of-bounds checks degrade the performance when evaluating up to eight times. Unfortunately, this presents challenges to optimizations since we are merging two concerns: parsing and execution.
00:12:30.319
To move forward, does anyone recall McDoodles? When typically processing programming languages, you would parse to produce an abstract syntax tree. In this instance with Piatt, this graph is two-dimensional and may introduce natural cycles.
00:12:55.590
Based on this idea, we're committed to designing an abstract syntax graph. This graph will represent each operation we execute, and nodes will reflect operations like addition, subtractions, and direction pointers. Each time we reach the edge of our image, we’ll log that and adjust the runtime state.
00:13:20.940
Now, let me illustrate a somewhat challenging slide. At the inception of our implementation, the first priority is managing the 'not' operations using the graph interpreter, which pulls a value from the stack, checks if it equals zero, and subsequently pushes one or zero back under the stack.
00:13:42.250
This first line consequently equates to a pop instruction. Thus, we achieve a seamless mapping for the instruction that saves the popped value and lines up the remainder.
00:14:01.960
For those familiar with assembly language, this should resonate; think of it as a straightforward if-else statement. This approach checks the last variable and restarts processing the graph. The outcome is a streamlined list of elementary instructions.
00:14:27.069
For every occurrence demanding a jump or branch, we’ll note the label within the instruction list, which appears uniquely at another point in that list.
00:14:41.699
Here's the complete list of instructions for executing. You initiate at the start of the list, retrieve and perform an instruction. For branches, the label directs you to the appropriate next step, enhancing performance and optimizing execution.
00:15:06.389
As an overview of the performance when counting down from a million, the execution time improved roughly seven times faster. There's a multitude of invariants occurring throughout this process.
00:15:28.149
But we won’t halt here; we'll explore additional accelerations by converting the abstract syntax graph into a suite of virtual machine instructions, serving as input for a compiler back end.
00:16:05.069
Taking a closer look, we aim to eliminate cycles, which can create discrepancies for a compiler back end. Thus, every cycle will transition into a jump or branch statement.
00:16:30.049
Following through, the remaining operations will translate into a more detailed variant of virtual machine instructions. Here’s a very challenging slide, but it’s worthwhile.
00:16:56.720
The initial subject of backend operations is the 'not' implementations through the interpreter graphs, which facilitate a valuable push and pop sequence, enhancing processing efficiency.
00:17:25.110
I know this might become convoluted. Nevertheless, implementing a functional virtual machine adds complexity to the process as we maintain a program counter and manage jumps.
00:17:49.110
Even with this adjustment, we aim toward compilation, which gives rise to developing a back end. This is when matters begin to get truly peculiar.
00:18:07.640
My extension of work on JRuby and familiarity with its internal instruction sets—as when parsing Ruby code—translates efforts into generating virtual machine instructions that encapsulate our Piatt code.
00:18:32.820
If one finds themselves immersed in JRuby, they can use piatt by requiring the image file and subsequently executing the lambda returned. Consequently, JRuby accommodates both Piatt and Ruby.
00:19:14.520
Analyzing the results reveals a growing speed disparity. The first number illustrates running JRuby in interpreted mode; you'll see it's about 17 times faster compared to executing the Piatt instructions directly through its interpreter.
00:19:44.510
This increase arises from combining fast Java execution with any optimizations implemented in the JRuby framework. Moreover, if I compile it, performance impressively boosts another five times.
00:20:13.920
So far, I've managed a 305-times speedup overall. Additionally, I aimed to run benchmarks using LLVM to count down from a million and could employ various compiler optimizations.
00:20:47.566
Alas, time constraints thwarted those endeavors; I also anticipated discussing JRuby's optimizations, but this 25-minute session already accommodates too much material.
00:21:16.000
To conclude, delving into various programming languages is highly enjoyable. It’s commonly acknowledged that many people learn new languages for utility and job opportunities.
00:21:40.320
However, esoteric languages expand your minds divergently, engaging you in ways you might not foresee. Working with a language based in two-dimensional flow is undeniably fascinating.
00:22:06.000
I encourage you to explore esoteric languages as this talk demonstrates that you can transform mired code complexity into refined functionality that performs excellently.
00:22:23.290
Thank you.