[MUSIC PLAYING] [APPLAUSE] TIM SWEENEY: Hey, everyone. We're back to talk about Verse,
the new programming language that we've been designing
for the metaverse. So Verse is about solving the
larger problem of the metaverse. Verse is launching in
Unreal Editor for Fortnite. But we have much longer-term
and bigger plans for it. Essentially, it's aiming to
provide a programming language solution supporting development
of many kinds of games and other real-time 3D simulations,
supporting a full development cycle of tools and content
creation for the metaverse. I'd like to say a little bit about
what we see this as, ultimately, because the metaverse is more
than Unreal Engine is today. And it's more than Unreal
Editor for Fortnite is today. But it's about social interaction
and shared real-time 3D simulation, right? The metaverse is
about the experiences people are playing today in Fortnite
and Roblox and a whole lot more, and what this becomes as it
evolves into a medium for billions of people. And we're talking
about the metaverse as a long-term open economy. And so when we talk about what
we're shipping with Verse today, we're really shipping one
thing, but we're designing for a much, much
longer-term set of features and set of aspirations for this thing. And the metaverse, importantly,
is not just another app platform. When you release an app,
you use a bunch of libraries. But you compile one piece of
code, you ship it, and it doesn't change again
until you release a new version, whereas the metaverse, we think,
will be the combination of millions of objects written by millions
of different developers-- a lot of code, a lot of content
that's constantly being updated-- in which vehicles from
one developer, together with characters from another
developer, have to work together, even if those programmers
have never met each other or never tested
their content before. So we're talking a
programming world that's quite different than
the ones of the past, and one which requires a very
robust framework supporting these sorts of usage cases. And so the metaverse needs a special
kind of programming foundation, right? We want something, first of all,
that's really easy to learn. We want it to be somebody's
first programming language, just like JavaScript is
to web programmers today. We also want a language that
enables us to catch problems at development time
before we've shipped content to millions of users. The cost of fixing a problem
once it's already shipped are much, much,
much higher than catching bugs. So we want a strongly-typed language
that we can count on the compiler to guide us on what the
problems with the programs are before we ship them. We also want a
language that's really conducive to writing
lots of modules by different authors which can
work together and evolve over time while maintaining
backwards compatibility. So this open-world interoperability
is a big design goal for the entire system. We're also thinking of a programming
framework which can eventually scale to massive simulations. Fortnite Battle Royale is 100
players together in a single shard. But in the future, we might be able
to get a billion users together in a single shard. And we want a programming
model that can support that. We also want a language, and
we've been putting a lot of effort into building a specification
with enough rigor that it could be a future open
standard that's agreed on and widely implemented by companies
all around the industry, just like JavaScript is
in a web browser today. So Verse is our attempt at this. And we're aspiring to create a
strongly-typed language that's very recognizable to programmers who've
used any of the mainstream popular languages today,
whether it's C# or Python. We want something that's
not too scary but is at the leading edge
of compiler technology and being able to catch
problems at compile time. So there are several other
principles guiding this. And we're kind of learning
from the mistakes of the past. We want a programming
foundation that is just code, where you're not writing
code in one language that constructs queries
in another language and converts them to strings
and sends them off to a database and then parses the result, where
a whole lot of different languages are interoperating through
some clumsy interfaces. We want a single language
where you can just write code that gets your job done. We also want a language that can
scale to transactional programming in the future. If you think about a simulation
that might scale, be it far, far beyond the capabilities of a
single node in a data center, transactions are the core technology
that supported databases scaling up to huge data sets and
to huge concurrency. And transactions, we think,
will be the future programming model that enables code to scale
up without becoming complex. We also are aiming to build a
language that can do everything-- supporting code in multiple
paradigms, a language for data also. Just like JavaScript has
JSON for describing data, Verse has VSON, a subset of language that can describe data accurately. And even things like markup-- there's a markup language
embedded in Verse. It's not usable today,
but it's in the specification that will evolve in the future,
and even more advanced features for the future. We've also put a lot of effort
into building a language that's, to a certain extent, timeless. We have this question. What happens if we met some
aliens for the first time and compared our
programming languages? Well, I think we'd find that
we have a lot in common. But they probably don't have
32-bit or 64-bit integers. And so we want a
programming language that's free of the temporary
constraints of current systems. And to do this, we recognize that
we're building in a very long-term evolutionary environment,
where we're shipping one-- we're designing a language
for the very long-term future. And we've coded in that MaxVerse. And we have a massive
specification written out on paper for what we want the
language to eventually be. And we're working to that step by
step in what we call BetaVerse. This is the beta version of the
language that's launching right now. It has a limited subset
of those features. But we have a nice clear
path for it step by step. We can get closer and
closer to the ideal so we don't end up painting
ourselves into a corner as we evolve the language, as so
many others have done in the past. And we're holding ourselves to very
rigorous backwards compatibility standards. Now, these are going to be
relaxed during the Verse beta. But when we get to
the open metaverse, we really need a
programming foundation where your code does
not break every time a new version of your
metaverse browser comes out or that doesn't differ between
different browser engines. You want something that's
very stable and very reliable as a foundation for all of our
long-term development plans. And so now, to talk about the
specifics of the language, I'd like to invite up Phil Pizlo,
the director of language engineering at Epic. Phil? [APPLAUSE] [MUSIC PLAYING] PHIL PIZLO: Hey, everybody. So I'm super excited to
show you Verse by example. So let's just jump right in. Let's say that you
want to define a value, constant value called X,
and set it to the value 42. This is what it would look like. And here we've given
it the type int. Although it is also possible
to write this without the type, if you just say X :=
42, the compiler will figure it out that
this is an integer. And here we're defining
a constant value. Later on,
I'll show you how to define values that are mutable, like mutable
variables in most other languages. Here's an example of an array. Again, here I've given the type. So the type is square bracket
int, which means an array of int. And the value is the three
integers 1, 2, and 3. Of course, I can also do that
without specifying the type, and the compiler will
just figure it out. So let's get into something a little
bit more complicated-- functions. Verse supports a function syntax
that is very similar to mathematics. So here is just a
one-liner function. It'll take an X and return X+1. You could also put the
X+1 on the next line. Verse supports syntactically
significant indentation like Python and Haskell. So if you have an indented function
body below the function signature, everything that's indented
stays part of the function body. And the same is true for other block
scoping constructs in the language. The language does also
support squiggly braces. So you could put the
function in squiggly braces if you don't like syntactically
significant indentation. Verse functions can be overloaded. Here's an example of a function Foo
that takes either an int or a logic. It doesn't even have the same
return type in both cases. It could be a completely
different function body. If you call Foo with 0, it calls
the first Foo and returns a string. If you call Foo with true, it calls
the second one and returns nothing. Next up, modules-- modules are a
great feature for encapsulation. The easiest way to
make a module in Verse is using the directory structure. Within your project, if you have
Verse files in a subdirectory, that subdirectory becomes a module. But you can also use modules
directly in your code. And this is how you would do it. You use the module macro. Again, syntactically
significant indentation means that the A and F members
are part of that module. So here I've defined
both members public, which allows code outside of
the module to reference them. Verse also has structs. Structs are great for just
passing around clusters of values with named properties. So here I have a struct that just
has one member A of type integer. There's a couple of things going
on here that I want to point out. First of all,
our naming convention, which is not enforced by the compiler,
is that we use capital case for values and lowercase for types. For multiple words,
we use snake case for types. So maybe it would be
foo_bar instead of just foo. And we use camel case,
uppercase camel case, for values. It's not enforced by the compiler. So you can do whatever
you feel like. But this is what we recommend. Another thing happening here is that
I have given the A member a default value of 42. So if I instantiated foo without
specifying the value of A, A would be 42. But here, as you can see
on the second-to-last line, I'm instantiating foo with A being
overridden with the value 43. So then, later, when I say
X.A, I get 43 instead of 42. Verse also supports classes. Classes are more
powerful than structs. You can have subtyping. You can have functions. Classes also have--
class instances also have identity,
kind of like they do in Java and other object-oriented languages. Here I've just created a class
that has no supertype called bar. I've given it a field A with
default value 42 and a function. And I've instantiated bar
and, again, overridden the
default value of A with 43. This is what it would look
like if you did subtyping. Subtyping is-- the
syntax for subtyping is you say class with
a parenthesized clause. Whatever is inside of those
parentheses is the supertype. So here bar is the subtype. foo is the supertype. Functions are virtual
by-- member functions and classes are virtual
by default in Verse. And we require that you
use the override specifier when you are intentionally
overriding a virtual function. So here we've overridden F in
bar to do something different than it would have done in foo. And in order to placate
the compiler, we've placed the override specifier on F. Now let's talk about mutability. So far I've shown you
a bunch of features where there's immutable variables. And that's not appropriate
for all use cases. So Verse also supports
mutable variables. And the mutable variable
support is really awesome. Here's a really simple example. All I have to do is say var,
and X is now a mutable variable. This means that I can change
its value whenever I like. The way that I change its value
is using the set keyword-- var and set, very simple. So here var X starts
out with the value 42. Then I set it to 43. Later, when I say Y:=X+1, the X
value that it's reading there is 43, not 42. So Y will have the value 44. The mutability features allow for
something we call deep mutability. So here I've created a var map. So it's a mutable map
that maps int to int. X starts out being the empty map. The way that I insert elements
into the map is using set. So I set X subscript 42 equals 100. That makes it so that X now
has a mapping from 42 to 100. Similar syntax can be used
for appending to an array. So here I've got a mutable array. It starts out empty. And then I push the value
42 at the end of it. That's what pushing to the end
of the array looks like in Verse. Now let's talk about another
feature, which is tuples. Tuples are like a very lightweight
way of just taking a bunch of values and passing them around together. Here I've created a tuple that has
an integer, a string, and an array. I can also give this
thing a type if I want. So that's what that would look
like if I spelled out the type. Tuples are mostly used
as function parameters. That's the main way that
you'll encounter them. So, for example,
if I say that there's a function F that takes two
parameters X and Y, what I'm really saying in Verse is that
it takes one parameter, and that parameter is a
tuple of type int int. So if I create a tuple like
1, comma, 2, I can use that as a parameter to this function that takes X and
Y, and the tuple will be flattened. But parameters are actually a little
bit more complicated than tuples. They also support
optional named parameters. So here Z is an optional
named parameter. It's named. So what that means is that if I
wanted to pass a Z to function F, I would actually have to say Z:=
instead of just passing the value. And they're optional. If you don't pass the Z,
it gets its default value. In this case,
the default value is 42. Now let's talk about generics. Verse has a very powerful
generic type system. If you've ever programmed in C++,
Swift, other modern languages, they also support some
variant of generics. Here is a piece of
code without generics. So I've created a
class called thingy, and it's got an X that's an
int and a Y that's a string. Let's say that we wanted to add
a little bit of generics to this. Here's what it would look like. So instead of defining thingy
as a value that is just a class, I have defined it as
a function over type. So thingy is now a function that
takes a type and returns a class. And the class that
it returns is a class where the Y member has the type
t that you passed into thingy. So here you can see that instead of
instantiating the object by saying "thingy" and then
the squiggly braces, I'm instantiating it
by saying "thingy" and then, in parentheses,
"string," and then the rest. So I'm instantiating-- that
tells us that we're instantiating a thingy where the t is a string. And, finally, on the last line,
I've made the function generic. So in the original
version, the function just simply took an
object of type thingy. Here it's taking an object of
type thingy with a generic type. And because I'm using the where
clause, the t is inferred. So if I call the
function F with some object of type
thingy for any type, you can just call this function. And type inference will infer that
t is whatever type you were using. Because of our
aspiration to have Verse be the language of a unified
metaverse with everybody's code all in one namespace, Verse
supports a global unified namespace with paths. The top level of a path is a domain. So here are examples of
using paths in Verse today. This is basically the
Verse include statement. We're pulling in the verse.org
simulation module into our scope, and then we're pulling in the
Fortnite.com devices module into our scope. And these paths are not strings. They're syntactically
recognized within the language. And you'll see more and more
of paths in the language as we develop it out. All right. Now let's talk about
where Verse really diverges from other languages. Verse is inspired by functional
logic programming, which means that instead of relying
on Booleans for conditions, it relies on success and failure. So here I've written a Verse program
that first says that X is 100 and then says that X is 200. That's a contradiction. So the program will fail. And, in fact, failure is the way
that you do comparison in Verse. So if you run a piece of code
within the condition of an if statement,
what you're doing is you're asking Verse to run that code
to see if it succeeds or fails. If it succeeds,
then you take the then case. If it fails, you don't. So here the X=200 will fail
because X already has a value, and that value is 100. And so "wat" will not be printed. Same thing happens if you
use inequalities-- so greater than is a failable expression. If it succeeds, then the if
statement will print "wat." In this case, it'll fail. You can also abstract failure
out using the decides effect. So here I've defined a function
F with the decides effect. And it decides if X
is greater than 100. I can call this function F with
the square bracket call syntax. Square bracket call
syntax in Verse means I want to call this function to
see if it will succeed or fail. If it succeeds,
you'll get the value. If it fails, well, you have
to be in a failure context. And in this case, I'm calling F from
within the condition of an if, which is a failure context. So this is the same
thing as if I had said X greater than 100 inside
of the if condition. And, again, this will fail
because I'm calling F with 0, and 0 is not greater than 100. This decides thing is an example
of effect specifications in Verse. In Verse, you can specify for any
function what kinds of effects it's capable of. By default, functions have
a certain set of effects that you'll find
useful for most cases. But sometimes you will use
effects like decides to broaden the power of the function. In this case, I'm giving the
function the additional power to fail if it wants to. And a little bit later,
I'll show you another effect that is popular in Verse. OK. Now, this concept of failure is
closely tied up with transactions. So if you run a failure context-- in this case, the if condition
is a failure context-- that failure context will either
succeed as a whole or all of it will fail. What this means is if you run this
code, and X is not less than 100, then this effect that you performed
will actually never happen. It'll happen,
but behind the scenes, we will roll it back as soon as we
realize that this failure context is failing. Now let's look at another
effect, the suspends effect, which is the way that you
create coroutines in Verse. If you've ever programmed with
JavaScript async functions, coroutines in Verse
work sort of like that. So here I've created a
coroutine, and the reason why
I've done that is I want to wait for user input. So this WaitForInput, presumably,
is another suspends function that I'm calling. And it might suspend for, maybe,
multiple frame ticks or something. So if you want to wait for
input, if you want to wait for another frame
tick, you've got to be in a suspends
function, and you've got to call something
that will wait. But our coroutines are way cooler
than JavaScript async functions because we've brought in all
of the power of SkookumScript's structured concurrency. So here's an example of how
you create coroutines in Verse. On the left is the block
construct, which doesn't really create coroutines. It just runs whatever-- the Coro1,
2, 3, 4, in sequence synchronously. But if I say "sync," then
these four coroutines will be run concurrently
to one another. And the sync clause will return
once all of them are done. And keep in mind that any of these
things could be waiting for input, could be sleeping,
could be doing whatever they want. Race is another construct. This one's really fun. Race means run a
bunch of coroutines. And whichever one
finishes first wins, and the other ones are
canceled at that point. Rush-- similar. It runs until one of
the coroutines finishes. But then the remaining
coroutines that took longer are allowed to finish asynchronously
after the rush statement returns. Finally, the branch statement
creates just a single path of asynchronous execution. So here Coro1, 2,
3, 4 are running one after another, but concurrently
to the code that used the branch. To make the race construct and this
idea of cancelling coroutines even more powerful,
we have a defer statement. You don't have to use
it in a coroutine. Here's a simple example where
I'm printing "hello world!" even though the code
is out of order. The reason why this works is if
you have a defer statement, then the code within that
defer statement will run when the scope that you're
in exits, no matter how it exits. So here, presumably,
after Print("hello"), you'll return or something. So then it will print
"hello" and then will print "world" because
printing "world" was deferred. So this is a goofy way of printing
"hello world!" using defer. But this is where the construct
actually becomes useful. And that's if you use it with race. So as I said before, race will
run the various coroutines. In this case,
there's two coroutines. One coroutine is the one created by
the block construct, which defers thingy and then does SomethingSlow. And the other coroutine is
the SomethingFast coroutine. As you recall, race will run until
whichever coroutine finishes first, and then the other
coroutines are canceled. But the defer statement ensures
that when that first coroutine is canceled because it was too slow,
it will run the thingy function immediately upon being canceled. So this lets you manage cancellation
in your code in some way. So it's not just that
your coroutine goes away. You can actually run
some cleanup code. Now let me get into my
favorite feature of Verse, which is the for loop. Here is a very simple for loop. I'm just using a for loop
here to iterate over an array. This does what you would expect. It iterates over the elements of
SomeArray and prints all of them. But the for loop is
kind of like a query. Because of the functional
logic power of the language, it can do some of the things you
would expect from a query language. So, for example, I can throw in
an additional condition here. This will print all of
the elements of SomeArray that are greater than 100. Or this will print all of
the elements of SomeArray that are not equal to 100. And you could layer these
conditions on top of one another if you wanted to. Just before I show you
some more crazy code, here's another simple example. This will print the integers
from 1 to 200 except for 100. All right. Now let me show you the
really cool example. So this example is taken
from a Minesweeper game that we wrote during
one of our Verse-- that one of us wrote during
one of our Verse game jams. So to set up Minesweeper, you
have to compute the adjacent mines for every cell in the
Minesweeper table. And that's kind of annoying
to write because you have to iterate over all of
the X coordinates of the map, then the Y coordinates. Then you have to iterate around
whichever cell you're in. And, of course, you could be at a
cell that's adjacent to the edge. So then, it doesn't have all of the
adjacent cells you'd expect it to, so you have to do
some bounds checking. In Verse, you can write that
entire loop just as a single loop without any nesting. The way you do that is first, we
use the Y->CellRow:Cells construct to say, I want the index in the
array and the element in the array of Cells. So Y is the index in Cells. Cells is a two-dimensional array. And CellRow is the element. So CellRow ends up itself
being an array, a row of cells. But without even having to
go into a deeper loop nest, I can, within that same for
loop, say, well, I want to grab the X coordinate
and the cell out of CellRow. So, again, X ends up being
the index in CellRow. Cell is the value at that index. So now,
with just those two statements, within the rest of the
scope of the for loop, I have the X index into
this two-dimensional array, the Y index into the two-dimensional
array, and the entry. But wait. It gets better. I can then use the
range construct to loop even more
within the same loop. Here I'm looping over all of the
adjacents-- so all nine adjacents-- by just simply saying
X-1..X+1 and Y-1..Y+1. And then,
when I access the Cells array, notice that array accesses
use the square bracket syntax. The square bracket syntax
is a failable expression. When does it fail? Well, it fails if the
indices are out of bounds. So because all of the
things in for loop clause are failable conditions
that, if they fail, the loop just doesn't consider
it, this means that the loop
will automatically skip the out-of-bounds cases without
you having to say anything about it. So that's how you write the
Minesweeper setup in Verse, just in a single loop without having
to use any crazy nesting, thanks to Verse's functional logic power. And with that, let me talk
about some future plans. So we're going to bring lots
of additional language features on top of what's already there. So right now,
it is still a smaller language than what we hope for in the future. As Tim said,
right now we're shipping BetaVerse. And we're working incrementally
towards the MaxVerse vision. Additionally, although right now the
language is only built into UEFN, we eventually want to build
it into Unreal Engine as well. And this isn't to
replace Blueprints. This is to augment Blueprints. So if you love programming
with Blueprints, keep doing it. If you want to program in a
scripting language, Verse is coming. We also want to release
the language implementation under a permissively-licensed
open-source license so that other people can use
it for whatever they like, whether it's a different game engine
or something not even game-related. The current implementation is still
early days in terms of performance. So expect lots of performance
improvements to come. Also, right now, we're shipping a
relatively simple gameplay framework with Verse. But we're going to grow that
and ship a much bigger framework in the future. And on that note, let me turn
it over to Tim Tillotson, our gameplay engineer director. [MUSIC PLAYING] [APPLAUSE] TIM TILLOTSON: Thanks, Phil. Let's talk about the Verse API. So much of what I will share
today is really forward-looking. We have a lot of plans that
we'd like to do, a lot of things we've prototyped. The API is currently in beta
and will be for a long time. We strive to have a
public stable API, but we reserve the
right to change things throughout beta as we need to. If we deprecate things, we'll
try to do it like we do with UE. We'll do it in phases, or we'll
provide some easy way for you to upgrade your code. So this is kind of a comparison
with the game metaverse to the world wide web and how we envision it. At the high level,
we want to make creating user games and simulations
is easy to do it is to create web applications today. But to do that, you have to have
this common set of APIs you're building on top of. And so initially, though, those
APIs often start out very custom to the browser or the simulation
engine that's created. So we saw a lot of things-- with web browsers, you would
find kind of very custom APIs. But, eventually, you'd find
an open spec that many of them implement so it's easier for people
to write applications against. We envision the same
thing will occur here in the games and simulation space. And, eventually, you'll have users
build their own custom community APIs on top of that. And so we start with
this phase where we have proposing your
individual standards that you implement that solve the
problems you need to solve. An example is QUIC was
implemented by Google and Chrome back in 2012 to speed up how the
browser talked to their web search engine. And then that became the basis
for HTTP3 almost a decade later. So we're proposing Verse
as an open standard. And we'll hope that
also becomes adopted, along with many of
the other 3D standards we have out there for
scenes and 3D models. Much like the JavaScript VM empowers
a lot of the web content logic, the Verse VM, we envision,
will empower a lot of the game simulation-type logic. And we open it up for
others to use in those same game simulation
engines as well, beyond Unreal. And we also want to extract
a lot of the hardwareisms so you can focus really on making
the games and what you do best. So talking about the
API we have today, really, the initial API is
built around Fortnite Creative. And so these are just a
variety of the different genres that people have created games in
inside of Fortnite Creative today. And the scriptable device is kind
of how we're first connecting Verse to Unreal and to Fortnite. As we look forward over the
course of this next year, we want to allow you to also script
components so you can build up individual objects and build scenes
and build much richer, deeper experiences. We also plan to add
a bunch of features which will enable new things that
are more challenging to do today with the limited API we provide. Looking forward a year or
two, we also want to make Verse performant
and work on gameplay systems so it's easier to do
things like physics, custom vehicles, those kind of
deeper high-performance operations. But long-term, we really want to
make Verse able to run AAA games. And so it's a lot of work. We have to get here. And before we'd recommend people
using Verse and UEFN in, say, a AAA game, we want to do that
inside of Fortnite ourselves. And so we've got years of
work ahead of us to do that. But there are many places
where a AAA game would want to say, OK,
let's make a limited experience to expose our IP to the
millions of Fortnite players-- and so a lot of
opportunity here for us to decide what's the right time
for you to jump in and try out Verse and then use it in your games. So there are a few differences
between UE and UEFN and how our guiding principles work. First of all, a lot of
times, in UE, you have to go and decide what you want
to replicate, write a lot of code that kind of connects
pieces together. With UEFN and Verse, everything
is replicated from the get-go. So it's simple to approach, very
easy to jump in, in an hour of code, write something that is playable. We want to be able
to constantly evolve. So Fortnite,
we update every two weeks. We want to be able to
update games very quickly and let people kind of iterate
in that space with their players. We want to have this world where
people can publish something, and someone else can
use it and kind of have this back-and-forth
iteration occur, much like happens in the web space. And so this really rapid
iteration of game content is what we want to
enable in this space. So at a high level, we divided the
Verse API into three namespaces. There's Verse.org, which contains
kind of the game-agnostic APIs that we will submit
as part of open specs. There's UnrealEngine.com, which
contains kind of the Spatial Math UI, those types of things which are
very specific to the Unreal Engine. And then there's
Fortnite.com, which is the APIs that are
largely specific to how Fortnite wants to do certain
things, like vehicles or characters. And those will largely
always be contained inside of Fortnite and UEFN. So this represents roughly
the high-level overview of where the APIs exist today. So if you download Unreal
Engine for Fortnite, this is where you'll
see the APIs exist. Instead of Verse.org, you'll see
Math, Containers, Colors, and things that are agnostic for Game
Engine but are generally in use in simulations like Player and Team. UnrealEngine.com,
we have things like diagnostics. Most of our diagnostics
today-- and debugging really is kind of this printf-based
diagnostic debugging-- we pipe that from the servers down to the editor. So you can at least see
it in real time, what's going on in your game simulation. Long-term, though, we have other
plans to improve that quite a bit. The Fortnite API right now is really
around these creative devices. We have a few things we've exposed
with characters and vehicles. But there's a lot more we want
to express in the future here. And in the very near future, we plan
to expose the ability to script AI. So I want to look a little
bit further out, what we plan on doing this year as
well as in the future. And so I went to one
of the indy showcases last night ready to
play a lot of games. And I would say there's only
a small percentage of those you can build in UEFN today. And that's because a lot of them
want things like persistence. They want things like basic
input and camera control. And so these are the
type of features we want to add over the
remainder of the coming year. But the majority of
our internal tech focus is going to be around
the Scene Graph. We want to let people build prefabs. We want to let people customize
weapons and abilities. We want to let people
put scripts on objects, build objects,
and build out scenes-- and so enabling this
really rich environment for people to share
and build content, and then I think things like
debuggers, performance profiling, and also analytics
so you can see what players are doing with your game. So a little bit of
detail into what we're looking at on the Scene Graph,
and some differences with, maybe, other Scene Graph implementations
that are out there-- the most important is
we are looking at how we can have a public API that
you basically say, here is the things I want other people to
be able to query in the Scene Graph, and these are the things that I want
to keep internal so we can iterate on it internally and change
it next version and not have to worry about breaking
anybody who's using our API. On the research side, we're looking
at things that you find in UE, like level instances, layers,
variants, other ways in which we're composing content today,
and see if there's better ways we can merge and undo
those operations, both in design time as well as at runtime,
ideally so you can make changes to your scene
dynamically, much as you have web styling today on web pages. So I want to walk through
a demo of creating-- adding Verse code to a Fortnite
Creative game, or, in this case, a new UEFN game. So you create a new Verse device
by inheriting from creative_device. In this case, I've created
an escape_sequence_device. And the Fortnite Creative devices
today are just this bundle of logic that you kind of drag into
the scene as an object. In this case, you'll see kind
of this little console here that represents your script. Inside of the script,
you can add editable properties. In this case,
we have a player spawn that shows up as a property in the scene. You can then modify on
a per-instance basis. So once you've created that
class, then you can override the OnBegin method-- or, in this case, because it has a
suspense effect, it's a coroutine-- and then add your own custom logic. In this case,
we'll spawn an escape sequence that the player will
then run through. So in this case,
a little bit into the race method that Phil talked about,
I have the escape method we run. And then we're also waiting
for the player to respawn. And so in this case, the escape
sequence shows a message. And then if the player
respawns, we run the defer block to hide that message. And so you'll see
in the game later-- the little demo that
I run through here-- pretty much any place in
that, we should be able to have the player respawn. And the defer blocks will
cause it to kind of reset and be ready for the player
to start that sequence again. And so these defer blocks
can be composed in nice ways so that you'll notice they
actually go back up the stack. And so the last defer
block that was run-- or placed on the stack will
be the first one that's run. So little caveats about
the scope of this demo-- this is based on the
Verse Parkour game template, which is in UEFN today. All the code and level edits are
made entirely by me-- so lots of programmer art. A lot of things aren't polished
like an artist would do. I've imported a few
small sounds and VFX. But I expect that
the experience that I've shown you--
will show you here is roughly what an
experienced developer who knows UE,
knows the toolset inside of UEFN, and is familiar with
the Verse code will be able to do in roughly a day or less. [MUSIC PLAYING] So here we tell the player
go grab the stolen files, give them a little indicator to
show them where at in the level, and then wait for them
to enter that area. So once they've grabbed the files
here, now we delete the file and then spawn some AI
to harass the player, and then wait for them to
enter the rooftop area. Once they've entered
that rooftop area, we spawn some more AI to
continue harassing the player. We start the building on fire, and
then wait for them to trigger one of these other
conditions-- in this case, they've entered the safe area-- and then prompt them to
enter the getaway vehicle. This could be many
branching conditions you have in gameplay code. I've only done a
simple one right here. So once they jump on the car
here, the getaway vehicle, I basically have a little
scripted animation you play. And I play a custom cinematic
cut scene here as well. And then give the option
to jump in a helicopter. And if they do jump in
this helicopter zone, we'll place them in the
seat of the helicopter and wait for them to enter
the level outro area. [EXPLOSION] And then, when they do,
we play the outro cinematic. So that's just a small sample of
what's possible with Verse in UEFN today. And this is part of just
a much larger ecosystem. Please see all the
other UEFN announcements they've made about
ecosystem and other things that we're enabling in Fortnite. We have years of
development workplan. I've only talked about a very small
portion of what is on our slate. But really, we want to iterate
with Verse and with UEFN as you as a community. Now the tools are out there,
there's so much we have planned. We really want feedback as we go
through and iterate in this space. So I'll give a shout-out
to the team that has worked with us over
the last couple of years to bring these things to you. And now we'll turn
the time over for Q&A and invite everyone else
back out on stage here, along with Andrew Schneidecker,
one of our Verse developers. [APPLAUSE] PHIL PIZLO: So let's see. Yeah, go ahead. There's a mic. Where's the mic? There it is. Could you go over to the mic? [AUDIENCE CHUCKLES] Just so everybody else can hear. TIM SWEENEY: If folks just want
to line up with the microphone, ask questions. AUDIENCE: Hi there. I'm just curious to see where Verse
fits in in the current Blueprint/C++ ecosystem. Because I've heard
rumors that you're basically sort of pushing Verse as a third wheel to complement both
of them rather than replace C++. Is that true? PHIL PIZLO: Yes. Yes. TIM TILLOTSON: Yeah. A good example is, in UEFN,
we can't expose native code like C++ to the platform owners. And also, deploying C++
on servers is dangerous. There's a lot of
security holes in C++. So Verse is a very
high performant work-- we plan it to be a very
high-performant language that we can run on our servers. And so it can do a lot of
the things that, today, you can only do in C++ in UE. AUDIENCE: All right. Thank you. AUDIENCE: So I actually had
a bit of a syntax question, earlier, about the decides keyword. I noticed that the function that had
decides, essentially, if it failed, it was going to
evaluate as false if it was in some kind of a
decision context, I think, is a word that you used. My question is, so what's the
purpose, then, of the logic type? I saw that it sort of is like
the replacement for Bool. Wouldn't a function that decides-- why doesn't it just return
a logic type instead of having the decides keyword? PHIL PIZLO: If it returned
a logic type, then, after calling the
function, you'd have to use question mark to turn the
logic into success or failure. So the convention is,
if you're returning Boolean, you almost always make
the function decides. But logic is still useful if
you want to carry around, say, an array of Booleans. Then you would use logic. AUDIENCE: So is there traditional
Boolean types in Verse? Because you were saying
that, in an if statement, it's essentially, if it
succeeds, then you do the code. And if it fails, then you don't. So is there a traditional
Boolean type in Verse? Or is it all just this
failure and success? PHIL PIZLO: There's no Boolean
type that feeds into control flow. So if you're doing an
if, then the if is based on the success or failure of
the expression in the condition. But there is a traditional
Boolean type in the sense that logic can be true or false and
can be passed around as a Boolean. AUDIENCE: And I just have
one final follow-up question. So this success-and-failure system
sort of seems like it replaces the traditional exception system
present in languages like Java and C#. So in this case, we wouldn't
really have try-catch blocks. It's that the whole language is
built around success and failure. So if you have an exception,
it acts the same way as if the expression failed. Is that correct? PHIL PIZLO: It's similar. The difference is that,
with exception handling in most languages, if you look
at a function, the points in the function where an
exception can happen are implicit. Like you call a function foo. Could it throw an exception? But here, in Verse,
if you call a function for the purpose of determining
if it decides or fails, you have to call it with
the square bracket syntax. You have to be in a failure context. So there's really no completely
implicit control flow here. You can see all the points in your
program where a failure could happen and the code you're running
could terminate early. AUDIENCE: And then I
imagine it's a lot more performant than
traditional exception handling in other languages. PHIL PIZLO: Oh yes, yes. AUDIENCE: Thank you very much. AUDIENCE: I had a question
about under the hood. Is all of this compiling to native?
or running in a virtual machine? or what? PHIL PIZLO: Right now,
it's compiling to the Blueprint VM. That's not the long-term
strategy, but it works great now. AUDIENCE: And is there any
plan for supporting FFI-- Foreign Functions--
or anything like that? PHIL PIZLO: For the purpose of
us building our framework, yes. When it's released as part
of Unreal Engine, yes. You just won't get FFI in UEFN
because of the security downside of letting you ship C++
code to our servers. AUDIENCE: Thanks. AUDIENCE: Hi. Just a high-level question. When you set out
architecting this language, what was it about
existing languages that was uneconomical or insufficient
for this application you're calling the metaverse? Very high-level question. TIM SWEENEY: You know,
there's really one driving force. It's that we thought it would be
very hard to retrofit an existing language to support the full usage
case requirements of the metaverse. The two big constraints here
are, number one, we need a language that can scale
to massive open-world programming where potentially millions of
modules by different authors evolve over time,
independent of each other, while maintaining
interface compatibility. To do that, well, you need an
expressive type system that goes rather beyond what even
C# and Java have done. Another big consideration
was a desire to implement transactions
is the solution to concurrency in the future. If you look at how all
existing MMOs and other games with massive simulations
have dealt with concurrency, they just push a huge
amount of error-prone work on the programmer where
you're both writing local game code to run on your current
node, but you're also sending messages to other
nodes in a data center to tell different nodes
to do different things, and you're kind of writing
your own manual and negotiation protocols for making
cross-server transactions or cross-server communications work. And it's all very error
prone, unscalable, and seems like a completely
unworkable solution for something as open-ended as the metaverse. And so we looked at transactional
memory as the solution to that. There's a 20 years of great
research, going back to the Haskell programming language
on transactions, and we felt that the task of retrofitting an existing language
like C# would just not be practical. And we also looked at
practical language-- well, engines such as Unity's
efforts to adopt C#, and recognized that unless there's
something that's really dedicated to solving these problems, it
becomes incredibly hard to maintain a third-party integration to a
language ecosystem like that. So that, plus just a
general desire to clean up some of the foundations
of programming, led to the decisions
that got us here. And the desire to
adopt logic programming features-- some of this fancy
"failure is control flow" stuff that we've
talked about and the new iteration
primitives, there's a lot of expressive power there. We've only barely scratched
the surface of what's possible. And over time, that will
become more and more apparent, and I think will kind
of be a direction that future languages and
even existing languages adopt more and more. And we thought it would be good
to do that once and cleanly rather than trying to
retrofit it over time later. AUDIENCE: Hi. So it sounds like the Verse
VM is either in partial work or not started at all. But will that be as permissively
licensed as the rest of the Verse language spec. And if Verse is a compiled
language, is it going to be compiled to a IR form? Or is that going to
translate into something more where the verse VM is
directly interpreting it? PHIL PIZLO: Good question. So we intend to release the Verse
VM with a permissively licensed open-source license that
would make it easy for anybody to use it in their products. So that's one thing. As for what it will compile
to, we're still in the research phase of
deciding to what extent it can be ahead-of-time compiled
versus to what extent it will benefit from more of the Java
style just-in-time compilation. And simultaneously,
we're going to make sure that it has a really fast
interpreter for all those cases where native code or JITing just
wouldn't have been practical. AUDIENCE: OK. And secondly,
on the language lifetime-- because you talk about a timeless
language or a language that has heavy extension-- what is the support for macros or
things like quotations and splices in a safe language
like, say, Scala, where they have heavy support
for language extension to allow for some internal
DSLs that allow for some of that extendable
functionality that you might want to see in a language like this? Because if you really
want it to be code as one, you need support for embedding
other types of formatted data. TIM SWEENEY: Yeah. So on the front of macros-- you know, Reynolds,
the old computer scientist, wrote down their Reynolds'
abstraction theorem, saying, basically, if a language has the
capability of doing something cool for itself, it had better open up
facility for abstracting over that feature for users. So we have expressions,
so we'd better have a variable so you can abstract over values. And we have formulas. You'd better be able to write
functions to abstract over values. And macros are a way of
abstracting over syntax. So we think that's important. We have just kind of a strawman
plan for going all the way down the macro rabbit
hole in the future, with the Scheme-inspired
hygienic macros. C++ programmers are horrified
to hear about macros. But actually,
there are languages that have done macros in a
completely clean way that avoid the pitfalls of
weird string-splicing operations and accidentally aliasing names. There's a really great methodology
for that from other languages. We have a plan for the whole thing. And we're not sure exactly how
far we want to go down that path. We want to at least get
to the point where users-- if you saw the for loop
here in Verse, well, that's a special construct
we made on arrays. But the for loop you
saw in these slides is actually just
using a native macro. There's a syntax for the macro. It's some name, parentheses,
some values, squiggly brackets, some expressions. And that's the format for a macro. And so it's already designed
to accommodate macros at a fairly fundamental level. We definitely expose
macros for creating iterator type constructs and
formers and containers of all sorts. So if we can write a
fancy syntax for arrays and you create a cool tree
type, you should be able to write a
fancy syntax for trees. But we're not sure
how far down we'll go. It gets a little bit dicey to
pick apart that abstract syntax tree of a language and casing
over special cases on a macro. And when you get down into
those domain-specific languages, they're just built
from ad hoc syntax. You kind of have to ask,
is this really a language? Or have we just done crazy
tricks to stick other languages in the language? So I'm not sure exactly
how far we'll go. But we'll definitely go pretty far. AUDIENCE: OK. Thank you. AUDIENCE: Are there plans to be able
to implement Blueprint nodes like you can do with C++ with Verse. PHIL PIZLO: We've
thought about that. But we don't have a concrete plan
of exactly how we would do it, what it would look like. AUDIENCE: OK. Cool. Thank you. PHIL PIZLO: That's a great idea. TIM SWEENEY: Yeah. Just one of the things
we're thinking through as we're developing all of this
is the long-term integration plan for Verse into Unreal Engine and
how it coexists with Blueprints. Right now,
everything's layered on top of the Blueprint virtual machine. So, you could theoretically
make these things interop more so than we have. But one possibility is
to, as we're building this new higher-performance virtual
machine, layer both Blueprints and Verse on top of
that so Blueprints become kind of a visual form of
the same language that's Verse and do more to align those. And we've also considered other
visual programming directions along those lines. That's an active
research topic that we're going to be experimenting with
quite a lot over the course of the next year or two. AUDIENCE: Thanks for the
talk-- really interesting. I like your transactional approach. It reminds me a lot of
Clojure's implementation if you've seen that one. One question I had was you seem to
be leaning pretty heavily into kind of pure values and pure functions. And I was wondering
if that was aimed towards multithreaded
scalability in the future. Because I know Haskell
and languages like that have derived a lot of benefit from
that kind of being their basis. PHIL PIZLO: So for us,
the basis is that we're actually going to make transactions over
mutable state fast, hopefully. So the language doesn't quite force
you to write pure code the way that you would in Haskell. It invites you to write very
traditional, object-oriented, imperative code. So I don't think that we're viewing
the pure features of the language as a performance optimization
for transactions, although they certainly could
be if you used them that way. AUDIENCE: OK. And a second question if that's OK. Have you looked at-- because you're talking about
all of this code sharing for, like,
thousands and millions of users, have you looked at
alternative forward looking ways of storing and sharing that
code, things like what Unison is doing with kind of hashing
abstract syntax trees and sharing things that way for
providing greater scalability than traditional text-based
sharing provides? TIM SWEENEY: Yeah. There are really two ways of
doing code sharing, as we see it, in the metaverse. The traditional way is, you want
to use a bunch of libraries? Great. Well, you copy those
into your directories. And now you have a separate
copy of the library. And you can modify
them however you want. And they never change. And now they're your
problem to maintain. Yeah, that works for some things. But we think the much more common
approach to sharing in the metaverse will be different authors
deploy their own modules and expose them as public
components of the metaverse. You see, in Verse, there are
public and private declarations and variables. Well, in the metaverse,
we take those things for real. If you release a public
module, that means any other programmer
in the entire world will be able to access
your module by its path. You'll have a path that might
start at Fortnite.com right now, and then go to your creator
name, and then have some directories underneath it. Well, that's your module that
you've released publicly. And the intention is that the
Verse publishing system has backwards compatibility constraints. If you publish a
version of a module that says it adheres to
some type signature, it exposes some classes
and some variables, then all future
versions of that module must be backwards compatible with
that public specification you made. You're kind of giving the public a
promise that your public interface will not change. And in that way, modules can evolve
over time while remaining in place and being addressed in place. And we think that that's
a really interesting way to allow the metaverse to
evolve, where lots of authors are collaboratively adding lots of
different features and capabilities and each accessing
their things in place, and especially when you
get into shared state. If one person creates
a scoreboard that supports lots of
different types of games, and other users tie in to
that, you're not creating your own
copy of that scoreboard. You're talking to the
global scoreboard. It's another idea
in the metaverse, is that, eventually, global variables
will really be global variables. There is one in the whole world. And everybody could access it
if you exposed it that way. So the intention really is to have
a programming language framework that, writ large-- and what we're shipping
right now doesn't implement this concurrency
model or this shared data model, although we have long
term intentions to move in that direction with the idea that
the metaverse, to the programmer, looks kind of like this massive
computer that runs very, very fast because it's a whole
data center-- or many data centers-- full of computers,
but otherwise looks single threaded because
this transactional memory system is sequencing all of
your gameplay updates through it as it goes. And everybody's code
could potentially interact with anybody else's code. And optimizing your code is really
about maintaining data locality. So there's a lot of really,
really long-term thinking about all of this
that feeds into how these systems,
especially modules, will interact. AUDIENCE: Interesting. Thank you. AUDIENCE: Thank you
very much for the show. You're amazing. And some of the questions that
have already been answered. But I just want to confirm,
if I understand correctly, it seems like Verse first
compiles to bytecode and be processed by
the Blueprint engine. And if so, do we have any data for
the comparison with some popular scripts we are using
[INAUDIBLE] like Python and Lua? And then something
like you mentioned, like if [INAUDIBLE] run into the
trap after global log, like Python, we are doing it-- we have just been
trying it for years. But it sounds like it would be
[INAUDIBLE] global log there, right? Like if the restriction
of Blueprint engine are-- PHIL PIZLO: So we're running
on top of Blueprints right now, but that's not the long-term plan. So the Verse VM that
we are building is just going to be multithreaded
from the start, basically. AUDIENCE: I see. PHIL PIZLO: And the key thing
that saves us compared to Python is, number one,
Verse is not nearly as dynamic. It's not like an
object is a dictionary. So concurrent updates to the
object from multiple threads are not as challenging for
us to implement as they would be for a Python implementer. And the other thing that saves
us is we have transactions. So because transactional semantics
is woven deep into the language, even if updating a language
required updating a dictionary, we would just simply
do it in a transaction and avoid all of the locking
problems that you have in Python. That being said, right
now, the performance-- I don't actually know,
off the top of my head, how it compares to Python or Lua. It's still early days. So the performance now is
not really predictive of what the performance will be. AUDIENCE: OK. Thanks. Very helpful. AUDIENCE: Hi. I'm really excited. The first question would be,
have you given any sort of thought to maybe not functional logic
programming, but more functional programming concepts? Like you already have the
effects system, which is awesome. But have you given more thought
into linear types, dependent types? And I did see, earlier in the talk,
that you just briefly mentioned proofs. So is there any thought
into those more-- like supercharging the compiler that
way with those functional concepts? TIM SWEENEY: Sure. I'll talk about some of our
forward-looking thoughts and all of that. First of all, yeah, there is
an effects system in Verse. And there are a bunch
of different effects. And you can combine effects. And when you say what
things a function can do. And when you write a function that
promises to have no side effects, then the compiler really
checks that and gives you an error if you violate
the promise you're making. So the effects are actually
part of the Open World type signature of a function,
are enforced by the language. And the effects system
enables you to say, well, this is a transacts function. That means this function can
read and write from memory. But all that reading and writing
can be done within a transaction because the transaction
system under the hood can speculatively run this code and
either commit it to the global heap or it can abort it and have
no changes made at all. There's different points
in the effects lattice where there's pure functions
which have no side effects at all. And so you can write pure
code like you can in Haskell. And then there's
even total functions, functions which are guaranteed to
produce a result in finite time given the right amount of memory. There's a lot of thinking
and planning there around the type system, which is-- well, it's a big
topic that could be-- it could have a developers'
conference of itself. But we plan to go a very long
way with the Verse type system in building a type system
that is statically verifiable and is more powerful than typical
type systems you see in languages today. One aspect of it, which you
saw a little bit of already, is dependent types. Instead of templates as in
C++ or generics as in C#, you can just write a function
that takes a type as a parameter and returns a class as a result.
And a generic function like that, it's just a normal function. And types are just normal values. And the compiler, over time,
will do more and more compile time reasoning about complex
sets of value constraints. In C++,
you have this idea of constexpr, where you can have a function
that can run at compile time. If you give it a
constant parameter, it will return a constant result.
Well, Verse ultimately has-- we've designed a much
more thorough system for taking that idea even further. It senses type checking, dependent
types, and some very interesting other features. I guess I've only just
given a little hint of it. I can't really go into
a lot more detail there. But there's going to be some
very interesting stuff happening. And I guess I should just mention,
since you opened the door-- AUDIENCE: Sorry. TIM SWEENEY: (AMUSED) No. It's a really interesting topic. It's funny. Very few practicing
programmers know about that. But there's this idea of proofs
as programs that's one of the big topics in type theory, if you have
ever taken a type theory class, that if you have a
type system that's designed in a very
particular way, then what looks like normal
types in C++ becomes, actually, a much more expressive and
powerful thing at compile time. A type system that's designed
in a very certain particular way can actually express proofs about
what can happen in a program as it runs. And for example,
you can write a sorting function whose return type is promising to
return an array of sorted integers. You can represent that
at the type level. And then a type checker
can actually type check. When you write the
function, you weave in some proof code along with
your function declaration. You can actually
prove to the compiler that your function
actually sorts integers. So if the compiler doesn't
beep, then your sort function is guaranteed to be bug free. That's one of the really interesting
topics of advanced computer science. And I think parts of this are on the
verge of going into the mainstream. And this is an area that a lot
of the Verse research team-- some of the greatest programming
language luminaries in the world have joined Epic over
the last few years, like Lennart Augustsson and
Simon Peyton Jones, Rajat Jalal, and some other of the best,
most incredible language folks in the world have just
collaborated academically on the Verse paper in recent times. Like Guy Steele from
Scheme and JavaScript and other previous language efforts
is a contributor to the Verse paper. Putting a lot of thought into how
to build a language and a type system that's not
just some arbitrary programming language designer's fantasy but is based on these really
solid foundational underpinnings of proofs as programs
and of type theory. So that what we're building
is not just another arbitrary, funny programming language, but is
something that really has a direct relationship to mathematics and
logic and proofs in a way that, as I talked about at the start of
the talk, if we met up with aliens, when you compared our
programming languages, I think, if the alien civilization
is sufficiently advanced, then they'll have actually explored
and filled out all these kinds of language features that you don't
find in C++ or Java or C# but you do find in a lot of research languages. They'll have sorted that out. And hopefully,
Verse is one of the languages that will contribute to bringing these ideas into the mainstream. AUDIENCE: Thank you so much. Hopefully this one is a bit
quicker, but-- PHIL PIZLO: Hold-- AUDIENCE: I assume,
right now, because it's-- you gave me a lot of time, so I'll-- PHIL PIZLO: Let's just-- we're a little bit over
time, but let's just get another 10 minutes of
questions since it looks like there's a lot of questions. I'm sorry. I didn't mean to cut you off. I just wanted to call that audible. [CHUCKLES] Go ahead. AUDIENCE: I'm wondering-- I
saw, on one of your slides, you talked about the idea
of a metaverse browser. And I just wanted to understand
a little better where you see Verse running. Is it on client devices,
or on the server, or both? And how is that managed? PHIL PIZLO: Eventually both. TIM SWEENEY: Yeah,
yeah, and magically so. So the idea-- I think the core idea of what we
look at as the metaverse should ultimately be not just a whole
bunch of different servers running like the web servers do
around the world, which have no relationship to each other. The metaverse should
have the potential of being one continuous, seamless
environment in which everybody participates and any code,
any object, anywhere, could potentially interact with
any other object anywhere else. And to keep performance in
check, you just have to optimize code
using certain patterns. And in that view of the
metaverse, you really want the servers that are
contributing to the world simulation,
whether they're in one data center now or distributed or
decentralized, in the future, you want all of the servers to be
negotiating a single coherent world state as they go. And that implies all of the game
logic running on the servers to produce kind of a
definitive world state. But now, of course, that actually
sucks for practical gameplay because you have 80 to
100 milliseconds of lag from client to server
in a lot of cases. And you really can't tolerate
that amount of latency in character movement. And so what everybody
has been doing-- John Carmack pioneered it
with Quake World in 1996? Unreal Engine
implemented it in 1998. All game engines have been
running a predictive-- predictor-corrector
model, where the server is running the definitive
version of the world state, but then clients are running
some local copies of that in order to predict ahead what
the next state of the world will be so that you can hide all
local latency and player movement and simulation of vehicles. And the server is correcting that. So sometimes,
you see some jittering in objects. Well, that's when the client
is making a prediction, and then the server is coming
in and correcting it later on. But the way this has been done
in Unreal Engine 1 through 5 has been fairly ad hoc. We expose some functions
with explicit declaration, saying,
this code runs on the client, this code runs on the server. And you write your code
very, very carefully to make sure all of those functions
are running in the right place and are negotiating the world state. This is something we really
want to automate in the future so that you have one
definitive code base. And from the programmer's
point of view, the programmer ought to be agnostic
on where the code is running. But code is contributing
or receiving player input or
other local things ought to be predicted
locally on the client side-- and then corrected
by the server side. And rather than this
being done manually by programmers writing
specifications, the language runtime ought
to handle this automatically. That's the vision. We hope that we can implement this. Not everybody is convinced. But for the right now, for UEFN,
this current version of it, it's Epic-written
code running on the client and then
user written code running on the server. And if we want something
to be predicted really well on the client side, then Epic,
at the moment, has to write that. Because it turns out it
takes a lot more rigor to get a scripting
language that can be trusted to run on the client side. You have all of the
security considerations of JavaScript and the web
browser, plus additional console considerations. So we want to get there. But we're at least a year
away, perhaps quite a bit more. AUDIENCE: Thank you. AUDIENCE: Yeah, so I really
like everything I've seen. One thing that hasn't really come
up in conversations is memory. I assume that Verse is garbage
collected given that it runs on Blueprint VM now, et cetera. It's a functional logic
programming language. Are there any concerns
about space leaks or GC pauses being a performance
issue in the future? And have you-- no
one's mentioned Rust, but I'm going to mention it now. Have you looked at
other memory models that are maybe more inspired by a
Rust ownership model or something else? PHIL PIZLO: Sure. So in terms of space leaks,
even the ownership model wouldn't help you there. AUDIENCE: True. PHIL PIZLO: If you allocate
too much stuff, that's on you. In terms of GC pauses,
that's an engineering problem. And so I think that
that's how we're going to approach it rather than moving
the burden on the programmer the way that Rust does. AUDIENCE: Yeah. TIM SWEENEY: That's right. Right now,
there's a garbage collector that will run from time to time. And it might cause hitches. That's the current version of it. But this is a problem we'll be
solving more and more over time as we implement the new VM. And the aim of Verse is to just let
programmers write as simple code as possible to solve their problem. We don't want programmers to have
to worry about memory, ownership, annotations as they write code. It's just another thing
that's not all that critical if the compiler and runtime
can solve that problem for you. AUDIENCE: OK. First off,
this was really interesting. It's a really interesting project. Is "set" a transaction when
you're setting a variable? PHIL PIZLO: Set itself
is not a transaction. It's just one operation
within a larger transaction. The way to think about the
transaction scope in Verse is you're always in a
transaction until you suspend. So like in the example where
you called wait for input, if that thing actually
waits for input, that's a transaction commit followed
by a new transaction starting after the input comes in. But if you just write
a bunch of code that doesn't have any suspensions in
it, that's all within a single transaction
and completely atomic. AUDIENCE: Oh, OK. So that makes sense. So that means that transaction--
all of the state changes within that transaction, when they propagate
to all of the other people that are sharing the same state-- PHIL PIZLO: Yeah. All or nothing. TIM SWEENEY: Every actor tick
basically is its own transaction. So there's no concurrency yet. But in the future, every actor
tick could try to run in parallel. And when a bunch of actor ticks
don't have any read/write conflicts, as detected dynamically,
they could all commit. And when some have
conflicts, then some would have to be
aborted and retried. And that's the whole
idea of transactions. But when you have one actor updated,
and it talks to another actor, and that collides
with a third actor you could have a pretty large
chain of events happening all in a single transaction scope. AUDIENCE: OK. Thank you. Second question--
functions, first class, yes? PHIL PIZLO: Yes, mostly, right now. AUDIENCE: All right. Thank you very much. PHIL PIZLO: And this
is the last question. Sorry. Go ahead. AUDIENCE: Hearing about all of
this, it sounds really cool. And it reminds me of
UnrealScript back in the day, which, if I am remembering
and understanding correctly, was ultimately deprecated
because it was such a big task to keep it updated and
keep it up to date. And there was C++, which had kind
of solved a lot of the problems already. So what kind of new
problems is Verse trying to solve that isn't already
being solved by another language? I have some ideas based
on listening, but I just would be interested to hear what you
guys consider the new problems that aren't already solved. TIM SWEENEY: When we moved
from Unreal Engine 3 to UE4, we made a really hard decision
to get rid of UnrealScript. We realized that in order to keep
up with the expectations of modern languages like generic types and all
of these other features that were popular in C++ and growing into
C#, you need a world-class language design and implementation
and research team. And we had one guy. [LAUGHS] And so that just
wasn't a possibility. And so falling back to C++ was
kind of the natural thing to do. And it worked just fine
for AAA developers, but was not a great
outcome for indie devs who found it just hard, or harder
than writing in a scripting language. The solution in the
Verse era is a language that really advances the state
of the art in a number of areas-- with logic programming,
with this work on transactions, and with other aspects
of our programming model that we think's more
appropriate for the metaverse. And thanks to Fortnite's
success, we were able to assemble a world-class
language implementation and design and research team. And we have that here
in the halls of Epic. And we have collaborators
all throughout academia who are committed to
contributing to making this work. So we feel we have
everything we need now to make a really
successful go of it. And we think this is
a good thing to do. It would be very unfortunate
if the move to the metaverse left us with a bunch
of rather messy, untyped,
nonconcurrent programming languages as the foundation of it. PHIL PIZLO: And-- TIM SWEENEY: One more? Last guy in line? PHIL PIZLO: I think we
have to wrap up now. So but we can continue conversations
in the lobby or the show floor. Thank you, everybody. TIM SWEENEY: Thanks. [APPLAUSE]