Reading the Nix expressions language
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Zimbatm, Grahamc
Nix is not a big language but the syntax is quite foreign to the usual language suspects. The goal of this talk is to demystify the language. At the end all the viewers should are able to read Nix code and start wielding Nix's super powers.
 I didn't really advertise this track heavily, so I'm surprised that there's so many people and I'm also delighted. Maybe we should start with just a quick... So this is more of an interactive session. The goal is for you to learn how to use X and kind of go over all of the aspects because it can be a bit difficult, right? So maybe we can start with a quick round of... Maybe who knows how to read the next code? Maybe raise your hand. Okay, so half of the room. Who knows how to create a new package in the next packages? Yeah, let's test. So, yeah, today we're going to cover these things like how to... So the first doc is how to read next code, so it doesn't look the weirdest anymore. And then we're going to cover how Nix works in the internals, how to build your own packages. And you should... If there's something that's unclear, you should interrupt us, and then we can just go over it right. Okay, let's get started. So, reading the next expression language. So Nix is an ecosystem, and that's just a small part of it, which is the language Nix, and then we're going to see other parts of the ecosystem. So a long time ago, like three years, which is 30 years in a completely different time, I was starting Nix and I was seeing things like this, right? Or like this, and like this. And just what I did is I banged my head against and I tried until it works. And so the goal of this doc is that you don't have to do this, and maybe after the end of this doc you will be able to just read the code, and it makes sense. Okay, so what is the next language? Next language is basically you have JSON-like values. So it translates actually quite well to JSON data types. So for example, the string is the same representation, number is the same. The list is already a bit different because we don't have commands between items. And to create an object like you have key equal value, and then you need a semicolon to end the expression. Now it is null and true-forces true-forces. So that's the JSON things. And if we put them together, it looks a bit like this. Okay, so strings have more constructions or a deterred representation. You can also have multiline strings. And so one of the things that you need to know about the multiline strings is, Nix is going to remove this part of the string for you. So you can actually align your literature and your codes. And if you have indents and Nix is going to do the right thing and remove everything that's in front. If you push this a bit further, then it's not going to remove this. It's just going to remove the smallest part of the white spaces. And then finally we have an event-like representation. So you can just type your S. But this part is going to be thinking of duplicating it, by I'm just mentioning it here, complacency. Okay, so that strings. There is another type that's called the path. That's not in the JSON data types. And that allows you to reference files directly. So there's multiple notifications. There's one that's just you type a relative path. And that's going to be reserved to an absolute path relative to the file where it's being loaded. So it's easy to think about it. Then you can use absolute paths. And it also completes with tids based on your home directory. And then the last one, which you probably are going to only see with Nix packages, is this where the bracket addition. This is actually a look into the Nix path environment rival. So I mean I'm just mentioning it's for now. You just need to know that this is going to reserve to a path. And if you want to know how, like what path is going to be, you have to look at the Nix path environment rival. And then there's a key equal value. So you can see Nix packages are on the right here. So I have my own Nix packages checkouts. So I just want it to my get report. All right. So now we have only values for now. So now we introduce functions. So Nix functions are just methods. So here, for example, you have one function. Each function has one argument. And it returns another function with one argument. And then that's the body of the function. So here we bind the value to A, we bind the value to B. And in terms of scoping, this creates a new scope. The scope is only below the function. So you don't produce, you can never go, like you can do like JavaScript where you declare a Bible. And then that's going to go below the right. And then there's another representation which is a keyword argument. So again, that's one function with one argument. But this is going to be a bit like pattern matched or you pass an attribute set like an object. And it's going to extract the keys from the object and bind them into your scope. So that's two ways of writing it. The most popular one is this one. And we're going to see more examples after. So here that's the simple way. But then if you pass, for example, an object that has A, B, and C, here it's going to fail the evaluation because it's going to complain that C is not the third in here. So this, another, you can do more things with this. For example, you can specify default values. You can say, I don't care about any extra arguments. So that's going to be a guard. And you can also bind the original attributes that's been passed to the function to an A or B variable. Okay, so now we have, so now we can build just values, a bit of functions. And now we start looking into some of the bit and functions. So these are functions provided by the interpreter and there are kind of existing functions in the environment. So you have two string boards. About two string, the next, there's no conversion, automatic conversion. You have to specify if you want to convert from one type to another, except in one day. I won't talk about it. You can import a file. So what you can do is you can say import another next file and it's going to be evaluated. And then with the value from this evaluation is returns to your current scope. You can do exceptions to this, you know, like functional type things like map and fold and functions like that. So these are all top level. And then we have another attributes, which is scriptings. And then in value find more functions. So there's a trace that I do you to just print out things for debugging. That's kind of from it. From JSON to JSON. And there's many more, but I'm not going to occur with them right now. Okay. And keywords. There's a few keywords on top of that and then we're going to finish with the membership. So the let's binding allows you to bind the values to names. And so here we actually create a new scope where we bind hello and packages into the scope. And then they're available below. So you can access that. One thing to note here. You might notice the we access packages here because the names are bound at the same time. So you can do things like you don't care about the ordering of the let's finding basically. And because next is a lazy language, you if you never access one of these values, they're never been a big. Rec is a bit of the same. So if you have an attribute set and you add the record, what it's going to do is the same. Like it's going to bind all of these keys as a variable. So sometimes you see a record and you're wondering why that is. It's just because it finds the values into the scope. And it's available so below like here you can see the version. With is another keyword that imports all of the values of the attribute that you pass into the scope. This one is a bit dangerous like in most languages where you have this keyword like here we do with packages and then magically it's not very explicit. Like you have these variables that are there. Excuse me. What is the difference between with and import? Okay. Good question. I need to start the next. So imports allows you to do things like here you get that's the value of the file and then you can bind it to. That's the environment. Whereas the with keyword is going to be with and then here you say with a equal to 4 a. That's because you're a value. So you only take some part of the packages not all of them and bind them. Imports allows you to load a product from somewhere else. The with is just a way of importing the existing attributes into keys into your scope. Only some of them. All of them. All of them. Import like with is a different construct is import is to load a new file into your scope. And with is a way to deconstruct an attribute into different environments. Does that make sense? Yeah. Thanks. So here, packages for example has been imported somewhere before and now we just create the scope and then these are viable. Not magically but they're kind of not. They're implicit. There's another tool keyword was in her and that is short hand to basically instead of writing GCC what it is the GCC can say in her from packages. And so it's just a way to reduce some repetition. And you can also use it that way when you inherit the value so you don't repeat like packages packages. So you make a typo it's like you the main advantages you avoid making typos. If the net is passive and assert this allows you to add another expression just before. So you have your code without assert and you can insert the search just here. So that's when you're debugging you want to make some assumption and verify them you add an assert and you say because the next error messages are not super clear always. So what you do is you sprinkle some asserts in your code and you like okay I think this should be a she could set it or something and then you get a better feedback. All right. Yeah, we're almost there. Now we have orders. There's a way of constructing objects that is shorter than it's Jason. So you don't need to you can create a deep hierarchy with just adding the dots in between. So we should do 5% slash device. For this value it actually brings actually I should show you directly. So now we have a that's so now I have a deep project with a that five systems. That's the device in here. Okay, there's another keyword that's or which allows you to test if this attribute exists. Then it's going to return this if it doesn't exist. Then you return this alternative value. And finally you have this test operator that allows you to test just returns a true force if the key exists in the. The few bullet approaches like classic string interpolation. So that's where conversion is done automatically on some cases where it comes to string. But not always. So here for example we access this we get the string and we build this string object from this value. There's a merge operator for each of its sets. It's a flat so it doesn't do a deep merge. Just good to know. Excuse me. It's like you have a out. I forgot to say so. In you when you read the next code in expectations for example you you see and that's confusing this. You see the dollar with this and then without the brackets right. So this one is on the next language level. So that is the interpolation. And then this is later on used in the builder phase in the bit phase which we're going to cover later. But this is just a bash viability. Yeah. And so they look the same but they're actually on use that different moments. Because in this you have the evolution that happens and you produce derivations and then you build the derivation. So you have a full life cycle. We're going to cover it. Yeah. Like number operators. So that's it for the language. So do I have a volunteer to read based on everything I said you should be able. Good. All right. So come over here. It's more than I did. So the first time is the definition of function right. Yes. We have two arguments. Standard deaf and then that URL. Then we have a body of function. Which says that we want to. I don't understand this part. I know that this is the definition of some data. But I don't see a sign. So what does mean. So this is an attribute sets. And we access this value. Yes. Which turns out it's a function. Oh OK. And then we pass this. All of this. The whole object is already record. We pass the record. OK. And in the record we have values and attributes and values. Also one attribute is generated by a function that was passed with the argument. And this takes also something. This is an attribute set. What is the difference between the rack and the attribute set. Great. So this attribute set is normal. This one has this right word that adds all of these keys to your scope. So this means that for example. The scope of the function. Which scope. So it gets a new scope that inherits from the barn scope. So here we have a new scope. Which contains it's then then F. Now when we enter here. We have a new scope that inherits from this. So it's still not as accessible as. First it adds all these values. And this one has no bar scope right. It doesn't incur. OK. So it has separate. We need a P name over here. We need the version over here. So it has a scope of the barn. It's always recursive to scope. Yeah recursive. It probably does like it wanted to mean. So this one only has a bar and this one has a parent and parent of the parent. Right. You can refer to the keys of that object itself. Right. You can even like you can refer to like name this game like other key. That's what it is. It's like that recursive. It's not a key word. Record box. It's recursive. Yeah I guess so. Yeah sure. Yeah it's recursive. I still doesn't understand. So this one is using keys from the parent. Yeah. And this one is also using keys from the parent. So what is the difference. So when you type right you create a new scope. And here we have no new scope. It's the same. It's always the scope is always inherited. But then you can extend the scope with new. I understand. I understand. So this one is sending those keys. They are using the scope of the where they are initialized. Every question may need to clarify. If I were to use your URL key within that attribute set I wouldn't be able unless I could try before the attribute set. You don't try. Yes. So what you're asking is if I need the URL maybe in another key in here within that attribute set then you would have to write the right. Okay. So that's what right does basically. Yes. Okay. Now on the set right it's recursive. Okay. Me too. Thank you. So this could still work if we wouldn't use the recursive back on the third line. No. If you remove this. Yeah. Then PNIM and version are not added to the scope. And then we wouldn't be able to use the. So it would never get it's here and then. Okay. But you can you can also so here we use it below but you can also use it over here. Okay. So the next slide is we assign the attribute out through then we have another attribute that is called meta and it says generating the another attribute set but with the with with leap attributes right. It's come from the leap. Yes. So we can hear inside we can use attribute from leap. Yeah. Okay. So this one has access to without having to use the namespace right because with namespace we would also access this right. If I use something here as the that the flip dot license it will work right. Yes. Okay. So with with we have the short hand notation. Yes. And then this generator is the whole thing for that. Yes. Thank you. Yeah. Thanks. So I have a question. What's the. So basically the body is what we call by the function. Oh yeah. Is the result of the function. Okay. So the third file is a function right. Okay. And if you import this you get a function. Okay. And if I call it with an attribute set with those two keys. Yeah. It will return another attribute set. Oh no. It will return the result of invoking just make derivation derivation function. Yes. Okay. That takes another attribute set. Yeah. Okay. Cool. That's how we do things. Yes. Should we do another one? Yeah. Yeah. Anyone else here for this one? It's shorter. Yeah. Okay. Nice. A brief sound. Is it? So this is a generator dot next. This is Nick's stuff. Not the next package manager. Yeah. Okay. You import config and packages and your hardware configuration X is another bit of Nix code that you're reporting into this file. So this is a function. Yeah. Yeah. Okay. So this is a configuration dot next. This is Nick's stuff. Not the next package manager. Yeah. I'm completely new to this. I'm just busking this. Okay. You just need to read the next one. Okay. You import config and packages and your hardware configuration X is another bit of Nix code that you're reporting into this. Okay. So yeah, basically you're, again, you're creating a new file with a function of the dot. Yeah. But this time we ignore extra parameters. Yeah. You can change the question. So the idea of ignoring those parameters is to make sure that whatever we pass as a attribute set will work as long as it has a config and packages. All right. And we don't care about the other one. Yeah. Okay. So and sometimes you want to be strict and be explicit about older arguments. Okay. Sometimes it's going to be more less. So yeah, we have this attribute set and then we assign to this key the function of the configuration. So yeah, so the contents of hardware configuration Nix becomes all the definitions in there become part of this. That's it. Yeah. All the. So now you're going to be going a bit too fast. Okay. Right now we're just reading the next one. Okay. So we're thinking about whether it's going to produce in terms of Nix values and Nix values. Okay. Yeah, the end result is going to be that you include this one. Yes. Is it? Because in specifying there, isn't it just a path? Yeah. So right now, exactly. So right now, all we do is we actually assign this array that contains a path. That's it. Like it's just a path for now. And we assign this, this attributes. Why not just using the input function from the file? Yes. Yes, you could. But that's more how Nix is configured. What we do under the hood is we're going to import it, but we'll get your. So we have functional config and package. Where do we use those? Attributes or variables or whatever. I don't actually, I could remove them actually. And how do you, so here we have like services. SSHP and input. How do we know where they exist on this code? Yeah, for now, we don't know. All we do is we built this big tree of config. So it's like attributes. Boobs that's new attributes that's it. We create the tree and we assign these values. That's it. And then in another talk, we're going to talk about how all of this gets together. All the things. Yeah. Thank you. I maybe it'll show. Because that one thing I found very confusing is how I don't really understand. I can still that how tables, tables works in Nix because like obviously that is like we use import, but it's not like the keyboard. So it's like the keyboard is doing the import, right? So how does it work? I'll kind of input this into the front. So you can have overwrite it, right? Yeah, well, yeah, but I don't think you can name it import, right? Or not? Or is it import? It's like sort of like thing, but this is the right way of the function kind of go. So the keywords are. So you have a bunch of different functions, which are basically by default you have a scope with all of these functions available. Then the keywords are more in the like the parsing section of the when you pass the next code that's going to use these. Yeah, so import is the word. Yeah, it's a function. It's a function. It's a function. It's an important function. It's important function. Okay, this import is still function, so I can define my own import in my scope will be like that import which I will break everything under. Can you go back to this sample? Yeah. So the important thing to see here is this is not import. Import is a function, but this is imports. Yeah, yeah. Oh, sorry. Yeah, so this imports, NICS doesn't know what imports means. And so we're not overloading anything in NICS. We're just making an attribute set with a list of. Yeah, but it reminds me of the word, right? So we're going to name it to import and then assign the array to import. It will still be function in our scope, right? It will be just an array. Yeah, I guess you can shadow. You can shadow. Yeah, shadowing. You can do shadowing of existing variables with new variables, but only below. Yeah, yeah, in scope. But I don't want to confuse you with the recursion because it records because sometimes you have like what? You have like same attribute and you're like what? Why is it different? Like shadowing. Yeah, I agree. The leds binding and the spec and the width cannot play similar roles. So that's more of when you start writing NICS, you're going when it's appropriate to use one. Yeah, when you're going by. Yeah. I think the main problem, I'm a procedural guy, so I'm a C-Pro guy. So I've got to get my head around functional way of thinking. Yeah. And that's the main kind of Everest mountain thing. So you get out of the functional curve or a straight forward, but you travel back. And it always makes more sense. Yeah, so yeah, you never muted anything, right? You only change when you do operations, you're only return new values from that. All right, so I guess so we code NICS is a functional language. It's lazy and it's pure. I just want to go over that quickly. So functional is this approach where you don't mutate anything like we're talking about. And you only have functions to do operations. Lazy is because NICS only does the operation when you access something. So you can have a whole tree of operations somewhere. If you don't touch it, it's not going to evaluate it. So it's not like a scripting language where in your heads when you read the NICS code, it's not like, it's not interactive where you do like, does this thing, then it does this thing, then it does this thing. It's only when you access the values that it's going to evaluate the whole thing. Which is a bit similar to my question. Maybe I can demonstrate more about this later. And then finally it's pure. From everything I showed, we are not writing anything to this. We're only reading things. So there's no side effects. For now, all you can do from what I explained is maybe put a bunch of values together and then produce a JSON of the NICS. Isn't working a file from a file system not like your operation? It is, but it's pure in the sense that you don't modify anything. As long as you only read, it's fine. You're like an observer. What happens if the file is not there? It's a throw an exception. You get errors, they just can happen. It's how you are, while in a shell script. So the nice thing is if it fails, it fails consistently. So when you compile the files. So that's the next talk is about. So right now, all we're doing is we're taking a bunch of values and putting them together. So that's the thing that are missing topics. The big missing topic is the derivation. Because that's where all the computation and the bits happen. We're going to talk about this next. So we have a pure scripting function, a pure and functional scripting image. Hopefully now when you see the next code, it's not just like, oh, what is this thing? You can actually follow through and then from that, maybe you can keep, like, it makes you more independent. Thanks. I wonder if it might be interesting to, on that configuration.nix, to sort of unpack it so it's building each, actually set individually. Like you're using unit compact nested syntax. What might be interesting to show the more verbose version? Okay. I guess I can show. So we have the configuration of next here. So what should we do? I'm just going to modify it for now and remove it. But it's not a function because we established that we don't need any of the arguments in the way. And now there's a to code mix and sentiate that allows you to actually read the next code. And you say dash dash eval. And that returns the values. But right now you can see it's lazy because it just returns the first step, but it didn't try to ever get all of the rest because we didn't access it. So we can say actually, please be straight. And now it returns the whole thing. So it's not really readable. So I'm just going to generate JSON instead. And a bit of thank you. And now we have the web structure. So on the left. So that's what we have on the left. And here, oh. So the path is not a recent value. So it's the point. There's no such problem, right? Yeah. No. Yeah, maybe it's. There's no such problem. There's an error there. So we have the file. Oh, you're right. So if I touch this. That's more than I get. So here we're starting to see a bit that does magic. Oh. What's that? So what it does is when it accesses a file, it imports it into the next store. And that's the value of the. And there's a hash here. We're going to cover that later. But if you change the configuration file, it changes the hash. This is for version 5. For version. For version. Yeah. Yeah. And another thing to notice is that the keys are ordered. And that's a property that we want to have because it's basically we want to be more repeatable. So we need to do things like ordering things. So you always get the same result. All right. It's something we can count on that the keys will be ordered on a. On a validation. He's our order. All the same. Right. I think that's enough for now. We'll take a small break and then I can go ahead.
 I didn't really advertise this track heavily, so I'm surprised that there's so many people  and I'm also delighted.  Maybe we should start with just a quick...  So this is more of an interactive session.  The goal is for you to learn how to use X and kind of go over all of the aspects  because it can be a bit difficult, right?  So maybe we can start with a quick round of...  Maybe who knows how to read the next code?  Maybe raise your hand.  Okay, so half of the room.  Who knows how to create a new package in the next packages?  Yeah, let's test.  So, yeah, today we're going to cover these things like how to...  So the first doc is how to read next code, so it doesn't look the weirdest anymore.  And then we're going to cover how Nix works in the internals, how to build your own packages.  And you should...  If there's something that's unclear, you should interrupt us,  and then we can just go over it right.  Okay, let's get started.  So, reading the next expression language.  So Nix is an ecosystem, and that's just a small part of it, which is the language Nix,  and then we're going to see other parts of the ecosystem.  So a long time ago, like three years, which is 30 years in a completely different time,  I was starting Nix and I was seeing things like this, right?  Or like this, and like this.  And just what I did is I banged my head against and I tried until it works.  And so the goal of this doc is that you don't have to do this,  and maybe after the end of this doc you will be able to just read the code, and it makes sense.  Okay, so what is the next language?  Next language is basically you have JSON-like values.  So it translates actually quite well to JSON data types.  So for example, the string is the same representation, number is the same.  The list is already a bit different because we don't have commands between items.  And to create an object like you have key equal value,  and then you need a semicolon to end the expression.  Now it is null and true-forces true-forces.  So that's the JSON things.  And if we put them together, it looks a bit like this.  Okay, so strings have more constructions or a deterred representation.  You can also have multiline strings.  And so one of the things that you need to know about the multiline strings is,  Nix is going to remove this part of the string for you.  So you can actually align your literature and your codes.  And if you have indents and Nix is going to do the right thing and remove everything that's in front.  If you push this a bit further, then it's not going to remove this.  It's just going to remove the smallest part of the white spaces.  And then finally we have an event-like representation.  So you can just type your S.  But this part is going to be thinking of duplicating it,  by I'm just mentioning it here, complacency.  Okay, so that strings.  There is another type that's called the path.  That's not in the JSON data types.  And that allows you to reference files directly.  So there's multiple notifications.  There's one that's just you type a relative path.  And that's going to be reserved to an absolute path relative to the file where it's being loaded.  So it's easy to think about it.  Then you can use absolute paths.  And it also completes with tids based on your home directory.  And then the last one, which you probably are going to only see with Nix packages,  is this where the bracket addition.  This is actually a look into the Nix path environment rival.  So I mean I'm just mentioning it's for now.  You just need to know that this is going to reserve to a path.  And if you want to know how, like what path is going to be,  you have to look at the Nix path environment rival.  And then there's a key equal value.  So you can see Nix packages are on the right here.  So I have my own Nix packages checkouts.  So I just want it to my get report.  All right.  So now we have only values for now.  So now we introduce functions.  So Nix functions are just methods.  So here, for example, you have one function.  Each function has one argument.  And it returns another function with one argument.  And then that's the body of the function.  So here we bind the value to A, we bind the value to B.  And in terms of scoping, this creates a new scope.  The scope is only below the function.  So you don't produce, you can never go, like you can do like JavaScript where you declare a Bible.  And then that's going to go below the right.  And then there's another representation which is a keyword argument.  So again, that's one function with one argument.  But this is going to be a bit like pattern matched or you pass an attribute set like an object.  And it's going to extract the keys from the object and bind them into your scope.  So that's two ways of writing it.  The most popular one is this one.  And we're going to see more examples after.  So here that's the simple way.  But then if you pass, for example, an object that has A, B, and C, here it's going to fail the evaluation  because it's going to complain that C is not the third in here.  So this, another, you can do more things with this.  For example, you can specify default values.  You can say, I don't care about any extra arguments.  So that's going to be a guard.  And you can also bind the original attributes that's been passed to the function to an A or B variable.  Okay, so now we have, so now we can build just values, a bit of functions.  And now we start looking into some of the bit and functions.  So these are functions provided by the interpreter and there are kind of existing functions in the environment.  So you have two string boards.  About two string, the next, there's no conversion, automatic conversion.  You have to specify if you want to convert from one type to another, except in one day.  I won't talk about it.  You can import a file.  So what you can do is you can say import another next file and it's going to be evaluated.  And then with the value from this evaluation is returns to your current scope.  You can do exceptions to this, you know, like functional type things like map and fold and functions like that.  So these are all top level.  And then we have another attributes, which is scriptings.  And then in value find more functions.  So there's a trace that I do you to just print out things for debugging.  That's kind of from it.  From JSON to JSON.  And there's many more, but I'm not going to occur with them right now.  Okay.  And keywords.  There's a few keywords on top of that and then we're going to finish with the membership.  So the let's binding allows you to bind the values to names.  And so here we actually create a new scope where we bind hello and packages into the scope.  And then they're available below.  So you can access that.  One thing to note here.  You might notice the we access packages here because the names are bound at the same time.  So you can do things like you don't care about the ordering of the let's finding basically.  And because next is a lazy language, you if you never access one of these values, they're never been a big.  Rec is a bit of the same.  So if you have an attribute set and you add the record, what it's going to do is the same.  Like it's going to bind all of these keys as a variable.  So sometimes you see a record and you're wondering why that is.  It's just because it finds the values into the scope.  And it's available so below like here you can see the version.  With is another keyword that imports all of the values of the attribute that you pass into the scope.  This one is a bit dangerous like in most languages where you have this keyword like here we do with packages and then magically it's not very explicit.  Like you have these variables that are there.  Excuse me.  What is the difference between with and import?  Okay.  Good question.  I need to start the next.  So imports allows you to do things like here you get that's the value of the file and then you can bind it to.  That's the environment.  Whereas the with keyword is going to be with and then here you say with a equal to 4 a.  That's because you're a value.  So you only take some part of the packages not all of them and bind them.  Imports allows you to load a product from somewhere else.  The with is just a way of importing the existing attributes into keys into your scope.  Only some of them.  All of them.  All of them.  Import like with is a different construct is import is to load a new file into your scope.  And with is a way to deconstruct an attribute into different environments.  Does that make sense?  Yeah.  Thanks.  So here, packages for example has been imported somewhere before and now we just create the scope and then these are viable.  Not magically but they're kind of not.  They're implicit.  There's another tool keyword was in her and that is short hand to basically instead of writing GCC what it is the GCC can say in her from packages.  And so it's just a way to reduce some repetition.  And you can also use it that way when you inherit the value so you don't repeat like packages packages.  So you make a typo it's like you the main advantages you avoid making typos.  If the net is passive and assert this allows you to add another expression just before.  So you have your code without assert and you can insert the search just here.  So that's when you're debugging you want to make some assumption and verify them you add an assert and you say because the next error messages are not super clear always.  So what you do is you sprinkle some asserts in your code and you like okay I think this should be a she could set it or something and then you get a better feedback.  All right.  Yeah, we're almost there.  Now we have orders.  There's a way of constructing objects that is shorter than it's Jason.  So you don't need to you can create a deep hierarchy with just adding the dots in between.  So we should do 5% slash device.  For this value it actually brings actually I should show you directly.  So now we have a that's so now I have a deep project with a that five systems.  That's the device in here.  Okay, there's another keyword that's or which allows you to test if this attribute exists.  Then it's going to return this if it doesn't exist.  Then you return this alternative value.  And finally you have this test operator that allows you to test just returns a true force if the key exists in the.  The few bullet approaches like classic string interpolation.  So that's where conversion is done automatically on some cases where it comes to string.  But not always.  So here for example we access this we get the string and we build this string object from this value.  There's a merge operator for each of its sets.  It's a flat so it doesn't do a deep merge.  Just good to know.  Excuse me.  It's like you have a out.  I forgot to say so.  In you when you read the next code in expectations for example you you see and that's confusing this.  You see the dollar with this and then without the brackets right.  So this one is on the next language level.  So that is the interpolation.  And then this is later on used in the builder phase in the bit phase which we're going to cover later.  But this is just a bash viability.  Yeah.  And so they look the same but they're actually on use that different moments.  Because in this you have the evolution that happens and you produce derivations and then you build the derivation.  So you have a full life cycle.  We're going to cover it.  Yeah.  Like number operators.  So that's it for the language.  So do I have a volunteer to read based on everything I said you should be able.  Good.  All right.  So come over here.  It's more than I did.  So the first time is the definition of function right.  Yes.  We have two arguments.  Standard deaf and then that URL.  Then we have a body of function.  Which says that we want to.  I don't understand this part.  I know that this is the definition of some data.  But I don't see a sign.  So what does mean.  So this is an attribute sets.  And we access this value.  Yes.  Which turns out it's a function.  Oh OK.  And then we pass this.  All of this.  The whole object is already record.  We pass the record.  OK.  And in the record we have values and attributes and values.  Also one attribute is generated by a function that was passed with the argument.  And this takes also something.  This is an attribute set.  What is the difference between the rack and the attribute set.  Great.  So this attribute set is normal.  This one has this right word that adds all of these keys to your scope.  So this means that for example.  The scope of the function.  Which scope.  So it gets a new scope that inherits from the barn scope.  So here we have a new scope.  Which contains it's then then F.  Now when we enter here.  We have a new scope that inherits from this.  So it's still not as accessible as.  First it adds all these values.  And this one has no bar scope right.  It doesn't incur.  OK.  So it has separate.  We need a P name over here.  We need the version over here.  So it has a scope of the barn.  It's always recursive to scope.  Yeah recursive.  It probably does like it wanted to mean.  So this one only has a bar and this one has a parent and parent of the parent.  Right.  You can refer to the keys of that object itself.  Right.  You can even like you can refer to like name this game like other key.  That's what it is.  It's like that recursive.  It's not a key word.  Record box.  It's recursive.  Yeah I guess so.  Yeah sure.  Yeah it's recursive.  I still doesn't understand.  So this one is using keys from the parent.  Yeah.  And this one is also using keys from the parent.  So what is the difference.  So when you type right you create a new scope.  And here we have no new scope.  It's the same.  It's always the scope is always inherited.  But then you can extend the scope with new.  I understand.  I understand.  So this one is sending those keys.  They are using the scope of the where they are initialized.  Every question may need to clarify.  If I were to use your URL key within that attribute set I wouldn't be able unless I could try  before the attribute set.  You don't try.  Yes.  So what you're asking is if I need the URL maybe in another key in here within that attribute  set then you would have to write the right.  Okay.  So that's what right does basically.  Yes.  Okay.  Now on the set right it's recursive.  Okay.  Me too.  Thank you.  So this could still work if we wouldn't use the recursive back on the third line.  No.  If you remove this.  Yeah.  Then PNIM and version are not added to the scope.  And then we wouldn't be able to use the.  So it would never get it's here and then.  Okay.  But you can you can also so here we use it below but you can also use it over here.  Okay.  So the next slide is we assign the attribute out through then we have another attribute  that is called meta and it says generating the another attribute set but with the with  with leap attributes right.  It's come from the leap.  Yes.  So we can hear inside we can use attribute from leap.  Yeah.  Okay.  So this one has access to without having to use the namespace right because with namespace  we would also access this right.  If I use something here as the that the flip dot license it will work right.  Yes.  Okay.  So with with we have the short hand notation.  Yes.  And then this generator is the whole thing for that.  Yes.  Thank you.  Yeah.  Thanks.  So I have a question.  What's the.  So basically the body is what we call by the function.  Oh yeah.  Is the result of the function.  Okay.  So the third file is a function right.  Okay.  And if you import this you get a function.  Okay.  And if I call it with an attribute set with those two keys.  Yeah.  It will return another attribute set.  Oh no.  It will return the result of invoking just make derivation derivation function.  Yes.  Okay.  That takes another attribute set.  Yeah.  Okay.  Cool.  That's how we do things.  Yes.  Should we do another one?  Yeah.  Yeah.  Anyone else here for this one?  It's shorter.  Yeah.  Okay.  Nice.  A brief sound.  Is it?  So this is a generator dot next.  This is Nick's stuff.  Not the next package manager.  Yeah.  Okay.  You import config and packages and your hardware configuration X is another bit of Nix code  that you're reporting into this file.  So this is a function.  Yeah.  Yeah.  Okay.  So this is a configuration dot next.  This is Nick's stuff.  Not the next package manager.  Yeah.  I'm completely new to this.  I'm just busking this.  Okay.  You just need to read the next one.  Okay.  You import config and packages and your hardware configuration X is another bit of Nix code that  you're reporting into this.  Okay.  So yeah, basically you're, again, you're creating a new file with a function of the dot.  Yeah.  But this time we ignore extra parameters.  Yeah.  You can change the question.  So the idea of ignoring those parameters is to make sure that whatever we pass as a  attribute set will work as long as it has a config and packages.  All right.  And we don't care about the other one.  Yeah.  Okay.  So and sometimes you want to be strict and be explicit about older arguments.  Okay.  Sometimes it's going to be more less.  So yeah, we have this attribute set and then we assign to this key the function of the  configuration.  So yeah, so the contents of hardware configuration Nix becomes all the definitions in there become  part of this.  That's it.  Yeah.  All the.  So now you're going to be going a bit too fast.  Okay.  Right now we're just reading the next one.  Okay.  So we're thinking about whether it's going to produce in terms of Nix values and Nix  values.  Okay.  Yeah, the end result is going to be that you include this one.  Yes.  Is it?  Because in specifying there, isn't it just a path?  Yeah.  So right now, exactly.  So right now, all we do is we actually assign this array that contains a path.  That's it.  Like it's just a path for now.  And we assign this, this attributes.  Why not just using the input function from the file?  Yes.  Yes, you could.  But that's more how Nix is configured.  What we do under the hood is we're going to import it, but we'll get your.  So we have functional config and package.  Where do we use those?  Attributes or variables or whatever.  I don't actually, I could remove them actually.  And how do you, so here we have like services.  SSHP and input.  How do we know where they exist on this code?  Yeah, for now, we don't know.  All we do is we built this big tree of config.  So it's like attributes.  Boobs that's new attributes that's it.  We create the tree and we assign these values.  That's it.  And then in another talk, we're going to talk about how all of this gets together.  All the things.  Yeah.  Thank you.  I maybe it'll show.  Because that one thing I found very confusing is how I don't really understand.  I can still that how tables, tables works in Nix because like obviously that is like we use import, but it's not like the keyboard.  So it's like the keyboard is doing the import, right?  So how does it work?  I'll kind of input this into the front.  So you can have overwrite it, right?  Yeah, well, yeah, but I don't think you can name it import, right?  Or not?  Or is it import?  It's like sort of like thing, but this is the right way of the function kind of go.  So the keywords are.  So you have a bunch of different functions, which are basically by default you have a scope with all of these functions available.  Then the keywords are more in the like the parsing section of the when you pass the next code that's going to use these.  Yeah, so import is the word.  Yeah, it's a function.  It's a function.  It's a function.  It's an important function.  It's important function.  Okay, this import is still function, so I can define my own import in my scope will be like that import which I will break everything under.  Can you go back to this sample?  Yeah.  So the important thing to see here is this is not import.  Import is a function, but this is imports.  Yeah, yeah.  Oh, sorry.  Yeah, so this imports, NICS doesn't know what imports means.  And so we're not overloading anything in NICS.  We're just making an attribute set with a list of.  Yeah, but it reminds me of the word, right?  So we're going to name it to import and then assign the array to import.  It will still be function in our scope, right?  It will be just an array.  Yeah, I guess you can shadow.  You can shadow.  Yeah, shadowing.  You can do shadowing of existing variables with new variables, but only below.  Yeah, yeah, in scope.  But I don't want to confuse you with the recursion because it records because sometimes you have like what?  You have like same attribute and you're like what?  Why is it different?  Like shadowing.  Yeah, I agree.  The leds binding and the spec and the width cannot play similar roles.  So that's more of when you start writing NICS, you're going when it's appropriate to use one.  Yeah, when you're going by.  Yeah.  I think the main problem, I'm a procedural guy, so I'm a C-Pro guy.  So I've got to get my head around functional way of thinking.  Yeah.  And that's the main kind of Everest mountain thing.  So you get out of the functional curve or a straight forward, but you travel back.  And it always makes more sense.  Yeah, so yeah, you never muted anything, right?  You only change when you do operations, you're only return new values from that.  All right, so I guess so we code NICS is a functional language.  It's lazy and it's pure.  I just want to go over that quickly.  So functional is this approach where you don't mutate anything like we're talking about.  And you only have functions to do operations.  Lazy is because NICS only does the operation when you access something.  So you can have a whole tree of operations somewhere.  If you don't touch it, it's not going to evaluate it.  So it's not like a scripting language where in your heads when you read the NICS code, it's not like,  it's not interactive where you do like, does this thing, then it does this thing, then it does this thing.  It's only when you access the values that it's going to evaluate the whole thing.  Which is a bit similar to my question.  Maybe I can demonstrate more about this later.  And then finally it's pure.  From everything I showed, we are not writing anything to this.  We're only reading things.  So there's no side effects.  For now, all you can do from what I explained is maybe put a bunch of values together  and then produce a JSON of the NICS.  Isn't working a file from a file system not like your operation?  It is, but it's pure in the sense that you don't modify anything.  As long as you only read, it's fine. You're like an observer.  What happens if the file is not there?  It's a throw an exception.  You get errors, they just can happen.  It's how you are, while in a shell script.  So the nice thing is if it fails, it fails consistently.  So when you compile the files.  So that's the next talk is about.  So right now, all we're doing is we're taking a bunch of values and putting them together.  So that's the thing that are missing topics.  The big missing topic is the derivation.  Because that's where all the computation and the bits happen.  We're going to talk about this next.  So we have a pure scripting function, a pure and functional scripting image.  Hopefully now when you see the next code, it's not just like,  oh, what is this thing?  You can actually follow through and then from that,  maybe you can keep, like, it makes you more independent.  Thanks.  I wonder if it might be interesting to, on that configuration.nix,  to sort of unpack it so it's building each,  actually set individually.  Like you're using unit compact nested syntax.  What might be interesting to show the more verbose version?  Okay.  I guess I can show.  So we have the configuration of next here.  So what should we do?  I'm just going to modify it for now and remove it.  But it's not a function because we established that we don't need any of the arguments in the way.  And now there's a to code mix and sentiate that allows you to actually read the next code.  And you say dash dash eval.  And that returns the values.  But right now you can see it's lazy because it just returns the first step,  but it didn't try to ever get all of the rest because we didn't access it.  So we can say actually, please be straight.  And now it returns the whole thing.  So it's not really readable.  So I'm just going to generate JSON instead.  And a bit of thank you.  And now we have the web structure.  So on the left.  So that's what we have on the left.  And here, oh.  So the path is not a recent value.  So it's the point.  There's no such problem, right?  Yeah.  No.  Yeah, maybe it's.  There's no such problem.  There's an error there.  So we have the file.  Oh, you're right.  So if I touch this.  That's more than I get.  So here we're starting to see a bit that does magic.  Oh.  What's that?  So what it does is when it accesses a file, it imports it into the next store.  And that's the value of the.  And there's a hash here.  We're going to cover that later.  But if you change the configuration file, it changes the hash.  This is for version 5.  For version.  For version.  Yeah.  Yeah.  And another thing to notice is that the keys are ordered.  And that's a property that we want to have because it's basically we want to be more repeatable.  So we need to do things like ordering things.  So you always get the same result.  All right.  It's something we can count on that the keys will be ordered on a.  On a validation.  He's our order.  All the same.  Right.  I think that's enough for now.  We'll take a small break and then I can go ahead.
