 Okay, I think we should be okay on recording now. All right, then I'll go ahead and begin. Okay, so my name is Gabriel. I'm an engineering manager at Arista Networks and today I'm going to be talking about doll, which is a programmable configuration language. Sorry. So in this talk I'm not going to assume that you know what doll is or I'm not even going to assume that you know what a configuration language is. I do assume that you have functional programming backgrounds this is the Houston functional program group. I'm not going to assume that you have Haskell background specifically so although doll was originally created as a Haskell implementation like it's really Haskell agnostic at this point. So I'll divide it roughly into three sections. In the first section I'm going to talk about how to use doll, sort of like an ordinary configuration file format, kind of like Yamal or Jason playing data. And this is before we even get to the programming language features. And then later on, I'll talk how to use the actual programming language features of doll. And in the final section I'm going to emphasize what are called dolls language security guarantees because this is the most common reason that people adopt doll in anger and use it despite some of its deficiencies. So first off, doll is a programmable configuration language and to a first approximation, you can think of doll as Jason plus functions, plus types, plus imports. And when I first created doll, I didn't actually have any intention of making it production ready it was really just an academic exercise because I would see in various social media forums, the same debate play over and over again, where somebody would say, gosh, you know I'm, I work in like cloud or ops. And I have to maintain these very large Yamal configuration files which are getting unwieldy, you know I really wish I had some ways of reducing repetition and types and tests, like I really want my configuration files to have some programming language, sorry some programming language features to make them easier to maintain. And inevitably, someone would always counter. Well I don't want my configuration files to be terrain complete right I want them to be safe inert playing data. And so the thought experiment was, if would you be okay with a programmable configuration file, if it was not terrain complete. And it turns out that the answer to that thought experiment was yes. And so doll ended up growing beyond my initial proof of proof of concept implementation so I just kind of went with it and learned a lot along the way and tried to make it as production ready as possible. So doll is like Jason in the sense that doll supports as the data types that doll natively supports are things like scalar values, records and lists, and some other things that we're not going to go into. And you can also directly convert doll as data into a host programming language, just like Jason so like and typically you can read some Jason file into your program, you can do the same thing with doll too. But it's very often when you first start out it's more common to actually turn doll into a Jason file first, and then read that into your program. In fact there actually is a utility for doing this called Delta Jason. So on the top here is an example doll configuration file for some users configuration so we have a record with three string valued fields. One for their home directory, one for their private key path, one for their public key path, and it corresponds to this Jason record, okay the syntax is a little bit different but it's pretty obvious what the mapping between the two is at least for simple examples like this one. And we can also convert in the other direction to so given a doll configuration, sorry, given a Jason configuration file, you can convert them to a doll configuration file using Jason to doll. And, but usually the the corresponding doll version will be a little bit more explicit than the Jason version, because doll is is more strict about the types and Jason is. So for example, if you have a list of records, the dolls type system requires that all the records in that list have the same shape, including the same fields. So, like in the Jason version, you can have the discontinued field in one record and not in the other record, whereas in the doll version, both all the records are going to have to have this discontinued field. But the difference now is that it can be an optional value so either it's present using some or absent using none. And the Jason the doll conversion utility will take care of doing these things for you. In fact, one way to build an intuition for doll is just to write out some Jason and then use the Jason the doll tool to figure out what is a rough idea what's the idiomatic doll that would correspond to that Jason and that will get you started. And you can also do the exact same thing with YAML. So you can convert a doll file to YAML in the obvious way. And you can also convert a YAML file to doll too. So like here's an example, like more ops like configuration file for some Docker configuration. And here would be the corresponding doll doll configuration file that models this the exact same YAML file. And I'm just assured that this conversion will roundtrip. So if we were to convert this doll file back to YAML, we'd get the original result. But so far, all the examples I've been showing up in that input till now have been really contrived in simple examples. So before I proceed any further, I want to show you what a real world doll configuration file looks like. It's a kind of file that you might where you're using doll in anger. So like maybe it's not very pretty. And, you know, maybe require some workarounds but like it gets the job done it's a real world use case. And one of the most common real world use cases for doll is Kubernetes, especially because Kubernetes configurations can be very large and difficult to maintain without some sort of programming language features. So I really expect you to understand this file at first glance. I'm just showing you so you can just take it in visually. But the idea here is that, you know, in doll we can actually type, sorry, each resource we can actually explicitly declare like this is supposed to be a deployment this is supposed to be an object made up and so on. And then we can validate the configuration against an expected type. And so using doll we can actually verify ahead of time that Kubernetes configurations are correct by construction so we will get significantly fewer runtime errors and we would if you were just using plain YAML to author these files. And what's cool though is that you don't need to know how to author that doll configuration file so you can actually convert a Kubernetes configuration to a doll configuration file totally automatically. Oh, sorry, this is just showing converting the previous example to YAML. But if I wanted to convert this YAML back into that same doll file automatically you can do it. It's a very large command. Okay, so we're not going to go into too much details here but it's possible. Basically if you can tell the doll compiler what is the expected type that you want the YAML file to be. And if you can also give it a set of all the default valued fields that it can perform this conversion to the doll expression, basically automatically. And so this is actually the output of that command right there and it will work for any Kubernetes configuration that this exact command here. The doll doesn't support only Jason or YAML doll also supports XML bidirectionally. It also all supports bash unidirectionally. So bash is sometimes uses a configuration format for like postgres. So in postgres they use environment variables to configure its runtime behavior so bash is being like a pseudo configuration language. So there's a proof of concept converter from doll to nix. I say it's proof of concept because like I think you would not be able to use this realistically in production, I don't think anybody does. But I am definitely sure that people absolutely do use these former for conversion utilities in production and I know because of all the tickets I get to fix various issues for them. So you have to go through a Jason or YAML intermediate when you're using doll. So if your language supports a native doll binding, then that language can read in doll directly into the host language instead of going through an intermediate. Kind of like they can read Jason directly and not having to go through some other format. So for example in Haskell, again, you don't have to use Haskell, I'm just showing kind of what it would look like. In most doll bindings, the way they will work is you'll declare some data type that is the shape that your your configuration should be in. And then the language binding will then be able to automatically marshal the doll configuration file into a record or a data type of that shape. And it will give you a type error if it doesn't match the shape or if there are any other conversion errors. And so it's basically kind of like using Jason because like the Haskell's Jason marshaling library works in the exact same way. You just define some data type. You derive from Jason and then it can read that Jason configuration file into Haskell. The only difference is that instead of driving from Jason we derive from doll, but it basically works the exact same way. And the languages that support a native language binding are closure Haskell, that was the original one. Go Ruby rust. And because of rust you can then like generate C bindings. In fact, for example, there's actually a Python binding to doll which is based on on top of the rust bindings. And also, there is a there is a complete Scala implementation of doll which has not been officially announced yet, but it implements the entire standard. And there's a there's a corresponding Java implementation which implements everything except dolls import system which we'll talk about later. And the most wished for language binding is Python. So although there are Python wrappers around the rust bindings people are still asking for the native Python binding, because they would just like to have that it's it's simpler for them to you know build install. If you ever want to know what's the latest up to date list of supported integrations or language bindings or conversion utilities. There's a website docs dot darling dot org, which describes all the supportive ways of integrating doll into your project. So let's let's so suppose that you are using one of those officially supported languages and you're wondering, which approach should I take, should I go through the Jason or email intermediate or should I use the native language binding you tell me Gabriel, which one to use. What I would recommend is that when you're first starting to use doll, definitely go through the Jason or YAML conversion route for a few reasons. It allows you to try before you buy, meaning that you don't need to get buy in from your peers, when you begin to use doll, like as far as they're concerned you're still checking in some Jason or YAML file into version control. They don't really care where you got it from. And then we can do is later on you can say, Oh, you know, by the way, you know, I was actually generating this Jason or YAML from doll, and that's the real source of truth here. And it's much simpler and easier to maintain why don't I just go ahead and store that inversion control. And then that makes it easier to get other people to adopt it. Another reason I recommend this route for adopting things is it's much easier. You don't require buy in from the, you know, your ops, or, or CI people, because all the tooling that you need for this is available as statically linked executables for Windows and Mac and Linux, the interpreter, the various conversion utilities, and also the language server for ID support. So again, just download them and you're ready to go. But suppose that you do get buy in from your peers to start using doll more pervasively at work. Then the next route is that you can start using the native language binding and but far and away the most important reason to do this would be simplicity, because like you know you don't have to have, you don't have to have this Jason intermediate anymore, you just have one configuration file instead of two that need to be in sync with one another. It's easier to deploy and to run and so on. So that's really is the one reason for using native language binding. There are two small reasons which is that doll supports unions, also known as some types. And Jason and Miele don't. So if you go through a Jason and Miele intermediate, when converting to your host language, something will get lost in translation or you'll have to model it somehow and so it's not as type safe. Another reason why is that some language bindings actually support the ability to marshal doll functions into host language functions. So just as a little taste of this here is a doll function which takes some number and then creates a list with two copies of that number. And I can read that doll function into Haskell at runtime. And I get a Haskell function which does the same thing, which is pretty cool. There are limitations on, you know how this works, but when it does work it's pretty nice. So this is not covers doll just using doll sort of like a plain configuration file format and the next section is going to talk about the programming language features. Do people have any questions so far. Yeah, so I had one. How do you fit on, like, not standard types into the doll? Um, so usually, so like, the way I interpret this question is like, you know, YAML has this system where you can define like, you know, types that are extensions like the default YAML specification I forgot like what are some example but doll does not have anything like YAML's plugin system for types. So usually, you have to just find the closest doll type that approximates that. And so sometimes, you know, you lose some type safety because of that. Yeah, as an example, like, a date, right. So like, if you if you model a date as a string in doll, then you lose something gets lost in translation there right you can't like do is no longer type safe. Another example would be like an IP address right doll does not have a built-in support right in IP address. Actually we are talking about like adding built-in support for dates but definitely not IP addresses as far as I know. So usually, I mean, sometimes you can find a way to try to make it a little bit more type safe. So like, let's use the date example, right, like you could try to model a date in doll as like a record with, I don't know, three fields like an integer for the year, a natural number for the month, a natural number for the day, but then you can still represent invalid days like you have a month greater than 12 or a day greater than 31 and so on so there's still type safety loss there. But yeah, like, I guess you try and get as close as possible. And then sometimes people will then try to make a push to upstream certain key types into language standard. Because dollars actually is an evolving language standard over time and we're always, you know, adding support for new types new built-ins and response to user feedback. I have a sort of similar question. You said that so doll has some types, but Jason, you know, don't so how, how are those translated. So the in the automatic conversion utility, it will just strip the tag, basically so if you have like, you know, so as an example, let's say you have using has to terminology like either bull or int, right. And if you have if you have a list with left, true, and then right one in that list, it'll just strip the left and right constructors when it converts to Jason, leaving behind a list just containing true and one. So by default, just it will throw away the tags. So there are some ways you can preserve the tag information so but the Haskell, the so the documentation for the conversion utilities explains in more detail how to do that, and there is a way but it's it's pretty technical. So you start with me or Jason, you can convert doll and then you can convert back perfectly, but he starts with doll you can't necessarily to work perfectly. That is correct. Well, yeah, yeah, so if you do doll to so doll to Jason to doll, you're not going to get back. Sorry, let me take that back. So when you convert from Jason or YAML to doll, you can actually give the conversion utility the expected doll type, and it will do its best to select the correct constructor to convert back into based off of the shape of the Jason data. And of course the case where that doesn't work perfectly is if two constructors both wrap the same type. So for example going back to that Jason example if I have like a list of bull true, and I say convert back into this union type of like you know left bull right true. Then it will do the right thing and it'll select the right constructors based off of what it sees in the Jason data. Yeah. Yeah, if you don't provide the expected doll type, and then it will you know it will auto generate it will infer the closest doll type to the Jason data and like it'll choose some, you know default constructors for each scalar type. So if you have a targeted conversion, like say for an example. Can you have more than one of those in a single doll document or file. No, you're like the conversion utility only works on the entire file so you can't like have different behaviors on like subsections of the file. Like, export like the local doctor thing thing. And, like, the servers. You don't like me. So one thing I want to mention really quickly is that not only is there a way to not only are there command line utilities to convert from doll to Jason. There also are pure doll implementations of that conversion, it's a little bit less ergonomic, but it's more powerful and sophisticated so for that utility, at least for the doll to Jason direction, you could actually have different behavior for different sections of the Jason because it's because it's implemented in doll rather than as like a single utility which processes an entire file. Yeah. Any other questions before we go on. Okay. So doll is a programming language, and the symbols that you can do if it's a programming language is you can factor out shared logic to avoid repeating yourself. Using the original example, let's say that I want to make sure that the home directory, the private key path, and the public key path all stay in sync with one another. What I can do is I can define a variable called user named and set it to bill. And then I can inter interpolate that user variable into the three string value fields and now they're guaranteed to always stay in sync with one another. But like this, this example is actually available on the website. So if you go to doll dash link.org, then if you go to the definitions example it's the exact same example and it's a live demo so whatever I type into the, in the left pane will then automatically update on the right side of the pain as well. So for example if I change the user bill here to Jane, then the right side will update immediately or, you know, Gabriel, for example. So this is a great example of how you can avoid repeating yourself if you use doll. And so it makes things much easier to maintain and less error prone. And the, the simple types of doll supports are bullying of values. So true and false text values select the string Hello world. These are natural numbers, which are non negative integers, and the natural literals are unsigned like zero one and two. And there's a separate numeric type for integers, and these literals are always signed, even when they're positive. So like plus zero plus one plus two. So there are two different types, and the reason why doll uses a separate type for natural numbers. It's because natural numbers are actually much more commonly used in all of dolls standard utilities. And the reason why is because usually the natural number type is the more appropriate type, both for like the input or the output for a function. So if you take the length of a list, the results are really to be a natural numbers never going to be negative, or vice versa if you're saying like you know how many elements should I drop from the list like that should also be a natural number you're not going to drop a negative number of elements. doll does not do automatic numeric number promotion so you can't like use a natural number where a function expects an integer, for example, all conversions between numeric types and doll are explicit. There's no implicit conversion between them. And the natural number and integer types are unlimited precision. But the double types, sorry, are, these are I triple E double precision floating point numbers. So these are not unlimited precision. And doll supports complex types which build upon those simpler types. So for example, you have an optional type, which represents the value which can be present, and then it'll be wrapped in some world be absent. It'll be none followed by the type of the value if it I've been there. It's like an actual number, let's say. And notice how this is an example of how dolls type inference is limited compared to like many more sophisticated programming languages and we'll get into that a little bit more later on. But it's so like many languages, it's rounded in brackets elements are separated by commas. But is important to note that if you have an empty list, you also need to provide an explicit type annotation. So this is another example where dolls type inference is limited. And they're like many of the languages, they're surrounded by braces key value pairs with commas equals instead of colon. So it's not like Jason in that regard. Field names are do not need to be quoted in most cases, but you can quote them using back ticks. And then unions, I'm not going to go into too much detail about unions but basically they're like some types. Okay, and you can also have enums to which are just a special case of some types. You can nest these complex types arbitrarily just like Jason or YAML so you can have like a record of records, or like a record of lists of optional values and actually there's one thing you can do which you cannot do in Jason or YAML which is that you can list optional, you know, layers arbitrarily whereas like Jason or YAML you can only have one level of nullability. So it's important to note that in doll, things are non nullable by default, and you have to explicitly opt in to nullability so you can't accidentally have absent values where you weren't expecting them. Oh, go ahead. Sorry, what was the question. Oh, why, why is it called double. Yeah. If you don't need performance, why not have the precision custom type instead of just using it. Right. So this was actually in response to user feedback. So originally the Haskell implementation used unlimited precision floating point representation what the there's a Haskell package called scientific and that's what we use. And originally the standard did not specify what precision the types had to be. And then most of the users were actually telling us we want you to use IEEE double precision floating point numbers. And so, and we did that and I was like, okay, I'll just do what the users tell me to do basically. The second reason was because this was easier for other implementations to implement. Because remember that doll is not just one Haskell implementation, it has to be a language standard which is implemented from scratch in several different programming languages and so like their respective language might not have a package for you know infinite precision floating point numbers or it might not work the exact same way as Haskell's or it might not parse, you know the literals in the exact same way so this made it much easier for them to implement the language. I can foresee a scenario where I'd be a programmer writing config files. Yep. And I get blown by the fact that it is not precision. One thing to note here is that even though it's not limited precision, you're not going to get a runtime failure if you specify something that's out of precision. If that happens, like the standard actually requires that it fails at parts time if that ever happens so you will actually get a fail fast scenario if that ever does occur. So, in that explanation, I totally understand this. The second reason, but why are the users asking for that was. Um, I would have to look it up. It was, it was like years ago. Basically, I don't remember the exact reason truthfully. Yeah. Um, okay. Any other questions. Okay. So dolls text literal support is best in class among configuration languages and it's a lot of text features are stolen from the next configuration language. So for example the syntax for string interpolation is the exact same as Nick's and also some other languages to not just next like you know this is also passes bash to. So you can interpolate using dollar sign braces, and also uses the same syntax is Nick's for multi line string literals. So you open with two single quotes, and you end with two single quotes. And, and I'm a mnemonic, if you want to remember this easily is that think of these as like large double quotes, if that helps you remember it. And just like Nick's doll will automatically de-dent the leading white space from the string literal as well. Another feature, which a doll supported from which doll stole from Nick's. And actually, doll and Nick's are not the only languages that do this so like the q configuration language also has a similar syntactic thing to. But basically you can if you want if you have nested records like you know a equals b equals c equals one and then d equals true. You can use this more condensed syntax where you can say a dot b dot c equals one a dot b dot d equals true, which comes a lot and handy when you're trying to work with deeply nested record types. So actually doll can handle some pretty sophisticated cases that Nick's does not and because, and this is actually it, there's a lot of tricky logic that actually makes this work pretty gracefully. And of course, it all has functions. And so this means that you can avoid repeating yourself using those functions. So for example, let's say that instead of one user configuration, I want to maintain a list of user configuration so one record per list element. One for Jane. And you can imagine that if you want to add a new user and you were not using a programmable configuration language, then what you would do is you would copy, you know one of these configuration records and paste it and then you update all the values like replace Jane with Gabriel and you know that's very tedious and it's error prone doesn't scale very well. So if you have functions that's much easier. So here's an example of defining a function and all. So everything from here to here by itself is anonymous function. Well it's not it's anonymous right up until we give it a name, make user in this case. You might also call this a lambda same thing. So this function takes one input name user of type text. And then this right here would be the body of the function. So in the body of the function we define three variables home private key and public key. Each one is defined in terms of the previous variable. And then this is a convenient shorthand syntax for packing those variables into a record fields of the same name. And once we have this function in hand that we can easily stamp out new users just by saying make user bill make user Jane, and then it generates Jason like this. In fact this is another example from the website so we can actually try it out live. So if I want to add a new user like Gabriel, I just say, you know, make user Gabriel, and then voila. I've got a new user configuration as the list. And that's much easier to maintain. Dolls also typed. So that means that you can add type annotations in various places in order to assert that value should have an expected shape. It's kind of like Jason schema, except the schema lives inside the language it's not like a separate file that lives off to the side that you maintain separate from the actual Jason configuration. And so here's an example where we can not only can we define, you know, values or functions and doll we can also define types and doll using the same let syntax. It's because in doll types are first class so you can define them using let you can stick them in a record. You can do all sorts of things with them. So they're not like a separate like they don't exist on this separate level so types and so dolls actually a technically dependently typed language so meaning that like you can actually mix types and terms together with some restrictions which I'm not going to go into. So here I'm actually so and whenever you see this colon right here, you should read the colon as saying like is a or has type. That would be like saying so config is a type. And specifically it's this type is the type of a record, which has three values, each of which has type text. And then once I define this type, I can actually use it in downstream type annotations. So now I can give make user a type annotation saying make user is a function from text to a config. And then also for each variable that we define within the body of the make user function, we can give those type annotations to like home is text private key is text public key is text config is a config. So these type annotations are not necessary. So even though doll does have limited type inference, it's not that doll has no type inference it does have some is just that doll does not have bidirectional type inference which is what many people mean when they say type inference. So you may still want to add type annotations in places, even when they're not strictly required, maybe just to make it easier for humans to understand, or maybe to clarify your intent a bit better, or maybe because you want to assert that something should have the expected type kind of like you want to validate it against the schema. I'm sorry, go ahead. Directional type. Yeah. So an example of bidirectional type if we had bidirectional type inference, then we wouldn't need this type annotation right here. Because then the compiler could infer so bidirectional type matter. So like if the compiler were sufficiently smart. So the interpreter, not compiler. If the interpreter were sufficiently smart, it could look at this code down here and be like, Oh, like, hey, I see you call the make user function on the string name bill. So I assume that means that this should have the type text, or similarly you can see like, Oh, hey, I see that you took this user function input, and you interpolated it here into the string. And you can only interpolate strings. Okay, there's no explicit conversion to strings. So therefore I should be able to infer that this function input should have type text so that's what bidirectional type inference means that it means that the type the compiler looks like the interpreter can do type inference in reverse it can work backwards from how you use values to figure out what their types should be. So I think you said you were going to talk about this more. Yeah. And mainly it's because it's difficult to standardize and implement. That doesn't mean we're not going to standardize or implement, but it's just takes time so we're slowly trying to add more, more spots for type inference into the language as we go. And every time we make any change the language it has to be, you know, fanned out to all of the officially supported language changes. And we wouldn't, and there's no way we could switch to a totally bidirectional type checking system overnight. That requires like a lot of preliminary changes to make it as easy as possible for implementers. Can you repeat the question. The implementations for all the other languages. Are they both implementations like it's here go. Yes. Yes, so it's not like the go they're not so that so like one of the things about dolls that like in order to vote on changes to the language standard. You have to have implemented the language from scratch within a language like the go the go implementation is implemented entirely and go the Ruby implementations implemented entirely and Ruby. So because they are implemented from scratch, they get to vote on changes to the language standard. If you do a derived language implementation, then you don't get a vote. It's still useful but like that's how kind of how we that sort of like is the unit of work as far as consensus goes within the community. Yeah. Yeah. Sorry, I think I didn't hear the question. Oh yeah. Why some features. And you couldn't. Yeah. Yeah, it's not like so one of the things we have been discussing is perhaps like, should we just have like a few key implementations that others are derived from. So like maybe only like rust Haskell and let's say JavaScript. And then all the other implementations are just wrappers around like those three key ones because you can get a lot of mileage out of like just those three, because those three languages tend to have lots of bindings to or ways to compile to other formats. So like rust can like handle the whole, you know, see native based languages, JavaScript can handle all the JavaScript based languages, and Haskell can handle like, you know, works a lot of functional programming languages. So that's one thing we've been discussing but we haven't officially switched to that way of doing things yet. Okay. So going back. Okay, so doll also has imports and this is in my opinion is one of the coolest language features. So you can embed other doll expressions by their path. So if I save the number two to a file called number dot doll, and then in another file, I can write number dot doll plus number dot doll. And it's as if I had written two plus two. And this doesn't just work for, you know, playing data, it works for any doll expression. So you can import a function in this way, like literally any doll code any doll sub expression you can factor out into a separate file. Similarly, if you reference the same file more than one time, you'll typically use a lot binding to avoid repeating yourself you'll say like let number equals this import. And then you can just say number plus number. And this is pretty important when you have longer relative paths or absolute past you don't have to keep writing the path over and over again. You can also import doll code from environment variables. You can also. And so like this example we're importing the username from an environment variable as text just means we're importing the raw text value that environment variable. But you're not import you're not restricted to importing just raw text, you can actually import arbitrary doll code from environment variables you can import a doll function from a direct environment variable if you wanted to, for example, you can import a doll type from an environment variable because types are first class in doll. And so now we get to the most controversial language feature in doll. You can also import doll code by URL. So data functions types you name it, you can import it via URL. So here just started laughing. Yes. Yes. Yeah, so here. Yeah, let's get into it. It was already like going on. Okay, so yeah so so I'm going to make the statement that even though doll supports importing arbitrary code from URLs, I will assert that doll is actually safer than basically every other language out there. Okay, so doll is actually the best in class when it comes to language security guarantees. And we'll get we'll touch more on that in the very last section of the talk. So, but let's just show how this works. I'll just assume the magic right now. Okay, so given a path to a URL, which represents utfa encoded doll source code, like I'll actually just open up this URL right now. So let's go there. Right. So here's the doll source code that that URL represents right there. And so that URL is so that URL within the code is the exact same. It's as if we had sort of with some caveats as if we had just inlined that code that is in the URL. And so I can assign that to this variable called generate and I can now just use like a function. So here I'm actually importing a function from URL expression. So this make user expression right here is the same as the one we saw before. Then we're going to create a little wrapper around it called build user that basically given an index into a list, we're going to create a user named build, and then the index of the list rendered as a string. Okay. And this again the reason we have to do this explicit conversion here is because we don't do explicit promotion of types so if you have an integer you need to convert it to a string for you interpolate it. And so now at the bottom we're going to say generate 10 configs using the build user function. And then that's another example from the website so we can just run that really quickly. So this is with a bit more comments but it's the exact same code. And so here on the right you can see we've generated 10 users so build zero build one build to up to build nine. If I want to generate 90 more users will just add another zero here and then there we go. We've got 100 users. So this is where you can really see the power of repeating yourself like if you asked me to like try to generate 99 of these users by hand you know copy and pasting editing it. There's no way I would do that without making mistakes, basically. And here's the key part, the language design ensures that these URL imports are secure and we're going to go a lot more detail about that later on. Before doing doing that I also want to talk about tests. So dull provides language support for tests. So meaning that, given a function like this one. So this is a function from dull standard library, which is called the prelude, which checks if one natural number is less than or equal to another natural number. And then we can so and then we can write some unit tests for that function so we can say okay by should be less than or equal to true type by should be less than or equal to six that's true. By should be less than or equal to five that's true. By should be less than or equal to four that's false. Okay. And so these tests are all run at type checking time, not at runtime, because in dull all the validation is supposed to be done ahead of time so that you never get runtime failures. I don't want to go any further. Do people any more questions. I have a comment. Oh, no, if you want to be secure, you copy that thing that's in the public Internet, you would have to find it. Well, you don't even have to do that. So I will show you ways that you can. So I'll show you what are the things that actually make dull safe so you don't need to trust, you know, DNS, like literally. It was more later but basically, it is safe to interpret malicious doll code like I could actually host a server on the public Internet that you just give it a URL it will interpret it. And that is a totally safe server for me to host on my desktop, and you would not be able to compromise my machine. Let's say you're importing a list of fireball exception. Anyway, let's move on. Okay, so. So one of the things I like about the way dolls designed is that many higher level features of doll are just the composition of smaller, simpler orthogonal language features. For example, in doll, a package is just a record that you import from a URL, and it might be nested like if you have sub packages of that record. For example, this is how the prelude works. So the prelude is a URL, which is just a giant record actually is a record of records so each sub record is like one sub package of the prelude. So here's a record and it has a field named bull, which is the bull sub package of the prelude, and that record has a bunch of fields which are functions, and one of those fields is the not function. So if I want to access the prelude not function I can say prelude dot bull dot not, then true, and then that will return false. And you can also support the sub package directly to you don't have to import the prelude so there's another URL you can use just to import the bull package if that's all you want. You don't have to import the not function directly, if that's all you want to you don't have to import an entire package. Another emergent property is templates. So in doll, a template is just a function that interpolates text using doll support for string interpolation and multi line strings. And that takes one argument named args, whose type is a record of two fields named year and copyright holder. And then we just interpolate those fields into what in this case it's an MIT license this is a function for templating an MIT license. And the way you instantiate a template and doll is just function application. And so that's how you provide the parameters for the template. And so here we're using we're taking advantage of the fact that in doll you can reference an expression by its path. So here's a function that I can call just by putting the past to the function. And here the function arguments which are just it's just a record of parameters to pass to that function and then it will template that MIT license using my name in the year. Another emergent property is support for schemas. So like kind of like JSON schema. And so in doll, a schema is just a type annotation that you import. So I can save a type to a file, I can call that you know schema dot doll. And then I can provide a type annotation for my main configuration file which just points to the path of the schema. And this works because you can import any type of doll expression and since types are expressions you can import types in this way. Another emergent property of doll is a property tests. Actually, I don't think property test is really the right word here, but it's the closest thing that you may be familiar with. So if you've ever used something like Haskell's quick check, I think there's also a Python quick check package to. So basically, if you're familiar with quick check, the way it works is you specify a property, it will feed in random data to your function and verify the property holds for all the random data that I would try if it finds a counter example will minimize that counter example. So doll property tests, they don't work on random data, they actually prove that the property is true for all possible inputs. And it's a proof. It's not like you know it's not guessing. So here you can read this as saying, for all natural numbers and I want to assert that zero is less than or equal to n, or in the end is less than or equal to and, and the compiler will actually approve this symbolically. So, even though it doesn't know what n is and knows that this assertion here is true. And again this is an emergent property of the language we actually didn't build in support for this is actually just sort of like the way that it falls out of the language design. The reason this works is because the interpreter can normalize abstract expressions, which we're about to get into later. Okay, so, but the language has several limitations. And so let's let's get into those limitations. So, doll has a very restricted set of primitive operations which we call built in, and there's a, and you can find the full list of the built in types functions and operators online. And the things that are most likely to surprise new users are, first off, there's no support for doing any sort of introspection on text. For example, you can't check what is the length of a text string, you cannot compare two text values for quality. You can't split it into substrings, you can't parse it, you can't match it against the rejects my text values. As far as the language is concerned, they're totally opaque, you can concatenate them, you can interpolate into them. And that's basically all you can do. Another thing that will surprise people, there's no support for double arithmetic. Actually, we might add support for like, you know, additional multiplication, but at the moment there's no support whatsoever. They're basically opaque values. Another surprising thing is that you also can do runtime equality and inequality tests, but it only works on bulls doesn't work on text. You actually can, you know, compare natural numbers for quality but not using the operators, you can only do so using named functions from the standard library. And if you want to learn more about why doll makes these weird decisions. There's a page which explains many of these design choices. The short summary is that doll tries to discourage weekly typed programming idioms. The language tries to make it so that the path of least resistance for a new user is to push all the validation logic ahead of time into the type system type checking time. For example, that's one of the reasons why tests run at type checking time and not at runtime. For example, you actually can compare two text values for equality at type checking time using a test, but you can't do it at runtime. So, so everything, everything about the language is trying to push you into doing ahead of time validation so that you don't have runtime failures. So doll is not just a functional programming language, it is a total functional programming language. I'm pro I don't want to like misrepresent the definition of total but like practically what that means for doll is that adult file or expression will never hang crash or throw exceptions. And but that's a good that's a nice thing in and of its own right, but one of the downstream benefits of that is what's called strong normalization. You can always take an expression. You just keep evaluating it until it gets stuck and there's nothing more left to evaluate, and we call this a canonical normal form. And these canonical normal forms are basically just they're free of indirection so all the there's no interaction left in these normal forms basically. So here's an example how that makes it easier for humans to comprehend doll code. So now I didn't actually talk about what the generate function did before so I'll give a little bit more description right here. So, whenever you import something in the doll rebel, they'll give you a type, and I will walk you through this type. So generate is a function that takes three inputs. The first input named and is a natural number, and this is how many elements of the list that we want to generate. The second element named sorry the second function input named a is a type. The third function input named f is a function from the list index, which is a natural number to an a. And then this function will then generate a list of that many values using the f function. And so, let's say you don't trust my explanation of how the generate function works, you can actually ask the interpreter. Okay, I'm just going to provide you one function input even though you can take up to three. So call generate on the number 10. So, so generate 10 elements I haven't yet told you what type I want. I haven't told you what the function f is, but it can still actually evaluate that it can evaluate things abstractly, or it's you can this is sometimes called evaluating under lambda. And so this is so they're up so the interpreter smart enough to realize. Okay, so now this is a function of two arguments, we still don't know what a is we still don't know what f is. We know that you're going to get a list of 10 values, and the 10 values are going to be f applied to zero f applied to one dot dot dot applied to nine. So this isn't a way to get an intuitive feel for what the generate function does at the term level, instead of at the type level. And. Okay, so another restriction of doll is that doll does not provide language support for recursion. This does not mean that recursion is impossible within the language. It's just not ergonomic. So basically there's a way there's a way to model recursion in doll. And there's a page explaining how to do it. Here's an example, an ugly example in my opinion of like how you would model, you know the Jason type in doll. But basically, it's something that you don't need to be an expert to use, but you do need to be an expert. If you want to author a doll package that uses a recursive type like that's kind of an experts only type of thing. So touch on before dolls type inference is limited. And the main places where you're going to stumble upon this are an empty list requires an explosive type annotation and empty optional value requires you to specify the type of the value if it were present. The function input type requires the type of notation. Actually, this is the one case where I feel that people don't mind that because a lot of programming languages work this way, you know, like go or Java or Scala, or I don't know, C sharp I think a lot of them they require these explicit type annotations on function input so this one is not quite so bad. But the other ones are bad in my opinion. Here's another place where we need like whenever you specialize a polymorphic function like map, you have to provide the explicit specialized types. And this one is particularly bad, because in this example, like the type right here is always going to be the same type as this type right here, they have to match. Right. And if we had a language with the proper bi directional type inference, we can actually omit both of them. Right, but it's kind of it's kind of weird having to like specify the same type two times when you know they're always going to be the same. Okay, so that covers the programming language features in the next section I'm going to be talking about the language security stuff specifically you people have any questions so far. Thank you. Jason specification. Yeah. That's describing all of you. Yeah. Yeah. Anyway, yeah. Yeah. So I have a question that that's sort of, I don't know, more meta here. So, you were just saying on on that last slide about like, yeah. Most of these you define as bad. Yeah. And except for the third one, you're like, yeah, that's okay, but, but the others classify as bad, but, but you invented this language so why would you implement something that you consider bad. So remember, this goes back to the origin of the language, it was supposed to just be an academic exercise or a thought experiment. And then all of a sudden people just started using it a lot. And I was like, Oh, shit, I got to like start supporting people production now. So that's why I didn't design in bi directional type inference so we've been trying to, you know, evolve the language incrementally over time to like work around the limitations of the original draft of the language. Yeah, that's the reason why basically. That seems fair. Yeah. I have some questions. So, first of all, I work with Terraform, and I really appreciate what you're doing here because it's, I don't know the rest of the people here understand how bad it can get. So, just having a collection of things is really difficult and terrible. And then if you're just too insensitive, and it's bad both times. It is very bad. I just want to put the best of the programmers writing this stuff. And we know there's a better way. That might be the thing. Maybe that server admin, they're just so happy that they have a way. Yeah, this actually goes back to like using doll in anger. Right. So like, people will put up with something limitations like these, if there is a very compelling reason for for using it. In my experience, the people who tend to adopt doll, like I think the most common people say is like dolls like one of the only sane ways to handle large configure sorry large Kubernetes configuration files. And again, I think the doll secret sauce is that it threads the needle between like providing programming language features, you know, like packages imports functions types, but still being safe, right safe, maintainable, and so on like that's something that like really no other configuration has like struck that balance in my opinion. Any other questions before we go on. I want to actually know just where how people are using doll in general. But anyway, we can talk about that. Yeah, there's like a doll, a commercial users of doll web page. It's all in production. So this is like some companies that are using doll in production they've endorsed in the other advertising. And there's also like a large set of doll packages to like if you want to get like I think out of all configuration formats doll has the most open the largest open source ecosystem around like the most packages and bindings. So like if you just go to the main page and click packages, you see bindings for things like you know Ansible Rgo CD cloud formation concourse Docker get lab chaos. And there's some other ones too but like these are like the best maintained and the most notable ones. Like I think there's also a Terraform one which is in Fargo which is getting pretty close to completion to, for example. Yeah, so we do a survey every once in a while where we ask people like, what is the binding that you want the most and Terraform regularly tops the charts of the one that people really want badly. Yeah, we use Terraform and all that works that we get it. So, okay, so, go ahead. Is it just a URL, or does it also allow for So the imports can be you can add query parameters you can also add custom headers to like you need to make an authenticated request, for example. Like, I'll just do like a really quick example this here. I'm not going to run this example but just to show you what that would look like it would be like com using to map, I don't know authentication equals I don't know access, and let's say, and GitHub token as texts, like as an example like that would be the fully baked example of making an HTTP request using a credential taken. I maybe I forget the exact syntax here but though that was that would be example how you can make secure a an HTTP import. So I have a really dumb question. Is it named after local. No is named after a an MPC from the role playing game planescape torment, which is my favorite computer game of all time. Yeah, yeah, I highly recommend it for anybody who hasn't played it. Okay, I'm sorry. Sorry, I was, I was angry to combat that game. Okay. Okay, so I'll get into language security. So, like I mentioned before, doll is best in class when it comes to language security we pay a lot of attention to this and the best way to summarize it is that is this quote from the main page, which says the language seems to support safely importing and evaluating untrusted doll code, even doll code authored by malicious users, and we treat the inability to do so as a specification but so we're always working on locking on the language is big dollars almost like the perfect sandbox of for language. And this is kind of like the original reason for doll like it goes back down to that original programming discussion, which is that we want to balance programming features with safety, right we want to get the best of both worlds we want to have our cake and eat it to. So that's why we take language security so seriously. Most people when they talk about, you know, in these online debates are like I don't want my configuration files to be turned complete. And like if you're going to be like really pedantic about it, being turned complete is actually like not that big of a deal as far as language security goes like it's nice to not be turned complete right I think that's a good, I think it's like good hygiene for programming language. And I think one of the reasons why people latch on to terrain completeness as is like as a proxy for some other features because like if you have a language which is not turned complete. That's that's actually hard to do right you know, there's like a website online which is called like accidentally turned complete like all these various you know languages or DSLs that are accidentally turned complete. So it's so easy to accidentally design a programming language that is turned complete. And you actually have to spend some time designing a language to not be turned complete. And so just saying, I made a language is not turning complete means that I actually took some time to do things a little bit correctly. So for example, it probably means your language has some sort of a type system or at least some form of static analysis to prevent terrain completeness. It also means that you eliminated various escape patches are back doors. And it also means that you probably forbid general recursion, and this is more of a programming language theory things like people who are programming language theory snobs like me they don't like general recursion so I don't know a lot of people put a lot of stock in that but I do. So when people say that they don't want turning complete config files what they really mean is they don't want configuration, a programmable configuration file that permits arbitrary side effects. They want configuration files to be easier to statically analyze, and they don't want configuration files to throw exceptions or panic or crash that's what they actually. And all gets those right to, but you don't have to get rid of turn completeness to get those right like you can have all those things and still be turning complete. That's a possibility. It's just that people use turn completeness as like a shorthand syntax a shorthand for these features that they actually want. So the actual thing that makes doll really safe is its purity. And this is the most important safeguard against malicious code. So the only permitted side effect and doll is importing other doll code. So you like a doll program cannot, you know, delete your files or you know make a database connection. Or anything like that right it's just pure computation. And the import system, even though it can make HP requests, it goes to great lengths to make sure that you cannot use it to harvest or leak secrets keys or passwords so you can't have these data exfiltration attacks. So for example, you can't like stuff program data into the HP header right you this is something you can do it statically you can but you can make static data into HP headers but not dynamic data. You can also completely disable the import system if you're very paranoid or you can disable just the remote imports, if you feel like that's the right boundary to strike. Okay, you can also pre resolve doll files like you can say take a doll file which has imports, and then within a safe environment that may be like CI instead of production you can do the import resolution. You can inline everything basically you can pre resolve the file, and then in production you can just turn off the imports and just do the pure computation after that. So other than that, other than the import system the language is totally pure. So like the firewall example that one of you mentioned earlier, the only other effect the doll program can have is via the program being configured so that is the only actual way you can inject bad behavior is via the actual data. Actually, I'm getting what you're saying. You're not going to dollars and going to allow people to do a solo thing. Whatever. Anyway, there's still lots of it's still out there but at least you've got a lot of stuff. There's more. This is not the only safeguards. Let's keep going. Okay, the second safeguard is static analysis. Okay, so the type system has no escape patch. So even like in a really safe language like rust, even rust has the unsafe keyword which will let you, you know, turn off the borrower checker, or whatever. In dull there is no turn off the type systems which there is no escape hatching on. The other thing is that in addition to having type level, you know, annotations, there's a concept of integrity checks in dull so when you import something you can add an integrity check, which is basically a hash of the canonical normal form of that expression. So if you if you add an integrity check to an import and the import changes or someone perturbs it anyway, then the import will fail. So the integrity checks to you know packages that you distribute via typical software distributions you have the same feature in dull. I'm not going to cover in this presentation but there's a longer blog post which explains how these work and also adult tutorials all talk about this too. Also it's really important like if you're freezing a file is not enough to just say you know I don't want this import to change right that like you need to be able to audit the import. I'm going to verify this is good behavior before you want to say I want to freeze this good behavior for all time. So it's not just important for the computer to be able to understand all code it's important for humans to be able to understand all code. And this is where strong normalization comes into play. So because we always have the ability to remove in direction we can have our cake and eat it too. And a lot of people when they think about the tension between, you know, programmable configuration languages and inert data they think about as a spectrum, like on one end, you have things that are easier to write, but harder to understand or comprehend. Like that will be your, you know, your fully programmable stuff. And on the other end of the spectrum you have things that are easier to read, like plain data like Jason or YAML but hard to author because you have a lot of repetition and they're hard to maintain and so on. So if you get stronger normalization you can get the best of both worlds, you can write use programming language features, and then you can remove all the interaction to get the plain data, before you even run it, so that you can better understand what's going on. And we have a lot of protections which are very specific to those you are imports. So we already talked about integrity checks so these can help protect against man and middle attacks. We have caching, which can improve, which can help mitigate usage tracking of imports. And we also have what's called a referential sanity check which would basically protects against cross site scripting. And we also have a same origin policy which protects against data exfiltration, and we also have cores which can protect against server side request forging. So we've thought about like a lot of vectors and there may still be some but like if you open a bug report saying like I think here's a vector that people can use to come to to as like an attack vector for doll like we will take that very seriously and work to evolve the language attack vector. Okay, so to conclude doll is a programmable configuration language with a strong emphasis on language security, and you can use Jason or YAML as an intermediate to support into to introduce doll incrementally within your own organization. If you'd like to learn more, you can visit doll-ling.org. And this is an abridged version of a longer version of this talk that I sometimes give so you can find the slides for the longer version of this talk online here at my slides repository and it's called the doll intro. Yeah, so that's the end of my talk. It's all open in the floor for you to ask any more remaining questions. You are all imports defaulted to like a lot. Yes. It's all back and then pass them to turn back. It's an event that a developer not doing something to prevent the security failure, which, yes, you can walk. And it prevents accidentally doing something you don't understand. You're saying, Oh, where's this feature? Oh, I have to go turn it on. And then there's a giant warning that says here's the security failures that your auditor will ask you about. This is interesting. I mean, I remember the stories were told back in the day that I never had to see it. So I don't know. I don't know if the story is true, but it seems like, yeah, that was a bad idea. Anyway, so this is better. Yeah, this is this is, and I'm, yeah, very angry at terrible. Well, if statements of their performance are very different. Okay, so I'm going to ask, like, a question because everyone else here, like, actually is a real programmer and works in industry and I'm an academic and I do tiny stuff. And so one of the questions I've always had, and this is really for everyone and it already sounds like, yes, yes. I don't understand how configuration files are that complicated. Would you like to understand? It's a very, I asked because I could give you the full answer. Okay, so one of the examples was given like, if you have to generate like 100 reasons. I can do that. I can write a script because that next to that. That's not a problem. But all of you are like, yeah, this solves a lot of problems. Imagine you have to write a configuration that sets up the computer that the thing is going to run on as well as setting up the computer. So, I'll explain the one I do for today. So, it creates a virtual, but on the app, sort of on Azure. He creates a database. Now, the computer agent, fortunately, doesn't create all the data in the file, but it calls the thing that does that, right? It says, the application is, I think, I think the one that I'm working with right now, on a regular basis, has about somewhere between 150 and 300J something. It's a lot of regenerating. I mean, it actually does a change very often. But Lord, what he changes. Like, the one I bring up is just the local. It's setting up, setting up database, grab an MQ server, it's setting up all the builds. We're rolling the database out like from scratch to usable. There's several other services. S3 is basically a final system. It's setting up. Oh, yeah, I got that. This is why I wonder about the one of any file that you're talking about. It's super useful. Actually, no, this would be an interesting idea. So you have the doll to Jason cool. Why couldn't you have the universal format? It's a way to generate an arbitrary data directory structure. You can. You can do that, actually. So there is a doll to directory tree sub command where basically you give it like a doll. So basically, it'll basically take it like a record of records and like it'll treat records as directories and text value fields as files. So you can actually generate a directory tree, including nesting from a single doll expression. Yeah, and said something that this the services that that are used to manage. Logins, like credentials. Awesome. Oh, we did in addition to all the details on the yellow. That's just a little one. We have. We have any good server about 10 miles. I have learned that everything. Don't worry. I don't understand the complexity. You have a person divide where building this thing and architect again. And then you have a divide between the teams. Sometimes force to legally with the people writing the configuration at the point. And so crossing the divide creates all of these. We're all one team. Yeah, we have infrastructure team, but we rotate on to the infrastructure team. Oh, my car. This is me. It is just me. I do it all. You just have too much to write. Yeah, it's the same thing. No, it's almost a huge problem. I mean, it really does. It's, it's a better solution than most. What I'm doing. I'm using a DSL that's designed specifically to do that. Which is pretty obvious. But it's code. It's not a configuration. It's not safe. Some of these, some of these scripts, they basically can set up a business. Like we had an entire business. Don't tear it down. On accident. I actually created a whole environment. Well, is that an arm sensor? This is why I love Terraform. Because it says, oh, by the way, you're about to make 60 new things. I meant to change that bullet from true to false. And now it wants to add a secret thing. Sorry, we're all over here just telling war stories. Yeah. Feel free to jump in. I have one example of my own. Like when I was at a, I worked at Twitter, they use a build tool called pants, which is kind of like their version of basil for like, you know, like they're like the original version of basil. Like you know, they're like, you know, like they were building within a monoripo. And so each project you'd have, like, you know, some's built a project also individual files. You'd have, you know, build recipes. And there was this plague of people just like copying and pasting these build recipes. Like very thoughtlessly. And so whenever we needed to make changes to these copy and pasted was to like, like they would be copying us to like really low level details. Like, you know, they should have like, you know, this much memory or disk or whatever. And we don't know, like, if you actually want exactly this much disk or were you just copying what this other person did and you want to stay in sync with them? Like that information was totally lost once people did all this copy and paste programming. Whereas if you have like a function to specify that intent that you can make changes to the function and then that is, that will occur per basically. Like let's actually use an example like from right here, right? So here we had like not only does having a function make it easier to roll out new users but it also makes it easier to roll out new changes to all users too. So like if I want to change all users to use an RSA private key, I can just replace this with RSA and now boom, everybody switched over because the intention was that all the users should be using the same key type was preserved in the code. It's not nearly as much fun if you get rid of every which would be different. Yeah, it's always better to do it the hard way. It's always better to do it the hard way. It's like a lot more boring. Yeah, it's a lot more boring. Yeah, it's a lot more boring. Mike put, so, yeah, how to do this. Human components. Well, no worries, I'm sure they, they might add a quick comment to express their intent. John, how security is for the guy in sales? So this is a dumb question too, but have you had any user requests or someone tell you that they're using Dawn and it's like, that's the horrible. I want to know this. It's the risk. It is basically reported. I just want to hear some funny story. This already sold me. And the security by the way, I am sold it is. Anyway, I'm sold. Yeah, so weirdest, I think the weirdest use case I heard was like somebody was using doll to maintain their latex bibliography. So there was some like, some. Well, I live in latex. No, no, I'm so interested in this idea. I know what you're saying, say more. Yeah, yeah, everyone looked at me. I'm fascinated with my desk. So they asked for some features and we implemented some of them and other ones we had to turn down. I think some other. So like, I don't know what they're doing. I have to. Okay, okay, okay. Here, here, I mean, like I'm good at bug reports and like, yeah. Okay, okay. Here, I'll get you started on that. So if we go to the dolling repository, there's a specific user. So all of these are associated with one user. If I find their name, I will then. No, this is not it. Hold on, let me, maybe it was in the hassle. So sometime back before there was a language standard. People would open up issues against the original Haskell implementation. So it might be here. So let me just check that quick. No, no, no, I could have sworn. Well, there's one more thing I can check. I can find it, that's okay. I'll look it up. Yeah. I know we, there was some, but I just can't remember what their names were, but anyway, so yeah, if, if you just like email me, I can help me find it afterwards. Flex it in. My bib tech file is a pain in the ass. So I was like, yeah, I could interpolate this. Yeah. So another, some other use cases, which are I think less weird, but they're interesting. I would say these are not mainstream use cases, but it would be using doll kind of like a, an API for code. It's like, you know, most APIs, like that, let that are programmable or queryable. Like the set of things that you can change about the API's behavior is kind of restricted. Like you can add like, you know, query parameters or aggregations or things like that, but like you can't just like send arbitrary code over like some JSON endpoint, right? And the main reason why is because normally you don't want your users sending you arbitrary code for you to execute, right? It's kind of like the same way you felt when I told you, oh, hey, you can import arbitrary code from a URL and run it. Like you kind of feel the same way with an API, right? Once you tell people like, we can kind of make this safe, then they're like, oh, well, maybe I can, you know, just have my API just like accept a function. Like you just give me a function to filter these rows and I'll run it. And if you specify it in doll, then maybe I can just safely interpret that function server side. I still think doll is like not really ready for that use case yet, not because of language security reasons, but just more, it would require like, maybe more language design changes or tooling or things like that. Maybe you've got better ecosystem around it, but that's one issue. Oh, well, one use case that sometimes comes up. Another, I guess, niche use case is sometimes like using it for like contracts or contract languages. Like, you know, again, I don't think doll is really well suited for that use case, but we've had some inquiries along those lines. And I don't think doll is anywhere ready to be used for that kind of thing. Why not? I'm totally seeing that on the internet. Well, the reason why is because dolls built-in functions are incredibly impoverished, basically. So that's, and the second reason is because even though doll is like not turned complete, so it does technically finish evaluation in like a certain amount of time, like it can like, you know, I mean, it could take longer than the heat death of the universe. Like, so there's an example I sometimes give is like, you know, we have a GitHub file containing like the Ackerman function for doll. And so I can write a doll expression that takes basically forever. Like, we'll all be dead long. It'll be, it'll be killed still running long after we're all dead. So it technically finishes in a finite amount of time, but like it's not practical. And so like a language that was really designed for like, you know, to be a contract language or like to run on a blockchain or whatever without like a, like harder boundaries on execution time or a concept of gas or whatever it is they do to limit resource utilization. And I don't want to add those features to doll, basically. Is anybody use it for sort of general text across something Jordan said? Again, that would also require a larger suite of built-in. So what you could do, and some people do this, is that like, so it's not just available from the command line. So like there's like the Haskell and several other applications, several other APIs, they let you customize a set of built-in. So if you just want to create something just for your company that has like a much greater extended set of built-ins, you can do that. And so you want, if you want to add like text equality or I don't know, whatever it is, or maybe you can just like add like things that are specific to your company's proprietary API, you can do that. It might not be very ergonomic compared to like a, you know, purpose built DSL, but it would work. But again, I don't think dolls really built for that use case. Like I think because the set of out of the box function, like an example where that would kind of fall down is, you know, we don't provide the language server so you can get IDE support. But then you would need, like if you wanted to add custom built-in, then you would need to rebuild the language server to use those custom built-ins using, you know, the Haskell API. And that'd be kind of a pain to do. And we don't really support easy way of doing that. So. This is another dumb question. Has anyone tried to do a like static site generator? Like has anyone tried to generate? Yes. Yes they have. So at least one user has asked for features specific to using doll as kind of a static site generator. Yes. It was inevitable. Yeah. So when you're importing URLs, you're importing doll code or you're importing arbitrary HTML and then you're able to process it. No, it has to be raw text that is doll source code. So it can't be HTML. Okay. I mean, you could do something like you could use the, so one change we've been considering and just nobody's gotten around to it is we could have the interpreter use, specify a content type. So like we already know what the content type would be, like what we would standardize if we did this. So then you can have like an endpoint if you specify the doll content type it'll serve the raw source code. And then you specify HTML it might render it a bit better basically or maybe provide documentation or something. Like for example, we actually do have like a store.dolling.org which hosts the documentation for various doll packages. So like Kubernetes right here. So you can like go to various resources and see whatever. So yeah, like that was actually the part of the talk I had to cut for time reasons. Like doll has a lot of really cool tooling around it like repels and language servers and host the documentation and things like that. And so I was able to cover that. But if you go to the link to the longer form version of the slides I will go over that in more detail. I was just thinking about my BIPPEC file and automatically updating things that were like pre-release versus have been published and if I could do that in some way because that I've been running into that just the past couple of weeks. We'll work on that when we're done. We'll solve it tonight. I think we'll be able to leave. We have pizza. I mean, you can do it. We have pizza. We have pizza. We have pizza. We have one laptop. We have pizza. I know Lex as well. I know too far. There we go. There we go. We're ready. All right. I'm ready. We all talk. Yeah. I also have to head out soon because we're about to have dinner over here. Well, I want to thank you then and release you from our idiotic cramp links. But this was, for me this is super, super interesting and seemed like that for everyone else here. So yeah. I didn't think it was gonna be a tricky at all. I thought it was fascinating. Whoa! I really didn't know. I'm like, my English is seriously like, yeah. But this is, wow. I'm impressed. So is the answer. Yeah. So is the answer. Yeah. But I've seen all the awful ones. Yeah. So I keep going back to that. We can do all that the next week though. So everyone just went, wait, let's see. Everyone just defaults to, well, text templates. And it's like, oh, we'll just do some text templates and make it work. And this is an actual solution for real problems. Beyond just text. Yeah. That's high praise from this bunch of assholes. Thank you. So thank you so much. This was really great. Yeah. You're very welcome. It was my pleasure too. So I'll be in touch. We've got the recording. We'll probably have to edit some of it. We'll share it. But yeah, we will be able to share that. So thank you so much. Any last words from my side? You will not. You're going to start here and be like, Just have like a soundtrack. Just play some, like a little boring stuff. All right, thank you so much. Yeah, you're welcome. We're not going to hang out and talk about this for and how to use what you've created. All right, then. I'll chat with you guys later then. Thank you. Is it just us? It's just us, yeah. You're welcome to be Robert. It's just you. We're not there. He's not there. Even though it's a while ago and just now this has to go off the recording. You have to like stop on the recording. All right. We're about to get ready. OK, we are going to turn off the recording now. So what are you doing? Self-cloud recording? Yes.