I do love languages, and (as I wrote in my very first post on this blog) Copper has its origins in Goldfish, a language initially intended for AI. In a way, making a language was still on the bucket list, so the things I said in that post are not lie, but there is more to the story.
We could start by asking the question, “Why another language?” Certainly love of languages is nice, and certainly I would enjoy creating a language just for the sake of it. However, in my post “(,-o.c(((O) The Goals”, there were very specific criteria for this language. Those aren’t criteria I simply invent. In fact, were I creating a language for the fun of it, I might have tried to create a compiled language and targeted LLVM. More likely, I probably would have gone with Rust and contributed to its development. But no. I’m a man on a mission.
As it turns out, I was working on another project where an embedded language would have been very useful. From this project, I came up with a set of criteria for the language (which Copper is designed to fulfill). I looked at a number of good, promising candidates, but all of them had some quirk that made them unsuitable for the project I was working on.
First, the virtual machine (VM) needed to be self-contained. AngelScript automatically failed since it balloons into a module structure with files and forces you to handle initialization errors in a semi-annoying manner. The VM could be wrapped, but the needed file functionality couldn’t be, so AngelScript was out just on the basis of it requiring file access. Lua handling is a mess; the desired encapsulation simply isn’t there (it’s hard to explain though), so it was also out.
Second, the VM needed to be C++ and version agnostic or at least C++98 compatible in order to work with the libraries I was using. This scratched ChaiScript, which would have been excluded anyways on the basis of being more difficult to integrate than AngelScript.
Third, the VM needed to be in C++. Python and Lua were thus out. While Lua has C++ bindings, they aren’t reliable. There are many Lua bindings, so picking one up may have made me feel like the sole maintainer, at least as far as my project was concerned. That being the case, I’d rather maintain my own code. It’s more fun and better designed to fulfill my goals.
Fourth, the language needed to be interactive. Compiled languages were not necessarily out, as they could be used for other purposes, but I would then need a second language, which might fulfill both purposes. NekoVM was definitely out, though, because Neko is barely human-readable.
Fifth, the language needed to be fast. Lua and other languages requiring bindings were out. Compiled languages were in.
Sixth, the VM couldn’t use a garbage collector. Garbage collection running could be at the most inconvenient time, and manually forcing garbage collection after or before important sections would have both required the operation be performed more than necessary and caused undesirable slow downs.
It’s difficult to explain how all of these became the criteria without going into deep detail about the program in which the virtual machine would be used, so you’ll have to take my word for it. That said, fulfilling these criteria doesn’t make the winning language somehow more suitable for other things.
Designing Copper was my answer to the problem. I wanted the ideal scripting language for the job. It fulfilled most of the criteria, except that the current interpreter isn’t very fast, so I’d ultimately need a compiled language anyways.
One of the unspoken criteria is security. I wanted to be able to run a script from anywhere and be certain that it wouldn’t mess up my system or freeze my computer. After the redesign of the engine, I had a single segfault (that I quickly fixed) and that was it. All of the other bugs have manifested themselves in other ways or resulted in throwing exceptions (because I was smart enough to check for null all over the place). Of course, that’s only from my testing, and the Copper VM likely has a number of other hidden bugs I haven’t found yet. I can’t say how the other interpreted languages out there fare but I doubt safety was a key criterion in their design (or at least, as luck would have it, the one that would’ve worked best for fulfilling my other criteria would’ve been a failure on security).
Ironically, Copper would be suitable for a number of other tasks. With its safety and power, it would probably be good for a database scripting language, similar to MongoDB, but without the benefit of directly creating a file when you create an object. It might work something like:
clientDb.name = "myClientDB" clients ~ clientDb.clients clients.jerrywallace = [ firstName = "Jerry" lastName = "Wallace" age = 65 ] saveRecord(clientDb.name:, clientDb.clients)
Copper could also be used as a scripting language for project setup. Currently, there’s CMake, QMake, and Premake. I very much like Premake, but if I ever manage something more complex, it’d be nice to have the compile step built-in. Copper could make it both interactive and forgiving (if you make a mistake in Copper, it’s easy to simply redo without worrying about redefinition errors or typos within function bodies – just remake the function body before you call it).
I have fun just typing out ideas in Copper, so maybe I’ll use it for mind-mapping too.
That said, the current Copper virtual machine will definitely have some good uses even if it didn’t quite fulfill all of my intentions.