Reading_Nix_Expression___Zimbatm__NixCon_2019__0_6443.png Reading_Nix_Expression___Zimbatm__NixCon_2019__6444_15407.png Reading_Nix_Expression___Zimbatm__NixCon_2019__15408_23891.png Reading_Nix_Expression___Zimbatm__NixCon_2019__23892_23951.png Reading_Nix_Expression___Zimbatm__NixCon_2019__23952_24143.png Reading_Nix_Expression___Zimbatm__NixCon_2019__24144_26411.png Reading_Nix_Expression___Zimbatm__NixCon_2019__26412_26471.png Reading_Nix_Expression___Zimbatm__NixCon_2019__26472_28643.png Reading_Nix_Expression___Zimbatm__NixCon_2019__28644_29123.png Reading_Nix_Expression___Zimbatm__NixCon_2019__29124_29591.png Reading_Nix_Expression___Zimbatm__NixCon_2019__29592_30299.png Reading_Nix_Expression___Zimbatm__NixCon_2019__30300_31943.png Reading_Nix_Expression___Zimbatm__NixCon_2019__31944_32075.png Reading_Nix_Expression___Zimbatm__NixCon_2019__32076_32483.png Reading_Nix_Expression___Zimbatm__NixCon_2019__32484_32651.png Reading_Nix_Expression___Zimbatm__NixCon_2019__32652_33059.png Reading_Nix_Expression___Zimbatm__NixCon_2019__33060_33119.png Reading_Nix_Expression___Zimbatm__NixCon_2019__33120_33311.png Reading_Nix_Expression___Zimbatm__NixCon_2019__33312_33443.png Reading_Nix_Expression___Zimbatm__NixCon_2019__33444_33887.png Reading_Nix_Expression___Zimbatm__NixCon_2019__33888_35315.png Reading_Nix_Expression___Zimbatm__NixCon_2019__35316_35711.png Reading_Nix_Expression___Zimbatm__NixCon_2019__35712_37127.png Reading_Nix_Expression___Zimbatm__NixCon_2019__37128_37175.png Reading_Nix_Expression___Zimbatm__NixCon_2019__37176_38879.png Reading_Nix_Expression___Zimbatm__NixCon_2019__38880_40391.png Reading_Nix_Expression___Zimbatm__NixCon_2019__40392_44603.png Reading_Nix_Expression___Zimbatm__NixCon_2019__44604_47951.png Reading_Nix_Expression___Zimbatm__NixCon_2019__47952_47999.png Reading_Nix_Expression___Zimbatm__NixCon_2019__48000_51167.png Reading_Nix_Expression___Zimbatm__NixCon_2019__51168_55355.png Reading_Nix_Expression___Zimbatm__NixCon_2019__55356_56231.png Reading_Nix_Expression___Zimbatm__NixCon_2019__56232_56819.png Reading_Nix_Expression___Zimbatm__NixCon_2019__56820_56999.png Reading_Nix_Expression___Zimbatm__NixCon_2019__57000_60544.png