Press enter or click to view image in full size
Last week, Epic Games announced version 6 of their flagship Unreal Engine, one of the most popular and widely-used engines for video game development. Along with a host of other features, the flagship change is the deprecation of Unreal’s much-loved Blueprint feature and the introduction of a new programming language called Verse. We’ll get there.
Up front I want to make it clear that while I am a professional video game developer I do not have Unreal Engine experience — I’ve exclusively worked for studios using the Unity engine and I use Godot for personal projects. I do have friends and professional contacts who use Unreal and have spoken with them on many occasions about it, including in the lead-up to writing this piece.
With that out of the way, let’s talk about Blueprint: both what it is and why people like it.
Press enter or click to view image in full size
Blueprint is a visual scripting system: using graphical nodes and connections, a user can build custom game logic that applies to entities in the scene. Fundamentally this provides the same sort of control over a game’s behavior as any other form of scripting. Rather, the strength of Blueprint comes down to its accessibility.
As video games have grown larger and studios have ballooned in size, the individual roles performed by workers have become increasingly specialized. The old days of a single person writing Adventure for the Atari 2600 are long behind us, modern AAA experiences of the sort Unreal Engine is built to power have hundreds of people working on every aspect of the game. As a result designing the game has become a separate discipline from programming the game with different skillsets needed for each side of “making a game do a thing”.
What Blueprint enables, then, is for a designer to directly fiddle with the logic of the game without requiring them to know C++, the infamously finnicky language Unreal is built on. In my own experience in professional Unity development there is often a back-and-forth between designer and programmer iterating on a new feature, but with Blueprint that friction is reduced. Even better, Blueprint supports the creation of custom nodes, so in the event a designer wants something they can’t figure out how to build they can ask a programmer to build it for them. With Blueprint you can get the best of both worlds, rapid iteration without a need to know how to program combined with the deep control that writing C++ gives you.
Naturally, Unreal Engine 6 is deprecating Blueprint and replacing it with something new, Verse.
Press enter or click to view image in full size
Verse is, according to Epic, “the foundation for Epic’s future programming model”. It’s a new programming language built, according to the Book of Verse, on three fundamental principles:
- It’s Just Code: Everything written in Verse is code, built from the same primitive constructs.
- Just One Language: Verse uses the same constructs at compile-time and run-time.
- Metaverse First: Verse runs in a single global simulation, called the metaverse.
Oh no. If you’re like me, you already have some alarm bells going off in your head. For one, writing a custom language is rarely the correct solution for any engineering problem — language design is hard, and the reason “bad” languages like C++ or PHP or [insert your least favorite language] persist is because despite having deep problems they still do something better than the alternative. Something much bigger stood out to me from this initial section, though: Verse is code. In other words, Verse is not visual scripting, and it does not replace Blueprint. It’s doing a different thing, and if you work at a studio that relies on Blueprint to bridge the designer/programmer gap, too bad. Your designers need to learn Verse now.
Alright, but one of Epic’s stated goals for Verse is for it to be “simple enough for first-time programmers to learn, with consistent rules and minimal special cases”, so let’s take a look at what this language actually looks like.
Press enter or click to view image in full size
As an intro to the language Epic provides an Overview inside the previously-linked Book of Verse, which you can access here: https://verselang.github.io/book/00_overview/. Code samples here will be lifted directly from this page. Let’s read through it together.
Verse takes a page from the functional paradigm of language design by having no statements, instead only having expressions that produce values. As an example, here’s a simple if statement:
Result := if (Condition[]) then “yes” else “no”`If you’re familiar with a ternary expression from a C-like language or an if/then/else statement from other languages this will look deeply familiar to you — if Condition[] is a truthy value Result will store the string "yes" , otherwise it will store the string "no". This is pretty basic stuff and reasonable, although depending on your background you may be wondering how an array like Condition[] is truthy or falsey. The answer is that it’s not an array — we’ll get there.
Here’s a for statement that’s an expression:
Multiply := for (X : Array) { X * 42 }This is, uh. I’ll be honest I’m still not sure how to read this. I think this is defining Multiply as an anonymous function that accepts an array and multiplies each entry by 42? The overview document does not explain this whatsover and instead just says “loops are expressions”. It’s worth noting this is an overview of the language and not a document that is meant to teach you the language, so keep that in mind, but c’mon. What actually is this?
Now we move to “Failure as Control Flow”. Verse relies on failure as a primary control flow mechanism instead of boolean expressions and exceptions, which I’ll leave up to the reader how they feel about. This does however explain Condition[] : when calling a method that might fail, use square brackets, when calling a method that must succeed, use parentheses:
ValidateInput[Data]
ProcessData(Data)I don’t hate this, but it is definitely odd — if nothing else if we’re trying to make an easily-accessible language for newer programmers, adding a distinction between types of function calls is not something I personally would add. Additionally I’m not a fan of the square brackets notation (I’d do something like ValidateInput?(Data) if I was writing a language) but that’s just me.
Verse also offers strong static typing with inference, akin to what C++ gets with the auto keyword and C# gets with the var keyword. Personally, I think this is terrible and want var to die, but you might disagree. That’s fine, I suppose.
Press enter or click to view image in full size
But now we get to talk about one of the weirder features of Verse, and the one that eventually led me to realize the horrors of the language and what it represents: effect tracking. Let’s look at three small methods from the Book of Verse:
PureCompute()<computes>:int = 2 + 2
ReadState()<reads>:int = GetCurrentValue()
UpdateGame()<transacts>:void = set Score += 10In other words, all methods in Verse must have effect decorators on them that specify what sorts of side effects the method has. This isn’t totally new to Verse (Haskell and other pure functional languages have entire constructs dedicated to methods with side effects) but I’ve never seen a language decorate its function signatures with side effect declarations like this. To me this brings to mind Java’s checked exceptions, a family of exceptions that must be declared to be thrown from any method with the throws CheckedException decorator on the signature. Like checked exceptions I have to imagine these propagate, that is to say that GetCurrentValue() also has the <reads> specifier on it, and anything calling the ReadState() method will have to have <reads> . Having seen what infecting decorators can do to a large codebase I’m already scared of what a full Verse project might look like.
While we’re on this, I’ll point out that the early examples of expressions used := as an assignment operator, while these method declarations use = . I’m sure there’s some good reason for these as separate operators, but again if I’m designing a language to be friendly to new programmers I maybe am not going to introduce multiple assignment operators with different semantics.
Verse also offers built-in concurrency via its sync and race operators:
sync:
TaskA()
TaskB()
TaskC()race:
FastPath()
SlowButReliablePath()
These are fine, I suppose (they closely resemble the concept of Promises) but whereas Promises allow you to chain together complex graphs of asynchronous behavior sync / race do not appear to do that.
You’ve also probably already noticed this but Verse uses syntactic whitespace, aka Python’s worst “feature”. Stop it! Get some help! Braces are good!
We’ll skip Speculative Execution for a moment and move on to Reactive Programming with Live Variables, literally the only feature I do like of this language: with the live keyword, variables become reactives as a first-class language feature.
var MaxHealth:int = 100
var Damage:int = 0
var live Health:int = MaxHealth - Damage# Health automatically updates when dependencies change
set Damage = 20 # Health becomes 80
set MaxHealth = 150 # Health becomes 130
# Reactive constructs for event handling
when(Health < 25):
Log("Low health warning!")
This rules! More languages should have this. Shame we skipped the elephant in the room.
Press enter or click to view image in full size
Verse offers what it calls “speculative execution”, with this as a minimal example:
if (TryComplexOperation[]):
# Changes performed by TryComplexOperation[] are committed
else:
# Changes are rolled back automaticallyIn other words, the code attempts to run the method TryComplexOperation, and then has branching paths depending on if it succeeds or fails. Notably, if it fails, all changes made by TryComplexOperation are automatically rolled back.
What does this mean? For one it means that Verse cannot decompose into simple machine language with roughly one-to-one execution. Instead all changes made by Verse must be cached somewhere so that if a method fails, all changes performed by the method can be rolled back. This isn’t inherently terrible, mind you. More modern languages often rely on a language runtime, specialized software that performs background actions and provides features to the language that bare metal does not — a good example is garbage collection, when the runtime automatically frees up unused memory, relieving the programmer from the burden of having to track and release memory and helping prevent memory leaks and other memory-related bugs. But does Verse use a Verse runtime to support this?
Well, no. Remember, Verse is “metaverse first”. It’s designed to run “in a single global simulation”. Verse is written for a future where “code lives forever in a persistent metaverse”, “millions of developers contribute to a shared codebase”, and “the boundary between compile-time and runtime is fluid”. In other words, Verse isn’t made to run on your computer. It’s made to run on Epic’s.
This is the whole reason for the effects system. In Verse, when you write a method you’re not writing a method, you’re writing an RPC (a “remote procedure call”, for the non-technical among us). All your code runs on Epic’s system, and the decorators are there to let the system know what sorts of access to the broader global “metaverse” state your code needs. The reason failed methods rollback their side effects is that Epic’s system is maintaining your game’s state, and when the method fails it manages that rollback for you.
We’ve completely moved away from Blueprint here. Blueprint is a system that enables better workflows for designers and programmers, that opens game development up to non-programmers, and that allows large teams to work more effectively by separating “designing game logic” from “interfacing with code”. Verse does none of this. Verse moves all the game logic back into code and does away with the more immediately-understandable paradigm of visual scripting.
Why does Verse exist? Verse exists because Epic wants your game to need Epic, even beyond the point where it goes gold and presses to disc for a consumer to purchase. Verse exists so that they can run your game on their server and extract rent from you even when your game is in maintenance mode. Verse exists to make it easier to integrate your game into Fortnite, so that instead of selling your game through Steam or PSN or the Microsoft Store they can turn Fortnite even further from a game into a digital storefront. Verse exists to extract rent from developers.
Capitalism you’ve done it again.