 Perfect. Good morning everyone. My name is Marcus. I'm a software engineer with Snowflake and I'm working on co-FDB for three and a half years now. And I want to give you all an introduction into flow. So what is flow? That's probably the most important thing to get. Like if you read the abstract, you might already know. So flow is a programming language that implements the actor-based concurrency model. So think of Erlang and you're not that far off. So with flow you can write highly concurrent programs. It doesn't support parallelism. That's actually a feature. It kind of ships with an extensive library for platform-independent I.O. Ships is in quotes because we don't really ship flow. Or you could say it also ships with a distributed database. And it has exactly one implementation, at least as far as I'm aware of, and this implementation serves also as the specification because there's no specification and it's a C-sharp compiler that emits C++ code. And it is one of the main building blocks of FDB because all of co-FDB is written in flow. So there was a forum thread that was asking this question, why was flow developed? And I would encourage you to go to the forum and like check the answers. This is kind of my take and I have to warn you that this might be wrong because it's just my impression. I'm not one of the original authors so they might also have had other strong reasons. But basically the main motivation it seems was to allow for this simulation type of testing that FoundationDB implements, which is like FDB's secret source. Also, resumable functions were not available in C++ at the time. They technically still are not, but they might be in C++ 20. So we might be able to replace flow eventually. And C++ was chosen for performance reasons. I like to understand stuff by looking at how it actually works. So what I encourage you to do if you want to learn flow is write a small actor or steal one from, this one is stolen from the library. So this is like a helper actor that gets used all over the place. Take one of these short functions and run it through the actor compiler and look at the generator code. It's very painful, but it's a very helpful experience to do it at once. So I won't go through all the generator codes because it would fit on probably 15 slides. And I don't think you would enjoy that. But basically, so what this thing is doing is it waits on some input and then takes the resulting value and sends it to a number of promises. And so the two keywords that you can see in here, and these are language keywords, is actor and wait. And they are just equivalent of async and await in C sharp or I think JavaScript has that as well and Python. The other fundamental building block is futures and promises. So a future can hold a value now or in the future. And a promise can be used to send that value to a number of futures. And the way this is implemented very rough. So there's this SAV object which you will never encounter when you just use flow, which is a single assignment variable, I think it means, but it does no code command. So I wouldn't know. And this one stores a value and it's basically reference counted. So their promises and future ref counts. And the promises and futures are kind of like smart pointers to that object. And it also points to a linked list of callbacks. So whenever the value is set, it will call into all the callbacks that are registered to that. So to generate a code very quickly, like the function itself will look like that. Not very interesting, but basically we create a new future that gets this broadcast actor. So that's how the generated class, the generated actor is called as an argument. And if we look at how that looks like, I will, like this might be a bit too much information for one slide. But the basic idea here is that each actor is an SAV object in itself. It has some additional state. Everything in blue here is part of the code and everything in red is generated by the actor compiler. There's the actor state. So remember this is all callback based. The generated code, there's no stack for each actor. And all the state that has to survive a wait statement is stored in that class. And actually also most of the logic or almost all of the logic is in the state class and not in the broadcast actor class. And the broadcast actor class is mostly there to bring everything together. And so when you run a program, this will just generate callbacks for you and it will take the dirty work that you would usually do if you are familiar with like boost SEO where this can get pretty painful. This is obviously not also there are a few more language features. So one problem is there's no stack. And we have a compiler that is not very language level. Let's put it that way. So if you write a function like this, so this is basically takes the current time and then it's just an endless loop. It will sleep for one second and then gets woken up after that one second and it brings the time from now minus the start time. So it will tell you how many seconds it did run for. And this loop keyword is basically just the redefinition of while through. So it's just an endless loop. This will not compile. And the reason for that is often like this wait keyword actually registers a callback and returns out of the function. So you lose your stack, which means that when you try to access start time in the line afterwards, you will get a compilation error and the compiler will tell you that this variable doesn't exist in that context. So to solve that, there's a state keyword, which you can add to to your in front of that variable declaration. And what that will do is it will tell the actor compiler, hey, I want to use this variable throughout the life of this actor, please store it as part of the actor state. So it's a bit similar of like capturing variables in lambdas. Another feature is you can wait on multiple futures at once. So you can, I mean, you can have as many callbacks as you want to write. And this is basically what it does. So this is mostly presenting the syntax. The example I chose here is not very meaningful. But basically you can have this choose keyword and then a bunch of when statements and you have to then call wait on some futures that you have there. Another very useful features is streams. So if you're familiar with go that's used all over the place, streams are unidirectional in flow. And so there are future streams and promise streams. And you can read from a future stream, and you can write to a promise stream. And you can pause these streams to other actors and therefore these two like two actors can communicate with each other. So this is a very stupid example. I have a small add function here and add actor that just waits on a value in a loop. Whenever it receives a value, it will update its internal state by just a simple addition and then it will send it, send the complete sum to some promise stream. And in order to use that in a very bad way, so please don't try to make PLs with code like that, you probably won't get that merged. But basically what this is doing is does this loop that will sleep for a second, then it will send one to this promise stream and then it will wait on a future stream to receive the result. Now one interesting thing here is we don't call wait, we call wait next. And this is sadly necessary because again the actor compiler doesn't really understand C++ correctly, so it wouldn't know the type of whatever is in the parentheses. It cannot do type deduction for us. And because of that we need to tell it that this is actually a future stream and not a future because the generated code is slightly different in that case. So that's basically it, then this is actually most of flow already, there's not much more to it. There's one important library feature, the remote futures. These are technically probably not part of flow but of FTBRPC. But this is basically how you can do remote procedure calls or basically you can have futures promises and future stream and promise streams having on two different machines or two different processes. And the functions that implement, the classes that implement that request streams which are the equivalent of a future stream, there's the reply promise which is the equivalent of a promise which you can send to another machine and then that machine can send the promise and you will get the result. And both of them have a get future method that you can call to get the other reading object side of that. A good example to look at in my opinion is in the FTB code there's this storage server interface.h which implements all the RPC calls that we use to communicate with storage nodes. And it's pretty readable. It's one of the places that is actually pretty readable. So I'm still doing okay with time so I want to go into a few of the common pitfalls. So when you start programming in flow, most people will have some of, will do some of the similar mistakes that we do just because sometimes flow doesn't quite work in the way we expect it to. And most of these common problems result from the fact that the actor compiler doesn't really understand C++. I mentioned this a bunch of times. Like for example, one really annoying example is if you write lambdas and I love lambdas, I write, I tended to write them all the time and now in flow I use them less because of that. You can't really capture state variables because in the generator code, the state variable is actually a member of a class. And so it gets a bit weird. And then as I said before, type deduction doesn't work. So if you write the rate statement, you always have to explicitly declare what type you're waiting on by actually reading the result into a variable. And unless it's a future void, then you cannot meet that or actually you have to. And then the memory management rules, like the best practices how to do memory management are a bit different. And I won't really go into that here because that's like its whole topic for itself. So one common thing that people for trip over initially is that arguments to actors are getting copied into a state. And so if you try to write code as the first line here, you try to pass a string as a constant reference, then the actor compiler, because it is limited in its C++ knowledge, will try to rewrite it as something like that. I didn't try whether that's the actual code, but it will probably look a bit like that because it will try to copy the reference and not the string, which is not what you want to do in that case. Or you can't. So this won't compile. So if you want to pass something by reference, what you have to do is you have to pass a pointer because you can copy pointers, and then this will work. Another thing is that actors, whenever the, if the future count of an actor goes to zero, it will get canceled and it will stop working. So this is the same stupid counter that I had before with one bug that I introduced. So those who like HAs should probably see that pretty quickly what's wrong here. But basically we create this actor in like the, I don't know, sixth line or something. And it will run out of scope as soon as we call into wait. And therefore it will get canceled because we didn't pass this future to any other location. So this thing actually has to be a state variable so that it can survive this wait call. There are also some weird scoping rules. So this one here will actually compile this actor. It shouldn't, right? But it does. So what's the result of this actor? It's not clear what it should do. Should it be five tries? Should it be something else? And actually if you run that, what happens is that the first line is undefined behavior. So that might give you whatever. And then the second print will give you five. And the reason if you understand how state variables work is pretty simple, right? The state variable is just part of the actor state. This one is available throughout the whole, while the whole actor is running and there's no comp, like the compiler doesn't actually prevent you from writing code like that. So this is something to be a bit careful about. Another one is error handling is a bit weird. So if you write a code like that and let's say s is like a future to an actor that throws some exception after a while, you will not see that exception if you write the code like this. The reason is exceptions are only propagated if you wait on them. Or if you explicitly check whether they are storing an error currently. So yeah, that's basically it won't be thrown up. And so there are multiple ways of how you can fix that. You can additionally rate on that thing and just assert that it never actually returns anything if it's supposed to be an actor that should run forever. And then you can also catch the exception by just putting everything into a try catch block. Like as you can see here, this can get awkward if you have many, many actors. So there's this library class called actor collection. And you can just like pass all your futures into that and wait on that actor collection. And this will re-throw the error for you. So this is it mostly from my side. But I wanted to point out a few very useful resources, or I believe useful resources. The first one is there's a very short documentation on flow that you should look at if you're interested in that. In the codes, there's this tutorial.actor.cpp. And please, like there should be a forum thread or whatever. Look at that if you see anything missing or see anything unclear, like mention it and I will try to update it. It should have code comments on like how stuff works. It implements like a small key value store. Like not a good one. And another thing that is pretty good to look at, there's two versions of generic actors.actor.h which are files with like helpful actor functions. And it's good to have kind of a mental model what's in there. It's basically like algorithm in C++. You want to know what's in there because otherwise you re-implement that several times. And you can find stuff like this broadcast function, you can find a map function, you can find operators for end and all. You can do wait or error, which is sometimes useful. There's the flow log thingy. So if you don't want to have two actors concurrently accessing some data, you can use that. And there's many, many other useful stuff. And it also helps to understand the code style that you're supposed to use and how you can implement certain things that might not be completely obvious how it should be implemented. Like a lot of stuff is in there. So to me, this was actually one of the best learning resources to just look at that header file. So please go to the forum if you have questions. And I will try to answer as many of them as I can. And other people like AJ and Alex and whatever will also be there and will help. Thanks a lot.