 All right, so this is an example with a controller. And normally, we would need to put those two requires at the top, right? Because this controller is inherited from application controller. So normally, in a Ruby library, standard Ruby library, you should need to require the file that defines that class. And in the index action, we are using the POST model. So normally, we should be required in POST to have that defined when the action runs. But you know that in Rails, actually, you do not need to do that. Indeed, this has a number of issues. First, it looks like kind of redundant, right? We have POST and require POST application controller. Our RubyMind quickly says there's something redundant here. We could maybe automate something or something like that. The other thing is that requires the file only once. So if something changes, it's not going to be reflected in memory. And in development, we would like to be able to change things and have them refreshed in memory automatically. So Rails provides this feature, which is constant auto-loading and class reloading. And it's one of my favorite features of Ruby on Rails first. It's something that is focused on what I believe is the most important thing when you design software, which is how do you use this? You know, how do I use Rails? This is very convenient for me as a programmer, as a Rails programmer, to have this feature. So this helps a lot in your day-to-day. It's a key feature for me. The other thing is that it's kind of, I don't know, it's kind of unassuming. It's just there silently doing its work. I don't know. There's something there. And also it's technically interesting, I believe. So the talk is about how this works. And it has three sections. The first section is a section about constants in Ruby. So that's going to be just Ruby. And that's because this topic is a topic specifically about constants. And it's going to be good that we have them fresh in our minds how they work in Ruby. So first section, constants in Ruby. Second section is how this constant auto-loading works. I refer the post-model and it's just defined. So indeed, the idea is that if you had your application already loaded, you don't have to care about that. You can work more or less as if that was true. The third section is class-free-loading, because we have here actually two features. One is that the constant is auto-loaded for you. And the other one, related but different, is that in addition to that, in development mode by default, if you change something, that's refreshed memory. That's the third section. All right, so let's go with the constant refresher. You know what's a constant in Ruby. We have here an assignment. We are assigning an integer to the x constant. In most programming languages, constants are like a trivial topic. There's not a lot to say about constants. But surprisingly, in Ruby, it's a really, I don't know. There's a lot of things to say about constants. It's not by any means something as simple as in other languages. Here we have a class definition. It looks innocent, but here's the point. This is a constant assignment indeed. We do not see it because we have the class keyword and that's working behind the scenes. But there's a constant assignment there. So in reality, what happens is this. So we have here three, I cannot use the laser, so I'm going to try to describe where I am. The first thing is class C. We have defined the class C as in the previous slide. The second chunk is equivalent. Equivalent as far as constants is concerned. Then there's some stuff with the scope and some stuff that doesn't matter for this presentation. But if you define a class and assign that class to the C constant, that's the same thing the class keyword is doing, the same thing. I mean, I'm not talking about the implementation. I'm talking about the conceptual model in Ruby. It's that. So when we say the C class, we are doing an abuse of language because the class is the object that is stored in the C constant. Like you could store it in a variable, you know? So it's in the C constant. So Ruby has constants and has class and module objects. And they are independent things of the language. When you define a class that way, there's a little coupling there and that's also in addition, you know, give it to you in a simple way with the class keyword, but once you get that definition, they are constant and class object stored in a constant the same way we stored a one in the X constant in the previous slide. Same way. There's no difference. You have X storing one. You have C storing a class object. There's no difference. And here, if you ask in the third chunk of code, if we ask for the name of this class, we get C as the name. And why? Let's suppose the first chunk does not exist. Right? Let's suppose we have only the second and the third chunk. So the reason is that when you assign to a constant, the interpreter says, if the object I am assigning is a class or module and it does not have a name, it's anonymous, then I am going to put the name according to the constant I am assigning the object to. That's what happens. That's like, you know, there's code in the interpreter that does this, right? So you get C as a name. And by the way, this name, this method call is calling a method on the object that it's stored in the C constant. This is one of the most important slides of the presentation. So what happens in the third chunk is that there's a C constant that is the same you can think of a variable to separate clearly constants and class and module objects. There's a C constant that evaluates to a class object that responds to a name method that yields a result. That's what is happening there. So when the interpreter boots, you have a number of constants already defined, you know? But they are constants, they are not classes. So when we say the string class, and we write it that way, we are doing an abuse of language. It's a, of course, it's a convenient abuse of language. You are not going to say, you know, give me the object that is stored in the string constant by default by interpreter, something like that. Which would be, you know, the whole thing, but it's not convenient. But that's really what's happening. We have a string constant that stores a class object that is created by the interpreter when you would. Constants are stored in modules. So, for instance, this is the implementation of the module class in Rubinius. You see, it has a constant table. You can think of that as a hash table. It maps the name of the constants that that module has with the value. It's like a hash table, it's like a symbol table, you know? So they are stored in modules. And again, this is not implementation. This is the conceptual model in Ruby. Constants belong to modules conceptually. So here, we are assigning one to the constant x. And what's happening there? The module, and I am going to spell everything now. That's not how you talk, you know, in your everyday programming. But what happens here is that we are assigning one to a constant call it x that is stored in the constant table of the module that is stored at that time in the constant m. We normally say x is stored in m, right? But to clarify everything because one of the purposes, you know, one of the things that we are going to have clear when we finish a talk is that these things are totally decoupled. So we are storing the x in the module that is stored within the m constant. Indeed, the module could be called something else. And again, the class keyword and the module keyword are basically constant assignments. So this is something in the first chunk of code. This is something that we do routinely. Module something that creates a name space for you and you define a class in that name space, all right? That's a constant assignment. All class and module keywords are creating constants for you. So it's equivalent to the second chunk. The second chunk creates a class with a constructor, class new, assigns to SUCKS parser, and then if you ask for the name of this class object, it returns XML colon colon SUCKS parser. Why? Because it is storing the class object in a constant that belongs to a module called XML. Then the interpreter builds this XML colon colon thing for you, okay? Depending on the name of the module you are defining this thing. And this is another very important slide of this presentation because we are totally going to decouple constants and modules here. We have something similar to what we had before, but we are going to stress that the module and the constant are different things. So in the first chunk we define a module XML, empty. All right, then we do an assignment. This assignment is very important. If you want XML evaluates to a module object that we assign to another constant, same thing as if XML contain it on a string or something more ordinary, you know? There's no difference. It's just an object that is stored in the constant. We assign that object to, in this case, the M constant. All right, so after this line, the M constant and the XML constant hold the same object. If then we reopen the M module because in the third chunk we have module M. What does module M means? So the interpreter says, okay, M, do you have an object with this constant exists? Yes, it has a module, all right. So since it has a module, it's going to reopen the module. It doesn't matter that it was called it or assign it initially to the XML constant. It doesn't matter that the name of the module is XML. It doesn't matter. It's a constant evaluates to a module. We are going to reopen the module. And if we define the SUCKS parser class inside that name space, the name is still going to reflect the name of the module under which we are going to define this constant. You see the separation? So the XML ends in the name of the class because it doesn't matter which is the constant that you syntactically see in the scope. What matters is the module stored in that constant. Of course, this is something that we do not do in our everyday programming. But if we understand this example, we are able to distinguish and know what's going on. Since modules store constants, we have an API to modify the constant tables of those modules. And that's this API that you maybe know, cons get, cons set, cons define it, et cetera. So that's like a high GPI. Get me this constant from this module. Do you have this constant, you know? All right. So in order to resolve constant names, Ruby has three algorithms. We are going to see the three of them from the easiest one to the more complicated one. This is one is here. And it's kind of implicit. We maybe don't realize there's a constant lookup here. So we have a module admin and a user's controller that we want to define within the admin name space or admin name space. What happens here? Remember that every time you use the class or module keyword, the interpreter checks whether you are defining something or reopening something. So there's a check going on, you know? Ruby needs to check whether user's controller is defined in admin module. I don't remember what goes the accent admin or admin. Where goes? Admin? Admin, okay, thank you. So in the admin module, and it's only going to check the admin module exclusively, even if it has ancestors, it doesn't matter. It's going to check the admin module, which is what the name space we have in the scope. So if the constant user's controller exists, in the admin module, it's going to check if it's a class and reopen the class if it's a class, otherwise it's going to error. All right. And this is very important. It's only going to check the admin module. So if you have a user's controller, already defined it in the top level scope, it doesn't going to matter. It's not going to reopen that top level thing. It's strictly the module I have in the scope. All right. By the way, in the top level, constants are stored in the object, right? Okay, the second one. To explain the second one, we need to revise the concept of ancestors of a module or class. Okay, let's go through this slide. In the first chunk, we define an N module. In the second chunk, we define an M module that includes N. Then N becomes an ancestor of M. All right. Then we have class D. And finally, class C inherits from D and includes M. So we have a little bit of everything to see ancestors in all their generality, you know? So which are the ancestors of C? You see at the bottom the ancestors of C. So first C, so technically, the ancestors method returns the receiver. And in this presentation, I am going to refer sometimes to the ancestors. I am going not to include the receiver in that, in that notion, you know? Ancestors from me up, you know? But the ancestors method returns the receiver. All right. Then M, then N, because N is an ancestor of M. So it's kind of recursively unnesting everything for you until it gets flat. That's what it is doing. Then once you have, you know, recursively unnested everything regarding modules, include modules, then it goes to the superclass. And finally, if we have the rest of ancestors, you know, object, kernel, and finally basic object in recent rubies. So these are the ancestors of a class or module. And this is the algorithm that is used to resolve this particular case. And we are talking about the X. So in this particular thing, we have two constants, M, and then the X. The first M is not related to this algorithm we are explaining now. Let's suppose that M is resolved somehow and gives you, for instance, a module, okay? So this slide is about how the X is resolved. And the way the X is resolved is check in M. Do you have the M in your constants table? Let's suppose the answer is no. Then it's going to go through the ancestors of the M module. Okay? Check in one by one. If you find the constant, it's going to return a value. Otherwise, it's going to exhaust the ancestors and it's going to call a special method called const missing. Const missing is similar to method missing. Like if you were asking for a constant and it was not found in the places that there's a look up for, that method is going to be called. And Ruby has const missing defining module and that's the method that raises a name error if the constant is not found. It's a method, indeed, which is raising with that error message that say that the constant didn't exist. So only check in the ancestors and const missing if it fails. And now we go to the most complicated of the three and also maybe the most common one to use, which is in this situation we are going to introduce the concept of nesting here also, which is important for the third algorithm. So we saw the ancestors. We are going now to see the nesting and both of them are taken into account in the third algorithm. So the idea of nesting is that nesting reflects the nested name spaces you have at the point of execution. That's the idea. So in this case, we have m and c. And if these constants store the modules that we normally have in those constants where the name's match, we are going to have in module nesting, which is a method that tells you the nesting at the given point, those three things. The c-class, m and c, the mn-module and the m-module. That's the nesting. So it's something syntactical. You see the source code, you see the nesting. It's syntactical. All right. At the top level, the nesting is empty. And it's important to say that the nesting is only changed by the module class, sorry, the module keyword, the class keyword. And then the eval family, let's say family, there are several eval methods or several or eval-like methods when they take a string of code to evaluate. Not when they take a block, but when they take a string, then the nesting is changed for the context of the execution of that string. But that's the only thing that changed the nesting. In particular, class eval and this kind of things, when they take a block, the nesting is not changed. And this is important for the resolution of constants with relative names, which is what we are going to do now. So you see in the third chunk of code, module nesting, it has not changed. Still, it's empty. Even if for some other stuff is the m and c class that is in a scope to define methods and for other things, that class is in a scope. But the nesting is not, that class is not pushed to the nesting. All right, so what happens with this x in the middle of a screen? The algorithm goes this way. It checks whether x belongs to the class or stored in the c constant. Let's suppose it doesn't exist there. It is going to go up following the nesting. So it's going first checks c, well, the name is m, m and c, but let's say it's simple. See, then the next module, mn, then the next module, m. Let's suppose it has not found the constant in any of these three things. Then it's going to follow the ancestor chain of the c class, m and c class. Okay. And then there's a special rule here. With the c class, we are done. If the constant is not found, it's going to call const missing. But if the name space in a scope, the most nested thing in the nesting, it's a module instead of a class, then the interpreter manually checks object. Object does not belong to the nesting. Okay, so in the first thing, when we go up this way, it's a c and m and stop there. We are going now to go through the ancestors of c. And we have not checked object yet. Object is the last resort. So if the most nested thing is a module, then there's an exception in the algorithm. Special rule that says we are going to check no object. All right, if it fails, it involves const missing. To simplify these descriptions of the algorithms, I skip this little detail, but we are going to see it. You know this kernel autoload thing. Kernel autoload allows you to define here a constant, sex parcel, let's say, and associate that with a file, with a file name. What that does is basically the idea is to lazily load the constant when you need it. So when you need it means anytime you try to do something with a constant, get a value, ask if it's defined, something like that, transparently the interpreter, if you ask, if you are asking for that constant, is going to check if there's an autoload. And if there's an autoload, it's going to fetch the file and if the file defines the constant that we are expecting is going to return the value it holds, okay? So in every single time I set, it checks this module, it checks the ancestor, it checks, that check is always a check. If there's defined and if there's an autoload, go an autoload, all right? That's the entire algorithm. This is very important. I've been asking it a few times this. The way constant autoloading works in Ruby, in Rails, sorry, is not based in this autoload mechanism. It's a different thing. The implementation we are going to see it has nothing to do with this autoload feature. And the problem is that it's just not possible. There are a few things with this autoload thing. First thing is that it only accepts constant names. You cannot pass constant paths, all right? So that introduces some difficulties to support namespaces in Rails. The other thing is that it does a require. And in order to be able to reload things, we need to be able to execute files when they change. So if you use require, you are not going to be able to trigger this again. And in addition, you could decorate maybe, I don't know, as a hack, kernel require. But in addition to that, at least in MRI, that require is a particular require in C that is not kernel require. It uses a particular require. Still, you can do a hack with that because how does require know if something was loaded? So there's an array, call it dollar double quote, that has the names of the files that has been loaded so far. Require checks whether the file you want to load is there. And if it's there, it does nothing. If it's not, require and stores that, you know? So that array is mutable. So if we remove the string from the array, require is going to be fulled and is going to load again the file. OK, but it's not yet enough. Even if we did that hack, we had the issues with namespaces. There's no API to remove an autoload, for instance. So if you remove a file that defines the user class or something, we would expect that to, I don't know, to not work. There should be no autoload for users, you know? But you cannot remove autoload that you already have defined. So there's a number of reasons that prevents rails from implementing autoloading with this thing. And it's a pity because it could be so transparent. It could be so smooth. I don't know. For me, it could be the ideal solution for constant autoloading. But I don't think it's possible to implement it with this feature of Ruby. OK, so we are ready to go for constant autoloading. The thing is we are going to autoload the user constant. You know, we have been invoked the action up to that point in the execution of the code. The user model was not defined. And what happens? Ruby says, hey, you are accessing a user constant. I don't know anything about that constant. It looks for the constant. In users controller, it's not there. Admin is not there. Ancestor is not there. And what happens? It calls const missing, you know? And Rails defines a custom const missing. That's the key of this feature, that const missing. So instead of the default const missing that just raises, so const missing is a method. And the const missing is called doing a method dispatch, ordinary method dispatch. If you, in the answers tree, you have defined something in between, that one is going to be invoked. So const missing gets the constant name you are looking for. In this case, the constant name would be user. And it's running in the context, you know, of the admin users controller class. And that's the information you have. You know, it was invoked in admin users controller. The name we are looking for is user. Those are the two bits of input we have. There's a, this configuration collection in Rails application that by default, it has everything under the app directory. And it's mutable. You can add stuff in that collection. That's a collection of directories to look for constants in auto loading. So it goes this way. First, it checks whether there's a user RV below admin users controller. So is that file, do that file exist? Probably there's not even a users control directory, you know, but you check. This path exists in the file system. Let's suppose the answer is no. Next step, and this is a strange, but we are going to see in a minute what it means. But let me tell you that it checks also whether there's a user directory below the users control directory. Okay, let's suppose it doesn't exist. Then it goes one level up. And we are here kind of emulating going the nesting app. So the nesting here is first admin users controller, admin users controller, then admin. Okay? So we are kind of checking more or less like RubyDOS. It's different, but it's more or less the idea. You know, this thing exists here, no. Next level exists here. That's why it checks whether there's an admin user RV. Let's suppose the answer is no. And also checks whether there's a directory admin user. And if all of these checks fail, if we have a user RV in, you know, at the top level, it's going to load that one. And that's the way a user RV is loaded. Okay, and in development mode, this is done with load. You know, Ruby has require and has load. Require requires only once. Load loads every time you want to load a file. So in development mode is done with load and in production mode is done with require by default. The thing with directories is that maybe you have noticed that when you have namespaces in a Rails application, you do not need to define a file that defines by itself the module that you are using in the namespace. If it's a module. So here's an example. Let's say we have some workers and let's say that for organizational purposes in our application, we have the workers in a workers directory. It's plural or singular. Singular, worker directory. Okay, worker directory is something. You know, files. Maybe you have noticed that you do not need to define a worker.rb file that defines the worker module. You do not need to do that. You can do it, but it's not required. So the thing is, it's going to find, you know, doing this backtracking. It's going to eventually find the worker directory and in that case, it builds an anonymous module for you. Well, anonymous first and then, okay, let's explain this. We're going to match it with the previous section. So we store a worker constant in object and assign a module to that constant. And this is a constant assignment. It's a little bit convoluted. It goes through the API, but it's a constant assignment. So that module that it's anonymous is going to get the name of the constant we assign it to it. Ruby is going to do that for us. So when you ask for the name of the worker module, it's going to say worker. Okay, so Rails does that for you. There are a few cases, few, I don't know, corner cases where you need, so this thing is lazy, right? And that's fine, that's good, because you are not evaluating files until you need it. You need them. But there are a few cases where you need to be sure that the constant is defined at some point in the code. And you can do that with required dependency. Required dependency basically says, load that file now, so the constants are going to be defined now, but do it in a way that is integrated with all the system and they are going to be reloaded and everything. We do not have time to explain use cases for this, but let me say that you need this rarely. So this is something exceptional. Do not take it like normal API that you use every day. No, no, no, it's only for some particular cases where you need to be sure that something is loaded at that time. So we keep track of fully qualified staff and file names. Kernel load and kernel require are rapid because if the user, if the user, if user-rb requires no-co-giri, for instance, dependencies has to be able to know that user-rb was something out-loaded, but no-co-giri was something not out-loaded. It needs to distinguish them because it needs to know what was out-loaded and what was not. Because of course interpreter has tons of constants, you know? It's important to realize that constant out-loading in Rails is different. It uses different mechanisms that Ruby algorithms. First, const missing does not have the nesting. We have the name of the class, we have the constant, but we do not need in which of these situations we are because the nesting depends on the modules stored in the constants, not in the constant names. So the first chunk of code is the regular one, but in the middle, the nesting only has one module, mn, okay? So Rails is not, const missing is not able to say whether which is the nesting. I know my name is mn, but mn is the name in the first chunk and in the second chunk. And there's no way to tell which of the both cases you are, you know? And this is like very, very decoupled. I mean, you can build a nesting with any number of any modules. So generally speaking, the nesting does not reflect the name space. It has nothing to do with the names of the things. Of course, you normally do work with code that reflects it, but technically, it doesn't need to reflect anything. Nesting can be arbitrary as the third chunk exemplifies. And, well, there are even more corner cases, but we are running a lot a bit late, so I'm going to skip this one. So there's a trade-off. There's a trade-off. Rails is going to assume that the name space, you know, the name of the class reflects the nesting. It's going to assume that. If the code is not that way, it's not going to play by the rules of dependencies RV. That's the idea. So it's better, it flows better if your name spaces reflect the name of the things. Okay? So this is the assumption that we are in this situation. All right? Rather than doing class, admin, colon, colon, users, controller. You can do that. It mostly works, but it doesn't flow naturally with dependencies RV. Let's forget about this, which is a corner case. The other key information we do not have is which is the name of, which is the algorithm that was being used to load the constant. We have no fucking idea. We don't know. So here, we do something that I don't like very much. I don't think this is an elegant solution, but it's the best you can do. You cannot do anything else. We are going to check whether the... Okay, we do a check that says if this check succeeds, we kind of know which is the algorithm. But that check depends on the order of loading of the staff which are the constant that are defined at that point. I don't like it very much. Third important difference, we didn't mention any ancestors. We only did the directory thing, okay, which is kind of following the nesting, but we didn't say anything about ancestors. And that's just because we have seen no use case for doing that and complicating things. So it doesn't do it. So this is a corollary of this part. It doesn't emulate the way Ruby actually does things because we cannot, the key information is lacking. We don't have it. Okay, so quickly, the request flow. You know, there's a flag that says whether you want to reload things and auto-load things. There's something that monitors whether the files change. And there's a middleware if you want to reload stuff that is going to reload the stuff. Some stuff is watch it if you change the route, sorry, these changes, locales and everything. And that's the key point. If something changes in development mode in the file system, then the constants, we know because we were keeping track of the constants that we auto-loaded. Those constants, we just remove them. Rails removes those constants. Like using the API, remove const, remove const, remove const, remove const. That's done in the middleware when we start doing the next request and we detect that something changed. So all constants, all auto-load constants are removed. So the way reloading works is the following. If we change it a file and the constants are removed and we are in a request to that admin, users controller, what's going to happen that when the interpreter arrives to the line that uses the user constant says, it doesn't exist. Like it said in the previous request or whatever, it doesn't exist. Then therefore, I'm going to go through these algorithms, I'm going to try to load it and you get a new class object assigned to this constant that we just removed. It could be that the original, technically the original class object maybe, it could be floating somewhere, but it's not reachable through the constant anymore. In that, if your application is correctly written, there should be no nothing referenced, dangling in memory, but they are decoupled. It could still be that the class object somewhere leaving NFC projects that had issues because some stuff like this, they auto-load the constant in italizers or in places that get not reloaded, that kind of things. Okay, anyway, that's it. All right, thank you.