Metaprogramming with Nemerle
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Serientitel | ||
Anzahl der Teile | 110 | |
Autor | ||
Lizenz | CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 3.0 Unported: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen und nicht-kommerziellen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen und das Werk bzw. diesen Inhalt auch in veränderter Form nur unter den Bedingungen dieser Lizenz weitergeben | |
Identifikatoren | 10.5446/50970 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
NDC Oslo 201227 / 110
1
2
3
5
7
9
11
12
15
19
20
23
24
27
28
29
31
32
33
35
36
37
38
39
41
43
46
47
51
52
56
59
60
61
62
63
65
67
70
71
74
75
77
79
80
81
83
87
91
92
93
94
95
96
97
98
100
103
106
108
110
00:00
MetaprogrammierungFormale SpracheComputerMeta-TagProgrammCodegenerierungÜbersetzer <Informatik>Visuelles SystemTemplatePhysikalisches SystemMakrobefehlFunktion <Mathematik>SoftwareentwicklerWeb SiteFormale SpracheForcingTelekommunikationSpeicherabzugSoftwareentwicklungFunktionale ProgrammierspracheKartesische KoordinatenRechter WinkelKlasse <Mathematik>Coxeter-GruppeKategorie <Mathematik>WhiteboardDifferenteSichtenkonzeptSterbezifferPhysikalischer EffektSoftwareentwicklerElektronische PublikationMaßerweiterungTemplateVisualisierungMultiplikationsoperatorGenerator <Informatik>QuellcodeVollständigkeitEndliche ModelltheorieCASE <Informatik>SystemaufrufBitrateUnrundheitMathematikDatenbankMetaprogrammierungSchreiben <Datenverarbeitung>CodeDatenfeldZweiSchießverfahrenSampler <Musikinstrument>Logische ProgrammierspracheCompilerDemo <Programm>LaufzeitfehlerGruppenoperationC sharpComputeranimation
05:30
TemplateFunktion <Mathematik>DatentypPhysikalisches SystemMinkowski-MetrikPartielle DifferentiationCodeSoftwareentwicklerTypentheorieDatenmodellObjektorientierte ProgrammierspracheMathematikZeichenketteEigentliche AbbildungMaßerweiterungElektronischer FingerabdruckFormale SpracheDynamisches RAMKategorie <Mathematik>Spiegelung <Mathematik>Produkt <Mathematik>Abelsche KategorieLokales MinimumPhysikalischer EffektCodegenerierungÜbersetzer <Informatik>Visuelles SystemMakrobefehlRechenwerkE-MailPi <Zahl>Virtuelle RealitätOvalSystemaufrufProgrammierspracheComputersicherheitLogische ProgrammierspracheMultiplikationsoperatorDatenfeldInformationCodeProjektive EbeneWort <Informatik>Generator <Informatik>Virtuelle MaschineKategorie <Mathematik>Interface <Schaltung>Gebäude <Mathematik>Physikalisches SystemDatenbankDifferenteGeradeQuellcodeTemplateKlasse <Mathematik>SichtenkonzeptSampler <Musikinstrument>Kartesische KoordinatenCASE <Informatik>MathematikObjektorientierte ProgrammierspracheEndliche ModelltheorieTypentheorieLaufzeitfehlerElektronische PublikationAssemblerLesen <Datenverarbeitung>EreignishorizontBimodulAttributierte GrammatikIdentifizierbarkeitInnerer PunktRechter WinkelSystemaufrufZwischenspracheDynamisches SystemMAPAnalytische FortsetzungChirurgie <Mathematik>VollständigkeitEinfügungsdämpfungTopologieGruppenoperationNummernsystemSchlüsselverwaltungIdentitätsverwaltungTabelleBitrateDelisches ProblemEinschließungssatzKommandospracheProgram SlicingComputeranimation
11:00
SoftwareentwicklerPhysikalisches SystemOvalKonvexe HülleRechenwerkInnerer PunktProgrammÜbersetzer <Informatik>Lambda-KalkülCAN-BusGeradeBasis <Mathematik>ResultanteHochdruckParametersystemLambda-KalkülKonstanteVariableArithmetischer AusdruckDatenstrukturCASE <Informatik>CompilerGenerator <Informatik>VerschlingungMultipliziererCodeGanze ZahlFunktionale ProgrammierspracheTypentheorieTemplateSelbstrepräsentationRechenschieberBitrateSpieltheorieQuelle <Physik>MAPBenutzerschnittstellenverwaltungssystemComputerspielDean-ZahlMultiplikationsoperatorBeobachtungsstudieVererbungshierarchieComputeranimation
15:16
RechenwerkKonvexe HülleGebäude <Mathematik>KonfigurationsraumPhysikalisches SystemSoftwareentwicklerProgrammInnerer PunktOvalHydrostatikÜbersetzer <Informatik>KonstanteCodegenerierungVisuelles SystemTemplateMakrobefehlLastBimodulCASE <Informatik>MenütechnikPrimzahlzwillingeTypentheoriePhasenumwandlungPROMHilfesystemSchnelltasteZeichenketteMinkowski-MetrikDatentypTabelleMarketinginformationssystemComputersicherheitCodeHochdruckAbstrakte SyntaxCompilerVerschlingungZeichenketteLambda-KalkülResultanteDatenstrukturTemplateMultiplikationsoperatorLaufzeitfehlerGenerator <Informatik>DatenbankMAPMakrobefehlInformationRechter WinkelÜbersetzer <Informatik>TypentheorieGewicht <Ausgleichsrechnung>QuellcodeProgrammbibliothekSoftwareentwicklerIntegriertes InformationssystemCASE <Informatik>Formale SpracheProjektive EbeneLogische ProgrammierspracheÄhnlichkeitsgeometrieAssemblerBimodulAttributierte GrammatikArithmetischer AusdruckAbstrakter SyntaxbaumProgrammierspracheSoundverarbeitungProzess <Informatik>Plug inSampler <Musikinstrument>Funktionale ProgrammiersprachePunktGeradeDifferenteGüte der AnpassungWasserdampftafelSoftwareentwicklungParametersystemVollständigkeitBitrateGesetz <Physik>Lesen <Datenverarbeitung>Folge <Mathematik>SichtenkonzeptAggregatzustandOffene MengeEinfach zusammenhängender RaumZahlenbereichNummernsystemComputeranimation
21:59
ZeichenketteBimodulComputersicherheitMarketinginformationssystemRechenwerkMakrobefehlOvalSoftwareentwicklerDatentypCompilerPhysikalisches SystemModallogikDatenbankDatenfeldIdeal <Mathematik>Lambda-KalkülInnerer PunktMinkowski-MetrikBildschirmmaskeMusterspracheStrömungswiderstandCompilerDatenfeldZweiParametersystemLoopTupelKategorie <Mathematik>NamensraumDatenbankMailing-ListeZeichenketteKlasse <Mathematik>TypentheorieTabelleBoolesche AlgebraAbstrakter SyntaxbaumDeklarative ProgrammierspracheWeb SiteRegulärer GraphDatenverwaltungKartesische KoordinatenPunktCodeMereologieProgrammierumgebungRechter WinkelÄhnlichkeitsgeometrieSchreiben <Datenverarbeitung>Poisson-KlammerDatenstrukturInformationsspeicherungTrennschärfe <Statistik>DifferenteMAPKontrollstrukturExtreme programmingArithmetischer AusdruckDifferenzengleichungCASE <Informatik>FlächeninhaltBitrateMathematikMinkowski-MetrikPhysikalisches SystemEndliche ModelltheorieBenutzerschnittstellenverwaltungssystemMagnetbandlaufwerkDemoszene <Programmierung>Sampler <Musikinstrument>NummernsystemComputeranimation
28:42
BimodulZeichenketteOvalPhysikalisches SystemMinkowski-MetrikRechenwerkIdeal <Mathematik>DatenfeldMailing-ListeDatentypSoftwareentwicklerDisk-ArrayMakrobefehlAssemblerProgrammTabelleGeradeRestklasseKonvexe HülleGebäude <Mathematik>VariableKlasse <Mathematik>InstantiierungHochdruckTabelleKartesische KoordinatenMinkowski-MetrikAssemblerTypentheorieMereologieVollständiger VerbandPartielle DifferentiationCASE <Informatik>Attributierte GrammatikMAPNamensraumMailing-ListeZeichenketteGenerator <Informatik>ProgrammbibliothekKategorie <Mathematik>DatenfeldGeradeDeklarative ProgrammierspracheEinfügungsdämpfungSpieltheorieFunktionale ProgrammierspracheAbstandForcingSondierungDemoszene <Programmierung>CompilerGüte der AnpassungRechter WinkelGreen-FunktionStreaming <Kommunikationstechnik>MathematikInformationComputeranimation
35:25
OvalZeichenkettePartielle DifferentiationRestklasseRechenwerkPhysikalisches SystemBefreundete ZahlSoftwareentwicklerElektronische PublikationMinkowski-MetrikMakrobefehlModallogikSinguläres IntegralVollständiger VerbandDatentypTabelleTypentheorieTransformation <Mathematik>InformationZeichenkettep-BlockCompilerFunktion <Mathematik>Kategorie <Mathematik>Arithmetischer AusdruckAttributierte GrammatikKlasse <Mathematik>MakrobefehlAbstrakter SyntaxbaumGenerator <Informatik>DefaultATMCASE <Informatik>CodeGüte der AnpassungStreaming <Kommunikationstechnik>Rechter WinkelInformationsspeicherungMathematikGebäude <Mathematik>BeobachtungsstudieWeb SiteDatenfeldEinfügungsdämpfungAggregatzustandWorkstation <Musikinstrument>Computeranimation
40:28
GeradeSoftwareentwicklerOvalTabelleRechenwerkMakrobefehlZeichenketteBimodulDatenfeldGebäude <Mathematik>StichprobeGeradeRekursive FunktionSoftwareentwicklungStrömungsrichtungFrequenzMaßerweiterungComputerspielFolge <Mathematik>LoopAttributierte GrammatikBefehl <Informatik>Formale SpracheSchreib-Lese-KopfMultiplikationsoperatorKategorie <Mathematik>BeobachtungsstudieVererbungshierarchieCodeArray <Informatik>Funktionale ProgrammierspracheKardinalzahlRechter WinkelKlasse <Mathematik>Kartesische KoordinatenComputeranimation
43:57
Strom <Mathematik>Physikalisches SystemBimodulOvalSoftwareentwicklerMinkowski-MetrikRechenwerkMakrobefehlModallogikHilfesystemDatentypAliasingFormale GrammatikMusterspracheGleichheitszeichenFehlermeldungErwartungswertArithmetischer AusdruckDienst <Informatik>InformationRandverteilungZahlenbereichAnnulatorVererbungshierarchieDemoszene <Programmierung>ErwartungswertHoaxLogische ProgrammierspracheCASE <Informatik>FehlermeldungSchwach besetzte MatrixTypentheorieWorkstation <Musikinstrument>HyperbelverfahrenBitCompilerMereologieTermVariableMultiplikationsoperatorMAPParametersystemKontrollstrukturTransformation <Mathematik>UnrundheitPoisson-KlammerMatchingSchnelltastep-BlockVorzeichen <Mathematik>Array <Informatik>URLEin-AusgabeDateiformatCodeMusterspracheGarbentheorieHochdruckNichtlinearer OperatorTupelMustervergleichMessage-PassingKlasse <Mathematik>DifferenteComputeranimation
50:35
Ein-AusgabeSoftwareentwicklerRechenwerkBimodulOvalGruppenoperationGoogolSISPFormale SpracheAssemblerProgrammierspracheExistenzsatzWeb-SeiteInformationImplementierungQuellcodeGruppenoperationFunktionale ProgrammierspracheDifferenteCOMGoogolApp <Programm>Projektive EbeneMoment <Mathematik>AggregatzustandComputeranimation
Transkript: Englisch(automatisch erzeugt)
00:02
Can you hear me okay? Hello everyone, my name is Igor Katchev. This is our second Nimele session. Last time we discussed the functional programming features of the language. Today we are going to look at the other side of the language. Some people say that this is dark side, dark side of the programming force.
00:26
It's dark because metaprogramming markers and the ability to extend our compilers is two dangerous things. It's too big gun for developers because we can shoot ourselves and we can shoot everybody around us.
00:44
Today I'm going to show this gun and we're going to look at a few metaprogramming tools and metaprogramming techniques that are available even for C-sharp developers and then we will create a few markers.
01:02
We will extend Nimele compiler and we will extend the Nimele language itself. By the end of the presentation I believe that you will be able to decide if you should be scared of the size of this gun or probably it fits for you and you can use it and get benefits from using this.
01:24
Let's start. The definition of metaprogramming is very simple. In a few words, metaprogramming is the writing of metaprograms. Metaprogramming is a computer program that creates or manipulates other programs.
01:43
So if you have an application that generates source code and you compile this code later or your application generates the executable code at the runtime, then your program is metaprogramming. I prefer to group metaprogramming tools by the time when they generate or manipulate the code.
02:10
We can have tools that generate code at the pre-compile time, post-compile time, runtime or right at the compilation time.
02:20
The first example of pre-compile time code generation tool is Visual Studio Custom Tools. If you have ever used Visual Studio Database Designer or Visual Studio Dataset Designer, you should know that they generate some source code. They use Visual Studio Custom Tool for that. One of these tools is T4 Templates generator.
02:45
Now we are going to look at this thing. What is this? We can create T4 template in just a regular way. New item, general, text template. I just generated T4 template and now I can put any garbage here.
03:06
If we save it, we can see that now we have this garbage in our text file. We are going to generate source code. Let's change the extension.
03:21
It's a good idea to use generated.cs extensions because some tools like ReSharper can process these files differently. Now instead of this garbage, I'm going to put another one. We are going to have just one field.
03:47
Now if we save this file, we can see that we generate C Sharp code and inside this code we can find our file, our class. Of course this is useless.
04:02
Let's create some template that we can reuse to generate many classes like this. I already have it in my clipboard. All I need to do is to define a function and you can see that inside this function I have the template I wrote before.
04:26
Now if we save this file, we can... Okay, we didn't even call it. Let's call it first. Okay, generate class A.
04:43
So now we can see this class. Now we can reuse it. We can generate as many classes as we need. Okay, here we go. This is of course not a realistic example. I have another template, another demo that generates a model, view model for my application.
05:13
And yeah, by the way I didn't mention it but we can remove this code and put in the separated file and call it like...
05:21
Give it extension like TT include and then we can reuse this file from different templates. I already have some templates that implement some logic like creating classes, properties, methods. And I have another template that contains a logic to generate...
05:41
I notify property change interface. And now all I need to do is to create new class. I give a name to this class like view model and then I can add as many properties as I need. And let's look at what we just generate.
06:01
In this template, this template generates this file. We can see that we have identified property change interface. We have fields, we have support for this interface and this field, I mean properties, it has a field and all the logic we need to implement and support identify property change interface.
06:23
Also for example I have another template, editable object. And now if I change the type of my property, for example to editable, we will see the completely different picture in the generated file.
06:45
So now we have another interface and for example for this property, we have two fields to support original and current values. So this is metaprogramming, this is T4 templates and in this case we provide the information what used by this template right inside the template.
07:09
And if we look at the size of the generated file, for example right here, we have 15 lines of code and we generated almost 200 lines of code.
07:27
This template uses information I provide right inside the template but also we can read information from different sources that are available before the compilation time.
07:41
For example this template generates database classes, it reads the database schema from my database, from my machine and it generates some classes for Northwind database. So we have lots of classes, we have classes for view, for tables, identities, primary keys, all the information we need to work with our database.
08:07
So this is T4 templates, pre-compiled time code generation, we can use it if we have information before the compilation time.
08:20
Next item, post-sharp, post-compiled time code generation. I don't have post-sharp installed on my machine so I will explain just how it works in a few words. In the project settings, yes project properties, we have this build event tab and we can put any
08:46
tool in the post build event step and on the successful build for example we can run this tool. Post-sharp works in this way. You can use post-sharp attributes to decorate your classes, methods and even attributes and
09:04
after the successful build, post-sharp can read your assemblies and modify something inside this assemblies and maybe generate even new assemblies and add some additional logic in your application.
09:20
So this is post-compiled time code generation. Runtime code generation. We can generate executable code when we run our application and we have actually two techniques, two technologies to do that. System.reflection.imit.
09:41
I'm going to show you, we're not going to write any code because it's crazy. So that's the very simple example but we have a lot of code. This code implements this interface. It generates new class and implements this method and puts this logic inside this method.
10:03
So we need to programmatically, we need to create new assembly, dynamic assembly, new module type, okay and everything else and then we can generate Microsoft intermediate language. And these three lines generate just one line like this and these two lines generate the call of this method.
10:27
So it's very low-level technology but it can be used to improve, for example, increase performance of our applications. So sometimes we use it.
10:41
Next technology is System.link.expressions. Okay, let's play with this and we will need it later. Okay, I'm going to define a lambda. func int int and just function.
11:05
Our lambda is going to have just one parameter and we will multiply it by two. Now we can call it.
11:22
And get the result and print it. Right line, okay. So now if we run it we can see that it's four, yeah usually two by two is four. So now I'm going to modify this code.
11:42
First of all I duplicate it and then I will make one change. So I just rename my variables and now I'm going to change one little things. I'm going to change type of our variable.
12:01
Expression. Okay, you see this line is okay so I define the same lambda. But now I cannot call it because in this case compiler doesn't generate executable code. It generates a data structure that represents this code.
12:20
It generates link expressions. And to run it, to compile it, I have to compile this data structure first. compile function two and f2 compile. So now, now it's going to work.
12:43
Now we can run this and we can see that this is four and four. So again, in this line I defined lambda and compiler generates an executable code. We can run it, we can get result and print it. This line, I define the same lambda but compiler doesn't generate executable code.
13:01
It generates a data structure that represents this code, that describes this code. I have to compile it and then I can call it. So actually compiler does some magic but we are big boys and girls, right? So we don't believe in magic. Santa Claus doesn't exist and we know that we can write the same code manually.
13:23
And we can create this data structure ourselves. So let's do it. Now I'm going to duplicate it again. And again, I change my variables. Now I'm going to change this line. Instead of lambda, I'm going to generate the same data structure manually.
13:47
I'm going to use the static methods of the expression class. This is lambda. I need these templates parameters, generic parameters.
14:03
And now I have to provide the body of my lambda. The body of my lambda is a parameter multiplied by two. So now let's generate it, let's create this. Again, expression, multiply.
14:20
And now I have to provide left and right parameter. Left parameter is a parameter, it's this one. So let's create it. Again, expression, parameter, type of this parameter, this is integer. And name is x.
14:42
So now we can use x. The right side is a constant. But I cannot use just integer because it requires the expression again. So I need to create the representation of this constant. Expression, constant.
15:02
So we just created the body of this lambda. Now I have to provide this parameter. Next parameter is our parameter. Actually, we're done. If I execute it, we see 4, 4, 6. Yes, it's 6 because I used the best technology ever.
15:23
Copy, paste, powered by find and replace. So now it's okay. Again, what's going on here? In this line, we define lambda and compiler generates an executable code. We can run it and get the result and print it.
15:41
In this line, compiler does some magic. It doesn't create executable code. It generates data structure. Here we generate the same data structure manually. So this is link expressions, this is runtime code generation. And this is metaprogramming as well.
16:04
Next item, compile time code generation. If you have a C++ background or if you're familiar with C++, then probably you know that there is a kind of strange technology like templates plus macros.
16:20
You can use it. It's very difficult to understand. It's very difficult to create something that can be useful. And the result, unfortunately, result is very primitive. But anyway, we can use this technology to generate code at the compile time.
16:42
Unfortunately, it uses some probably side effects of the compiler, but still we can generate something. Namely, markers and C++ markers. These are completely different things. We have only names, the same names, but this is totally different things.
17:06
Namely is one of the very few languages that have been designed to support metaprogramming from the beginning. So metaprogramming is native things in the language.
17:22
And we can say that Namely has a pluggable compiler and macros are plugins to the compiler. Compilation process is a very kind of complicated thing and it has few steps like parsing, like typing,
17:40
semantic analysis and code generation. But the very first thing that the compiler does is create a data structure that represents the compiled source code. The same things what we saw here. And when the compiler generates this code, this data structure,
18:01
we can manipulate it. We can modify it, we can analyze it, we can add new nodes to this structure, we can remove something if we need. And for the developers, from the developers point of view, the markers is just a function. This function is called by the compiler
18:21
and this function has access to the compiler API and it can change and modify or transform this data structure. We call this data structure abstract syntax tree, IST. So markers actually manipulates this abstract syntax tree.
18:43
So now we are going to create a marker, Namely marker, and see how it works. And what we can do with that. I have already a demonstration project. We are going to test our markers in this project.
19:03
And another project is a marker library. We have to have two projects. As the marker is a plugin, it has to be compiled before we can use it. So we will create markers in this marker library. And the first marker is going to be our
19:21
database generator, so what we saw right here. So we are going to implement similar logic. Simpler, but similar. So let's create it. New item, and we have marker wizard. And the marker name is going to be dbimpart, right?
19:46
We have two types of markers. We are going to use marker attribute and expression level marker. In this case we are going to use marker attribute. Also we have few steps like before type members.
20:03
So it's related to typing. And we are going to leave this as it is. Also we are going to create assembly level marker. Our marker is going to have just one parameter, database name, database name of the string type.
20:29
Ok, so the wizard generated this template, and now we can modify it and implement this marker. Actually we can implement our marker right here,
20:40
but wizard created an additional module for implementing this marker, so we are going to use it. Ok, first thing what we are going to do is to read information from our database. So this is marker, it will be compiled, it will be called by the compiler at the compile time.
21:02
At this time we are going to read information from our database. Ok, so we are going to do it right. I created the helper and get schema methods, so we are not going to waste our time to do that.
21:21
Let's use this method. Ok, let's look what it does. This method defined next to, right inside this library, so actually macro library can contain any code. Like this for example, helpers, whatever, markers, everything.
21:40
In this method we just create open connection, we create connection, open connection, then read schema from our database. We read columns, tables, and then we even map some database types to .NET types, and then we return this data structure. We return a list of tuples,
22:02
and every tuple is a first field of the tuple, is a table name, and second field is a list of fields, and every field has a name of the field and type. Ok, so very simple. I didn't create the structure for that, so I can use tuples to return this simple structure.
22:24
Ok, so let's store it somewhere. Next step, we are going to do, we need a namespace for all our tables. We don't want to put them just in general namespace.
22:43
We want to create namespace, and the name of this namespace is going to be database name. So let's create a namespace inside of this marker. This is going to be inside of a compiler
23:00
when compiler compiles our application. So now we need to use the compiler API, and we have this parameter, typer, so this is an entry point to the compiler API, and we need this manager class, and in this manager class we need this coreenv property.
23:25
This property has this method what we need, enter into namespace. This method can be used to get existing namespace or create new one if it doesn't exist, ok? It takes as a parameter a list of strings.
23:41
Why list? Because, for example, this namespace has two parts, ok? So we need to provide a list of strings. But we are going to create just a namespace with the name of our database. But of course we can't put something else, for example, we can, let's set it, let's say table.
24:03
So we are going to have like database name and then tables, ok? Let's do it this way. It returns globalenv object, so we are going to need it, and ok, and now we are going to iterate through our database schema
24:28
and define new classes for each table. The type of this item is, you remember, this is table name and list of fields.
24:41
So this is tuple, I am going to decompose this tuple right here. So I have already, I have fields for every field in our tuple and now I am going to define a table. We have environment and we have define method
25:02
if we look at the parameter. This is part of the abstract syntax tree of the compiler and what I can do, I can create this class, for example, type declaration and so on, but I am not going to do this. If I start doing this, we are going to spend
25:22
the whole day and probably the weekend, so I am going to use another technique. You remember that in this code right here, compiler, I provide C-sharp code, but compiler generated some data structure. We have very similar technique in Numerle.
25:43
We call it quasi-quotation. We use these brackets and now inside these brackets I can write Numerle code and compiler, Numerle compiler will create not the executable code but data structure, ISTA syntax tree.
26:04
C-sharp can create only expressions like this, but we need a higher declaration. We are going to write a code to declare a class, but we use the same quasi-quotation,
26:24
the same syntax both for expressions, for defining classes, for everything. If I need to define class, I have to use this prefix, this modifier, so now compiler knows that I am going to define a new class.
26:41
Now I can put just regular Numerle code, public class. Now one more thing. Now I need this name to be class name. I need to put this variable somehow in my code, inside these brackets.
27:06
We use this quotation, this syntax to do that. Table, and I have to use site modifier. I will explain it later what is this.
27:20
Actually I just created a new class inside the compiler. It returns type builder. Now I need to do one more thing. I have to call the compile method.
27:48
Now we are done actually. This code will define new class, and in this loop we will create one class for each table in our database.
28:02
But we don't have fields yet, right? Now we need to put some properties for every field in our table. Now let's create properties. Fields, field is a list of tuples, so I have name of the field and type.
28:21
Now I need to transform it somehow into the abstract syntax tree. I can use select method, for example, like this, SystemLink.EnumerableSelect. But in Numerle we have map,
28:41
and the difference is that map returns list, and I need list actually. So I'm going to use list, but it's actually the same. Function, and of course I'm going to use QuasiQuotation again. The type of this field is strings. Name and type.
29:01
So I'm going to decompose this tuple again. Name, type. So now I can use them again. Declaration. I'm going to generate something like, for example, public customer. ID. String.
29:24
GetSet. Something like that. But instead of this name, I'm going to use this variable. And again, I'm going to use quotation. Name, useSite. And instead of string,
29:42
I'm going to use type variable. Type, useSite. Okay, so now it should be okay, but we need to store it somewhere. And now we can insert it in our class.
30:02
If we have just one variable, we use this syntax for quotation. If we have list, we use another syntax, we use this one. So it means that I insert the whole list. And now if we compile it,
30:20
it should be okay and we can test it. Okay, it works. So now let's go to our application. Test application. First thing I have to do, I have to compile my Marker library. I have to do it. Then I have to open the namespace where I define my Marker.
30:46
Using Marker library. And now I can use my attribute. Assembly. This is assembly level attribute. DB import.
31:04
And we have to provide the name of the database. North. I think it's okay and now we can create an instance of some table.
31:23
We have northwind namespace and I added the additional part of the namespace tables and now we have all the tables in this namespace. So we can create an instance and let's print
31:41
this variable. Okay, so as you can see we have all the tables. There is only one problem. Cilar allows to create the classes with the space inside the name.
32:01
But we will not be able to use it from C sharp, from Nimilia, so let's fix this problem. Let's replace all the spaces with the underscore for example. Replace. Underscore.
32:20
Let's compile it again. And now we see that the name changed and now we can use it. Okay, let's run the application and we see that we printed the name of the type.
32:42
Maybe it's a good idea to print something more detailed, more descriptive. And to do that we would override the two-string method of this class, right? But how can we do it? We can do it in this way.
33:02
We can define, we can say that our public class is partial and right inside of our marker and now we can define another part of this class.
33:21
Tables. And this is partial class. Okay. And now we can override the two-string method.
33:43
So, and in this method we can implement, we can return some some value. For example, we will print, we will return something like customer
34:00
customer ID is, let's add the value. Customer ID. Okay. So now if we print it, oops, we have an error. partial class here, let's compile it.
34:24
Okay. Now we can see that we override two-string method and now we print some descriptive information, but let's put something in this property.
34:42
Okay. Also we can print more fields. In this case we can use string join and the new line as a separator,
35:01
then array and then we will print another field. This is a company company name. Okay.
35:21
And if we print it, if we run it, it's going to print something. Okay, but we have metaprogramming tool. So let's compiler generate all these things for us. Okay, so let's define another macro. And this macro will override two-string method
35:43
in any class where we apply this macro. It's going to be macro attribute as well and the name is going to be implements two-string
36:01
macro attribute, but now we need another face with type members, because we need all these members and we're going to use this attribute on the type. We don't need parameters, so let's create it.
36:25
First thing we have to do is to override two-string method. We have type builder here. In our previous marker, we created this type builder, as you remember. We created it. Now compiler provides us
36:40
with this information with this type builder and now we can use it. Type builder, define, we define new method and of course we're going to use quasi-quotation here.
37:01
Here we'll put override override our two-string method and inside this method, we're going to put exactly the same logic.
37:24
But instead of these fields, we need to generate expressions for every property of our class. Let's do it.
37:41
I'm going to use type builder again because we can call the get property method. Actually, we are using the compiler API. We have all the properties and now we need to generate expressions
38:03
like this, to print our properties. Expressions, we will transform abstract syntax tree to expressions.
38:20
Map again. We have property and here we have another quasi-quotation block. But now I don't have to specify decl modifier because we are going to generate an expression and this is default
38:40
mode for this quasi-block. Okay. I need to generate this code. So, instead of this name, I'm going to use pname.
39:02
No. I'm going to use quotation again. Name plus this string and now I'm going to use pname again
39:25
but with the use site. So, in this case, compiler uses only information like a string. Only the name of the property. In this case, the compiler
39:43
insert the value of this property in our syntax tree. So, now we can use it right here. And again, if this is least, we have to use this syntax. Okay. Now let's decorate our
40:02
class with this attribute to string
40:22
redefinition. Of course, redefinition because I didn't delete this previous function. Now we have all the properties and one more thing. We can define this attribute
40:40
in our DB import markers right here. So, markers are recursive. We can use one markers from another one. And let's compile it again and execute and we see that it works.
41:00
Actually, we don't even need this class here. This is markers that are implemented as attributes. Now we are going to play with the marker that introduce new syntax in the language. Actually, we are going to
41:21
extend the language itself. As an example, we will use two sequences, two arrays and we will create a forage sample, like forage statement, but this forage statement will iterate through at the same time, right?
41:41
So, just for example. Let's say we have I need to define two arrays,
42:07
two, three, another array. First of all, I am going to create a program I want to generate. Then, I will put this code in my marker.
42:22
First of all, I am going to write the application without the marker. Now, I am going to write the code I want to generate. So, this is going to be iter
42:40
one access get the numerator. Then, I need the numerator for another array. And now, I am going to use the while loop to iterate through the
43:02
iter one through these arrays. And now,
43:22
I am going to get the current current values. And then, I can do I can do something with these values. For example, we can print it
43:43
right line and x y. Okay, so let's do that. But instead of doing all these things, I want to
44:00
automate it and create a new keyword and create a marker to implement all this logic. Okay, so let's copy it. And now, let's create a new marker. Let's call it
44:29
foreach2. This time, it's going to be expression level marker. And we will define syntax.
44:41
And the type of this parameter is going to be the expression and body. Okay, you see, now we have a syntax section and now we can define our
45:00
syntax. Let's foreach. Then, we are going to have round bracket and we will close this bracket. That's it. This is our syntax.
45:23
We are going to implement the transformation of our expression. Syntax level marker takes as a parameter one or more expressions and it transforms it and returns another expression.
45:42
Again, I'm going to use quasi-quotation block. And I put all this code I want to generate right inside this block. I'm going to use body that will be provided by
46:00
compiler when this marker is going to be called. Okay, so I use this expression. A little bit later, we are going to work on this expression. Now, let's see what we want from this marker. How we want to see it. We want this syntax.
46:24
x, y, for example, we will use tuple syntax here. Then we need in keyword and then our arrays. And after that, we will
46:41
have the body of this loop. So we need something like that. But we need to check that format of this expression, of this part of our format of our marker is this one.
47:00
So we need to check it somehow. And now we are going to do that. So we need to work on this expression. This expression is this part. This one. Again, we are going to use match operator. Match expression.
47:20
And pattern matching can work with the algebraic data types, numbers, strings, whatever, but also it supports quasi-quotation. So we are going to generate inside pattern matching.
47:41
And pattern matching will check that the input expression matches this format. Okay, so now I am going to write here. Okay.
48:00
But we need to bind these things, these variables, these parts of our expression to what we are going to generate. If you remember from the previous session, we can bind variables, we can introduce new variables in pattern
48:21
matching and we can bind these variables with the part of our expressions. But if we use quasi-quotation, we have to use a little bit different syntax. We use dollar sign for that. Okay, so now it means that pattern matching will check that we have this
48:42
format and all these parts, for example, this part will be bound to this variable, this one to y, and these parts will be bound to this xs and xy variable. And after that, we can use these variables in our
49:03
quasi-quotation block to generate a new expression. So actually we are done. The only problem is that if we have anything, we need an error. We need to inform our user that something is wrong. So if we match our
49:21
expression and we find that this is in this format, then we generate this code. If not, we are going to generate an error. We have a message class and it has a fatal error method and this method takes two parameters,
49:40
location of our expression because we want, if anything is wrong, we want to generate an error with the information where we have these errors. So we need this location. And then we can print something like expected,
50:06
expected, expected, let's say this. Okay, so now let's compile
50:21
and see if it works. Okay. Okay, yeah, it works. And as you can see, we have a new keyword. This is a marker, a marker for each two.
50:40
We have a new keyword and we can even see what we generated by this marker. Okay. We can create more markers but we can play with this marker and for example, we can even use like different languages.
51:00
For example, we can, let's try to use Chinese for example. For each in Chinese is going to be something like that. Okay, let's create a marker with keyword in Chinese.
51:27
We have already implementation. I am just going to reuse this implementation and instead of for each, of course, we need new name for our marker instead of this.
51:40
I am going to use this something I have no idea what I am doing but let's try. Okay, now we can compile it.
52:05
Okay, and as you can see, we have new keywords. This is actually the dark side, I believe. So if you get crazy, you can just rewrite the whole language and you can localize it and use, for example,
52:21
Russian, Chinese, Norwegian, whatever. Okay, so actually, what else? Actually, we are done. Here, our contact information, our site, nimile.org, our Google group
52:41
where we just discuss the issues and language features and GitHub.com, we host our sources there and download page and our contact information. Volochistekov is the main brain behind the nimile and Igor Kashi with me.
53:02
So now, if you have any questions, I would be happy to answer.
53:23
The best way, actually, this is, it's an assembly. So you can distribute it as a usual project, as a source, or you can compile it and distribute it as a DLL. This is just an assembly.
54:02
You don't have to, actually, we have reference to this assembly, but we need this reference, only we compile the project. After we have an application, we don't care if this marker exists. If you have dependencies in your project and if you have dependencies
54:24
in this assembly, then you have two. But if you have just markers, you don't have to. You don't need to distribute it. And that's it. Thanks for coming.