 So welcome everybody at my presentation about metaprogramming in Scala. Look at this WizardCup. It's here for a reason. Today we'll be playing with a very powerful API. We'll be tokenizing code, parsing code, and even modifying code written by developer. So in one word, it will be a lot of magic. But as you will see in examples, it won't be a black magic. We'll be able to create a lot of goodness. We'll be able to create tools which will help us write better programs, better software, or better than this. Okay, so without further introduction, let's start. And a slide about me. So my name is Bartosz Bombal. I have an updated photo of me. So this is what happens to you when you start to write metaprograms. And let's spend 20 minutes talking about me right now. So you can find me on Twitter and blog. If you want to contact me, you will find contact me there. And on my blog you will find also a couple of blog posts about metaprogramming in Scala. Today we've got only 45 minutes to introduce some topic, to sell you some idea, but it's not enough to cover every detail of each example. So I encourage you to preview it if you will find this topic interesting. And moreover, currently I work and live in Thailand, where I work for a company called Agoda. You probably heard about us. Maybe you have even booked a hotel using our application. And we are recruiting right now. So if you want to use newest software and work with outstanding people, tackle not trivial problems, I encourage you to talk to me. I will give you more information than HR because HR doesn't code obviously, right? So if you don't want to talk to me, which is absolutely reasonable, you can send mail to this jobs agoda.com where just write that you are from functional. It will be easier to recognize you. Okay, so traditional survey. Who have heard about Scala Macros or Scalameta? Two people, three, four. Okay, and who have used Scala Macros or Scalameta? Ritz, Wright, something. Okay, minority. That's good, that's good. So before we start, we will need to draw some timeline because metaprogramming ecosystem in Scala evolves in chain, evolves in speed of light. So we'll need to establish some timeline before we start some kind of history. A lot of things changes in recent months. So let's start with a past. And in Scala 2.10, we had experimental feature called Macros and they were experimental for four or five years. And besides some usage by library creators, you will still hear something like, don't use Macros, don't use Macros. It's some kind of a magic, which is true still. But there was experimental feature. It wasn't stable part of the language. So in June this year, creator of the Macros, Eugene Burmako, introduced library called Scalameta. And it was clean new implementation of metaprogramming toolkit as the definition of this library says. So now some horror music should play because like in a Good Hitchcock movie, we will start with an earthquake. And Macros are dead. And that was conclusion from Martin Odersky keynote at Scala Days this year. And so creator of the language and one of the biggest conference in Scala community excluded Macros as the future feature of the language. So you might say something like, okay, cool. So this is why I paid for functional tickets, right? Just to hear that biggest part of metaprogramming language will be excluded from the language. But keep calm, that was Friday at Scala Days, right? So I said that metaprogramming in Scala evolves in speed of light. So let's update our timeline. We've got experimental feature called Macros which in future versions will be deprecated, right? So that was Friday. And on Saturday, creator of Macros, Eugene Burmako, the same guy who has released the Scalameta thing, come on the stage and presented new approach mentioned by Martin Odersky. So presented new Macros which will be in the future versions of Scala. So purpose of those slides are just to say you, Macros are not dead. They are gonna be refactored. The API will be changed sometimes drastically, as Eugene said, but it's still gonna be a feature of the language. So let's summarize those slides and this is our final timeline. We've got deprecated feature Macros. We've got Scalameta and on top of Scalameta we've got new Macros with the new API. And today we'll be focusing on those two parts of the language, right? And we will start with Macros. We'll start with Macros. Then we'll go to Scalameta. So you might still say something like, okay, cool. So creator of the Macros said that they are not gonna be removed, but nothing is for sure. It's still experimental feature of the language. Why should you care? So let's stay with Scala days and let's look at the presentation of Matei Zaharia. One of the creators of Apache Spark framework. We'll not be talking about Apache Spark right now. I'm just showing you to give you some bigger perspective. So creator of the Spark, he was presenting roadmap for future versions of Apache Spark, like big data framework. And he, on one of the slides, he pointed Macros as a way to improve future API, to optimize it more and understand better code written by developer. And why I show this slide. I just want to give you some kind of notion of Macros that you will encounter Macros in more and more presentations that it's not a niche part of the language. It will be, I think, more and more popular recently. So who else uses Macros? So I have outlined here some Scala superstars which somewhere under the hood uses Macros. And today we'll focus a bit more on play framework. But if somebody's from Scala ecosystem, they should recognize all those libraries, right? I should update this talk after talking with you. So if you want to hear something about Scala, this is the right person to talk. And how they are gonna use Macros. So before we'll start with describing those, this example, let's establish some common domain. So what is meta programming? Meta is a prefix which comes from Greek language and it means it's a bound-owned category and what does it mean? So for example, if you are saying a joke between talks, today talks, during the break, and you are saying joke about some other joke, it's not a normal joke, it's a meta joke, right? If you've got data which describes other data in your database or in your file or in your JSON, it's a meta data. And if you've got program which programs other program, it's a meta program, right? So we will be writing programs which will be modifying other programs. And why you want a program which modify other program, right? You've got the program which operates on databases, right? You've got programs which program some servers. Why you wanna write a program to which modifies other program? You want to do this because you are lazy and you are lazy too and we are all lazy in this room. And, but we are lazy in a good way. We are lazy, we don't want to do some redundant work. We don't want to write boilerplate code, right? So, let's look at this analogy. You want to drive this nice car. It's red, it's sporty, it's easy to drive. But in your everyday work, you need this huge machine. It's super hard to drive. It's even easy, it's even hard to start, right? If something goes wrong, it's hard to repair. But you need it. But your dream is to drive this nice red piece of syntax and this is the main idea for macros. Okay, so let's move to some real work example, right? So you've got parsing case class to a JSON. If you are not from Scala community case class, whatever, object to some JSON, very common situation, right? How to do this in play framework? In play framework, you've got method write. And this method, you have to specify, you invoke this method for each field for your JSON, right? Nothing wrong with this code. You just have to, for each field, you have to specify this type, invoke method. Don't focus on the code, it's not important. What is important in this code? Let's think about code on the left, like about a word, a bag of words, a set of some tokens. And let's think about this. If we will have some program which would take those words, take this color, take this ink, take this card, take those words, rearrange them a little bit, modify, add new syntax, do something with those words. We could easily achieve code on the right, right? And this is the main idea why, and this is the main, how to call it, case for macros. You've got a program which takes something, modifies the input, and produces the new code, right? The new output. It's not my idea, of course, not my idea. Somebody has this idea before, and this is how invoking the macro looks like in play framework. We'll not be looking more on this example. So let's focus on some new examples using new macros. So are you convinced for the case for macros? We just have removed a lot of code with one line. The nice piece of syntax for a big amount, enormous amount of boilerplate code. So let's look at this example, and don't look, don't try to understand this method. It's random method with random signature. It's not important right now. What is important, we want to retry this method in case of failure. So let's say that if this method fails, you want to repeat it, certain amount of times. And if it finally will succeed, you want to return this value. If not, if it's still failing after certain amount of time, you want to, I don't know, throw an exception, let's say. So first, let's write this code. And this is how I try to write this code. It's super simple code. It's a for loop. Or 20 times, we are repeating somebody. And we are evaluating this method. If this method is success, we return the result. If it's after 20 times, it's still failing, we throw an exception. It's simple code like that. So what is wrong with this code? Actually, what is important, it's here, right? Evaluating of your method. This commented part, the body of our function, it's the only thing you need to understand, to understand behavior of your method, right? Everything else, like this for loop, this if condition, this throwing exception, it's not important for you to understand method of the body, right? And moreover, you have to modify method body, right? You have to write code. You might make mistake during this writing code or something like that. And if you, okay, so these are the disadvantages of this code. So this is ideal solution. You want to, you don't want to touch this method. Outside of this method, you want to write some annotation plus some parameter like number of repetitions, right? Let's call this annotation retry on failure. Name is whatever you want. So this annotation at compile time, and this is one of the main feature, if I will forget to repeat at compile time, you have to know that whatever we are doing today will be done at compile time. So at compile time, this annotation will take body of our function and generate rest of the boilerplate code. So generate this for loop and the rest of the not important code, right? And we don't have to touch this method. So let's look at the implementation. So as I said, I will present this new macros using the new API. So don't try to look too close to this code. It's very simple, but you might be feeling overwhelmed. It's a lot of words here. But first of all, you have to import Scalameta. Easy, so far so good. Then you've got definition of your annotation with method apply, right? And for you, probably this inline keyword should be new. And the goal of the inline modifier is to signify that application of this method are replaced with the method body. So this inline is saying, hey, whatever you annotated will be inlining other code into this method, right? So this is inline keyword. So this is the second thing you have to write. You have to specify to write your macro. The third thing is this meta keyword. And this meta keyword is to set boundaries where your code is enriched with metaprogramming capabilities, right? And what are those metaprogramming capabilities? Look at the signature method apply takes any, right? So if it takes any, we have to probably some pattern match of this code. So this definition is our annotated code. And we want to match it to some case, right? If we didn't match it to anything, we abort compilation and we are saying, hey man, you are annotating something wrong. Yes, macro-paradise, right? Yeah, but I thought it's a detail. So let's focus on this case statement because it's weird, obviously it's something new here. So first of all, let's have this queue interpolator. We know as interpolator for interpolating strings, right? The queue interpolator is very similar. It's main purpose is to deconstruct and construct code. And to be more specific to deconstruct and construct AST, right? Because when we build code, how would you build code from strings maybe, but then fun is over, right? If you have to modify strings, it's not fun anymore. So we've got one liner for extracting some definition, some scalar construction. If our case, we will be extracting method, right? And method can have modifiers, right? Method can be private. Method can, not can, method has name, right? Method have type parameters and arguments. So what is important in this line is you've got, you can check it in documentation if you will, if you feel kind of overwhelmed right now. What is important from the definition, you can extract everything, anything what is important in one line, right? So, okay, so we have extracted anything what's important from the method definition. But you might say, okay, what's that two dots, three dots thing, right? It's kind of weird also. So two dots means that in this place you are expecting list of something. In our case, we are expecting list of type parameters, right? In three dots means that you are expecting list of list of something, in our case parameters, because method can take many sets of arguments, right? So this is kind of documentation in a nutshell. So we deconstructed code, right? We've got anything we want from the method. Now we want to inline, replace old code with the new one at compile time, at compile time, at compile time, I want to emphasize that. So look at this code. In previous slide you have been deconstructing code. Here we are constructing code, also using this QInterpolator. And we are building method with the same signature, but we are changing the body. And you see it's human readable code. We just write for loop, we wrap body of our method with try, and if success, we return it else for exception and so on. So why I emphasize that it is human readable code? Because I have said that we are building AST, right? And AST is some API. You've got some API to build AST. So we've got normal types, normal Scala objects to build those AST types, right? So on left you've got quasi-quotes, and on the right you've got corresponding AST types. So you can build your tree using like row objects, low row AST objects. But for a simple example, like building literal, it's very easy, right? You are just passing literal. But for also very simple case, like building code X plus Y, building AST X plus Y, under the hood it transforms to kind of complicated tree, right now, right? It looks kind of complicated. I don't know what's that mean. I don't know what that apply and fix. So this slide is just to show you that writing human readable quasi-quotes, it's a huge asset. Okay, so next example of macros. When I was preparing for conference, I checked the Stack Overflow at Stack Scala macros, where you can find questions without surprises about Scala macros. And somebody has a question like that. So I've got a class user, and I want to invoke method to map, right? I want to involve, it's not my question. And he wants to invoke method to map on this instance of this class. And the result should be map where keys are the name of the parameter and value is evaluated value of this parameter, right? So he also said, I'm interested in automatically creating a method at compile time, right? So that's perfect. We can use macros for that. So this is our goal. We want to have class user with annotation map table. I called it map table. Maybe it's stupid name, I don't know. So we've got this annotation at compile time. Before actually, before compilation, we want to add a method to map to it to result with map where we've got keys as parameter names and values as, values as evaluated values of this parameter, right? So look at the implementation and it's the same implementation and it's previous example, couple of things changes. So don't be afraid of this code. Importing Scala meta, done. We are inlining, done, meta, okay. And the same, we are pattern matching the input code. But in previous example, we have been pattern matching definition, right? But if you go to documentation and check, okay, I wanna parse a case class or class, you will find this pattern. You will copy it and pattern match over it. So we are doing exactly the same. We are extracting everything we want from a class. And finally, we extracted the body of this class. So we extracted the body. Yes, this is the same slide but in bigger font. And this is the implementation. And I should, you know, not show this implementation because we extracted everything we want. We've got it in a kind of type safe manner. We've got the AST objects right now. And this expression, don't try to understand it. It's like do logic, do logic. And this do logic means build me keys and values, right? In the next step from, we did the logic, right? We did the logic. And here, we are building a map from those logic. So we are building expecting map. Next thing, we are updating body of our class. So body is a list of statements. We are adding new map, new method to map with our new build it map, right? And finally, we are updating case class and we are returning new case class with updated body. So far so good. We just took a class in previous example, took a method, extract everything we want, did some logic with those extracted values and returned new modified in previous example. Method in this example class, right? And everything happened at compile time. So let's go back to our timeline. And we just saw examples of new experimental feature called macros, this one, right? But actually something else is the main dish and it's called Scalameta. So is Scalameta the same as macros? It's also used for removing boilerplate code. And the answer is no. These are different metaprogramming toolkits which will help you dealing with different problems. So let's go back to Scalameta. So as I said before, Scalameta is a clean room implementation of metaprogramming toolkit in Scala. Cool, how you can use it? It's not Scala, it's, you can use it in different way than Scalamacros. So let's look at the use case first. In previous example we have been reducing boilerplate code and generating code, right? And we have been working more in context of annotated definition, right? So if we have annotated method, we have been working in the context of this method. If we have been annotating class, we are working in the context of the class. In Scalameta, we will be working more on the whole project level. So for example, let's say this example. You want to, you are sitting to the new project and you want to build like code metrics tool, right? You've got some classes in your project like smartphone, phone, iPhone and so on. And you want to see dependencies between them. Which class inherits which class, right? You want to see how big those classes are, right? This is bigger class than this. You want to build like kind of this code metrics tool. So this is good use case for Scalameta. For analyzing code in your project. So it's more on the, it operates more on the project level than on the annotation level like in the previous examples with macros. So different use cases. Who knows what's Ruby on Rails? It's like MVC, everybody knows what's that. And Ruby on Rails has a kind of cool feature called convention over configuration, right? So it means if you've got roots and you specify accordingly to this root controller, model and so on, everything works out of the box without any configuration, right? It's a kind of cool feature, but what is the biggest disadvantage of Rails? Ruby, for me, it's a dynamic language and it's interpreted language. So you want to have this kind of conventions checker at compile time. You don't want your client to call you and say something like, hey, apparently you are not following Ruby on Rails conventions because we've got runtime error, right? So the main idea, the kind of use case for Scalameta here would be to implement this kind of conventions in some Scala framework. Okay, so let's start with some, describing some API. Scalameta is a framework for tokenizing and parsing code. And I imagine this library as some kind of a tool which you can inject into different stages of compilation, right? And on different stage of compilation, you've got slightly different API and you've got slightly different use cases. We, what you want to achieve in this for Scalameta, no. It's only for, in Scalameta, you have to just import, it does it. And that's super simple to start. With macros, you still have to, you know. Okay, so on this slide, you've got different five compilation stages. So how you can inject Scalameta on one of those compilation stages and what you can do, what you can do, what's the use case? So let's start with some lexical analysis. And lexical analysis, what lexical analyzer do? It grabs a code and tokenizes it, split it into tokens. Without understanding the code. So let's look at some example. We've got code, some code. What lexical analyzer will do in this case, it will split it for different tokens. This value modifier, it will be different token. Space, it will be different token. Y and X, these are variable names. They are also tokens, right? Also, a sign sign, an equality sign, these are different tokens. So lexical analyzer has to, you know, figure it out that double a sign, it's not double a sign, it's like equals, right? So this is the job for lexical analyzer and during the lexical analysis, you've got spaces, you've got commas, you've got everything which what you have in your code. So why you want to tokenize code? Or maybe, how you want, how you can tokenize code in Scalameta? Very simple, you are importing Scalameta. First thing, like in the macros examples, you are importing Scalameta. After that, you've got some crazy implicit flying around your code. And one of these implicit gives you ability to tokenize string. And after tokenization of the string, you've got resulted object after tokenization of the string is a token which has two states, success and error, right? Okay. And so what you can, so okay, we tokenized code, cool. What we can do with this? We can print line tokens. So as I said, value is a token, space is a token, variable names these are token, assign, equality is a different token, right? You can print line structure, more for debugging. You will have exact place in your code where this token appears, right? So and you can also print line syntax for print line syntax, right? So make those token in human readable form like previously, right? Okay, cool, how you can use it. What are possible use cases? So let's say that you want to write some super simple formatter which will replace some pattern, right? And you want to replace get or else null to or null. Like super simple formatter. You want to replace filter head option to find. These are equivalents, right? But you want to have this kind of more sophisticated let's call it. We'll not be looking at the implementations right now because we don't have much time to do this. But I have these examples from my blog post and it's possible to achieve this kind of formatter very easily using those three methods I showed you in the previous slide. And also if you want to preview something more complex there's like a formatter called Scala FMT on the main page of Scala meta you will find also link to this library and the author of this library heavily operates on the token level and what he's doing, he is formatting the code. So code on the left is before formatting, code on the right is after formatting, right? So this is the use case where you can use Scala meta at compilation stage of lexical analysis, right? So formatting code looking for some patterns and so on. So let's move to the next compilation stage and next compilation stage is parsing code and parser needs simpler data structure than we've got after tokenization. In parser we don't care about spaces, we don't care about semicolons and so on. We need a super simple construction like AST tree which will give us information about semantics of the code. On this stage parser will try to understand code. In previous stage what we did is what is just tokenized code, split it into different words. Here parser will need to understand more this code. So how to parse code in Scala meta? Very simple, we are importing Scala meta again and we've got method parse and look we have to parameterize this method with specified type. Our parser needs to know what we are parsing. In this example we are parsing type, right? But if you want to parse something else you have to specify it with different type. And the same, after parse we've got object parsed which can be success and error but actually it's not important. So let's look at the different ways how you can parse something and if you want to parse statement you need to parse with the type statement, right? If you want to parse case, case pattern you have to parse it with the case type and so on, right? It's like more, it's not so, it's more type safe on this level, right? So what will happen if you will parse case statement as statement, it's normal statement. You will have compile time error that compiler will tell you, hey man you are parsing something else and you are saying that you're gonna parse statement, right? So here parser will prevent us from doing something very stupid. We can still do something stupid but not very stupid. Okay, so if Scala macros are built on top of Scalameta can we use in Scalameta quasi-quote? Yes we can and after parsing code we can extract values in the same way we have been extracting when we have been building new method or new case class during the macros example, right? So we can extract it very easily, one line and we've got everything we want in the ASD types. Okay, somebody is counting the time? Where are organizers? Good, we've got a lot of time. So joke, well, okay. Let's say that we want to implement some kind of a pattern, some kind of convention. It might be stupid convention but still. So let's say that every string constant you want to keep at the object constant, right? Very simple situation. You just want, if you've got a string in your project it has to be in the object constant. You just have this kind of pattern. You've got this idea and moreover you want every each string to be assigned only once to a value. Don't know why, that's your idea. And our object clearly doesn't follow this rule because Ruby is assigned to two different value lengths, right? So how we can prevent this at compile time? How we can check this at compile time? So let's say this is invocating so we'll be writing method validate and we'll be parsing our object constants, right? We will be parsing it at source. So it's one of the types you will find in the documentation. We'll not be parsing it because in the constants file you might find different scalar constructions, right? Depends on the main class, I don't know, in this example. You can build an SBT flag to do this but when I was writing these examples I simply invoked the method validate. It's like, yeah, for me it was also kind of different at the beginning because macros, they are in the different project, right? And Scalameta, it's not in the different project. You're just writing method which under the hood will operate on this compiler. It's kind of different. This is why I want to emphasize macros and Scalameta is different thing, different problem. Okay, so this is a signature of our validate method and we are doing the same as we have been doing in the free previous example or two, I don't know. So we are extracting something from the code. And in our source which we have as an input, we've got two dots stats. What does it mean? We've got list of statements because in the source file we can have many class definition object, whatever, right? So we are interested only in the object, right? Copy this from the documentation. We're only interested only in the object in the file, which name is constant. And if we've got this object and everything was important from this object, we can start implementing some logic and don't try to understand it. What we do here is just taking all the values, group by the value, right? Group by the assigned string and if this list after grouping is bigger than one, it means that this string is assigned more than once to different values, right? So it's very, I would say that it might be overwhelming for you because it's a lot of maybe new stuff for you, but it's very, if you download some examples and try to play with them, it will be very straightforward because any idea you want to implement will be super simple. Import Scalameta, extract whatever you want from whatever construction you want and do the logic using the Scalameta API. So, okay, code metrics. So code metrics, I'm not sure if I want to show you this example. We will be building code metrics, right? So we want to build something which will take all these different case classes and a case classes, traits, objects, whatever. It will take some Scala constructions and it will give you informations about them. So let's skip this, let's skip this. We are doing the same as in previous example, right? Source, whatever is in the file, try to find what I'm interested in. And this is actually the body, the real implementation. So if you found an object in the file, increment object number. If you've got class, increment class number and so on and so on, right? So in one line, you have to very easily specify what you are looking for, extract whatever is important in the site and do the logic. In our example, we'll be simply counting number of objects. On my blog post, I build it kind of more detailed example so I encourage you to play with this. So you might go further with this metrics idea and implement your own. And this is kind of use case I had just a couple of days ago. So I have an object, my application boot. And this my application boot has method run which take three implicit parameters, whatever these implicit are. Don't try it, it's some kind of actor system from ACCA library. It's not important here. And what I want to do is force people to not create those implicit here because I always want to run this method outside of this object. So I want to run this method from the different boot object which will run the application, right? So what are our possible, how we can do it? You can write comment, don't create actor system here and start to threaten people but always you will find somebody bigger than you. And in my example, it's not hard to find somebody bigger than me. So it will not work. So using the API I just showed you, you can very easily extract this object, extract anything that was important and find the places where somebody is creating new actor system in this object. And then you can throw compilation error, right? Or learning whatever you want. So, okay. So I hope that I show you some kind of, how to call it, use cases for Scalameter. It's a different thing than Scalamacros. It gives you possibilities for building different tools. And I believe that after familiarizing with the API, with previewing with the API, these are the links for the API, you will find the new ways how you can, how you can use this library to achieve your goals. So I hope that I convince you to spend Friday night writing Meta program and if you want to spend Friday night at Island, surrounded by beautiful beaches and environment, writing Meta program, talk to me, because our office in Bangkok is super close to the best islands in the world. So thank you for listening. And I hope you enjoy. It's like it. So you want to debug output from the map. For example, did I understood correctly? Depending what you ask. If for example, you generated code, right? And it's what you generated code and you push it further to the compilation. So if you made compile time error, you will have compile time error. If you will have like logic error in your business logic, then you have to, how I wrote, I'm not sure if I understood your question, but how I wrote this kind of example. I've got also bigger examples when I was writing really huge macro. And how I did it was write the code at the first time, the big one, right? And then step by step replacing each. You're looking for that much. Yeah, yeah. And if you've got, you've got build macro. It's building a lot of boilerplate code, right? And you've got, at some point, you've got the bug. How I did, I took the generated code, I replaced the code where I invoke macro with the generated code, and I debug it like normal code, right? Because you're, so yeah. So you copied the macro output to your code. You are debugging it normally. And you found the bug, you repaired it. You change your macro to generate better repaired code, right? Yes, yes. Like for example, let's say that you want to, yeah, let's say that you just loaded the file, the source, right? And by some example, you forgot to write two dots, right? You will have compile time error at this stage because this interpolator will expect to have list of statements in your file. And you just write that you are not expecting this. So you'll have a lot of compilation errors if you will do something not logical, right? Macro, you need macro paradise to write macros. If you use Calameta, you don't need macro paradise. Actually, I'm not sure you can do similar things. That's the first thing. And the second thing, like for me, macros you are operating on the annotation context, right? You annotated case plus. You are operating on the case class. You just annotate it, right? You annotated method. You operate on the method to just annotate it. In Calameta, you've got library, like any other library you might imagine, which you just use to inspect your code, to analyze your code, right? Is in-built now in Salameta. So what are the new things which are not present in? I think the def macros, that's the first thing. I think you also asked about what is removed from macro paradise, right? How do you actually, you said that you can do a compilation error on the data that you know of you, so you have to do that on the computer? Yes, yes, but in that case, I placed it in the main method, right? In our main, it was super simple object, super simple code, right? So I invoked the method. So you can invoke method in the code itself. Yes, you are not doing anything else. So in macros, you've got project, which your project depends on the macro project, right? So before your project run, your macro will generate anything in line everything. And you have to separate it into modules. Yes, exactly. Here, you are built SBT at Calameta, cool. Write a method in whatever you want, invoke this method, that's all, right? So, and you ask about SBT plugin. So maybe you can add it as a SBT plugin, which will do it. Maybe you don't need it, you can achieve it. You can invoke it like a mix macros with Calameta. I'm not sure about it. Maybe, yes, so you're asking, you're saying something like that. Are you annotated case class with annotation? Then your meta program from Calameta is doing something on that file. I think it will be invoked, if you are thinking about Calameta, it will be invoked like a normal code, sequentially. So you will invoke method validated, it will validate it. And under validate, you will do something, I don't know, do something else. For me, it was weird when I was writing macros in the previous API, and then I started to look at Calameta, and I couldn't find the use cases for it, because, yes, yes. But a compilation time, right? Yeah, yeah, yeah. So you might affect performance like another method, right? Some other questions? What line numbers? Yeah. Yeah. Class file in your target will have that modified code, right? So if you will have error with maybe, okay, so you will have error on annotation, but the message of the error will be like, what do you think? Yes, yes, yes. Okay, thank you for attending.