We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Designing a DSL with Kotlin

00:00

Formal Metadata

Title
Designing a DSL with Kotlin
Title of Series
Number of Parts
490
Author
License
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Kotlin is one of those “new” JVM languages that are currently rocking the boat. Although it’s made a great impact on Android, it’s equally good on the server side. As Domain-Specific Languages are constrained by the language they run on, Kotlin frees developers from Java fluent builders to propose something better.
33
35
Thumbnail
23:38
52
Thumbnail
30:38
53
Thumbnail
16:18
65
71
Thumbnail
14:24
72
Thumbnail
18:02
75
Thumbnail
19:35
101
Thumbnail
12:59
106
123
Thumbnail
25:58
146
Thumbnail
47:36
157
Thumbnail
51:32
166
172
Thumbnail
22:49
182
Thumbnail
25:44
186
Thumbnail
40:18
190
195
225
Thumbnail
23:41
273
281
284
Thumbnail
09:08
285
289
Thumbnail
26:03
290
297
Thumbnail
19:29
328
Thumbnail
24:11
379
Thumbnail
20:10
385
Thumbnail
28:37
393
Thumbnail
09:10
430
438
Problemorientierte ProgrammierspracheProgramming languageSoftware developerScale (map)Computing platformStreaming mediaProcess (computing)Data storage deviceStapeldateiParallel portSoftware developerMultiplication signStreaming mediaProduct (business)Hand fanJava appletData structureProcess (computing)Information technology consultingPoint (geometry)Computer animation
Programming languageProblemorientierte ProgrammierspracheLatent heatComputerContrast (vision)Software developerProgramming languageProblemorientierte ProgrammierspracheOrder (biology)Computer animation
Problemorientierte ProgrammierspracheSoftware developerProblemorientierte ProgrammierspracheAndroid (robot)Programming languageComputer animation
Problemorientierte ProgrammierspracheJava appletChainingSystem callChainProblemorientierte ProgrammierspracheSystem callOrder (biology)Object-oriented programmingSequenceComputer animation
Stress (mechanics)NamespaceComputer-generated imageryBuildingWindowNavigationClient (computing)CodeProjective planeAeroelasticityJava appletComputer animationSource code
BuildingString (computer science)Client (computing)Computer-generated imagerySlide ruleProblemorientierte ProgrammierspracheFormal grammarWindowView (database)Declarative programmingCodeShared memoryVertical directionField (computer science)OvalFluidLemma (mathematics)Convex hullMenu (computing)Inclusion mapGodServer (computing)Dynamic random-access memoryFluid staticsServer (computing)Order (biology)Social classContent (media)Marginal distributionConnectivity (graph theory)Software developerCategory of beingAndroid (robot)Java appletSingle-precision floating-point formatWeb applicationSoftware frameworkLine (geometry)Set (mathematics)CodeWeb 2.0CodeComputer animationSource code
LogarithmFluidGodComputer fileWindowBuildingVertical directionMIDISpectrum (functional analysis)Directed graphFunctional programmingConnectivity (graph theory)Field (computer science)BitExtension (kinesiology)Graphics tabletJava appletVertex (graph theory)Order (biology)Computer animation
BuildingWindowVertical directionBoolean algebraGeneric programmingProgrammable read-only memoryWeb pageServer (computing)Exception handlingPattern languageJava appletParameter (computer programming)Computer fileControl flowGraphics tabletComputer animation
FluidGodVertical directionBoolean algebraBuildingWindowString (computer science)Execution unitSpacetimeJava appletParallel portInheritance (object-oriented programming)Computer wormSpacetimeComputer animation
Vertical directionBoolean algebraComputer fileWindowBuildingConvex hullMaxima and minimaString (computer science)Execution unitPrice indexUser interfaceNormed vector spaceDefault (computer science)Computer animation
FluidVertical directionBoolean algebraWindowIntrusion detection systemBuildingExecution unitRule of inferenceDefault (computer science)Computer animation
Vertical directionBoolean algebraWindowBuildingFluidComputer filePointer (computer programming)Wechselseitige InformationLemma (mathematics)Execution unitConnectivity (graph theory)Electronic signatureBitVertex (graph theory)SpacetimeLambda calculusMarginal distributionComputer animationSource code
Boolean algebraVertical directionExecution unitBuildingWindowConvex hullSource codeComputer animation
EmpennageExecution unitBuildingWindowBoolean algebraVertical directionFluidComputer virusCodeExpressionComputer animation
Dean numberContent (media)BuildingWindowBoolean algebraExecution unitVertical directionComputer virusGodMarginal distributionLibrary (computing)Vertex (graph theory)Parameter (computer programming)Level (video gaming)CompilerDefault (computer science)Content (media)Source codeComputer animation
WindowBuildingBoolean algebraVertical directionExecution unitContent (media)Web crawlerRotationNavigationParameter (computer programming)Lambda calculusSource codeComputer animation
Execution unitBoolean algebraBuildingWindowVertical directionString (computer science)Lie groupGodContent (media)Field (computer science)Parameter (computer programming)Level (video gaming)Lambda calculusConnectivity (graph theory)Default (computer science)Computer animation
Execution unitVertical directionString (computer science)RotationBuildingWindowBoolean algebraFluidContent (media)Field (computer science)Point (geometry)Computer animation
Server (computing)Vertical directionExecution unitRotationBoolean algebraGodFluidBuildingWindowContent (media)Asynchronous Transfer ModeText editorVacuumField (computer science)String (computer science)Java appletSampling (statistics)Content (media)Video gameAsynchronous Transfer ModeFunctional programmingType theoryMultiplication signComputer animation
WindowNavigationRotationBuildingBoolean algebraExecution unitVertical directionConvex hullGodFluidNormal (geometry)Hausdorff spaceMenu (computing)Category of beingJava appletAreaMIDISource codeRootCompilerRevision controlInformationModule (mathematics)CompilerVideo gameSoftware frameworkComputer animation
Bookmark (World Wide Web)WindowMenu (computing)Error messageGUI widgetMultiplication signComputer configurationXML
Asynchronous Transfer ModeWitt algebraInfinityBuildingUniform resource locatorAreaObject-oriented programmingPrice indexSample (statistics)MaizeAttribute grammarPlanningConfiguration spaceProblemorientierte ProgrammierspracheError messageComputer animation
Query languageCache (computing)Price indexStapeldateiWindowBuildingDefault (computer science)Data bufferZoom lensNavigationHuman migrationDemo (music)Router (computing)Local ringAnalog-to-digital converterSimultaneous localization and mapping19 (number)Spring (hydrology)Repository (publishing)Binary fileType theoryComputer animationSource code
Demo (music)WindowBuildingSpring (hydrology)Software frameworkDivisorRouter (computing)AreaView (database)Slide ruleProblemorientierte ProgrammierspracheFormal grammarEmailRootSquare numberoutputLetterpress printingSocial classType theoryBinary fileRepository (publishing)Software developerProblemorientierte ProgrammierspracheComputer animation
RootSquare numberoutputLetterpress printingOperator overloadingOperator (mathematics)Generic programmingExtension (kinesiology)Function (mathematics)Parameter (computer programming)Default (computer science)WebsiteCategory of beingInformation overloadProduct (business)Set (mathematics)Line (geometry)Problemorientierte ProgrammierspracheFunctional programmingJava appletExtension (kinesiology)Logische ProgrammierspracheCodeTask (computing)Revision controlLibrary (computing)Parameter (computer programming)System callLambda calculusDefault (computer science)Demo (music)Operator overloadingEquals signComputer configurationMetric systemMathematicsPlastikkartePoint (geometry)Multiplication signOverhead (computing)BenchmarkContext awarenessBytecodeFraction (mathematics)Lecture/ConferenceComputer animation
Point cloudFacebookOpen source
Transcript: English(auto-generated)
Thank you to be here for this talk. I know it's the last slot so I really appreciate it. I thought the room would be like nearly empty so it's great. I'm Nicolas Frankel. For a long time I've been a Java developer working as consultants.
Then I did some architecting stuff and I mean, and at some point I decided that customer were too bothersome and it would be much better to go to conferences, drink beer, and talk to two people, which is what I'm doing right now. I'm now working as a developer advocate for Hazelcast
and I've been a long time Kotlin fan. Who knows about Hazelcast by the way? Yeah, that we assume that. So if you're interested, if you are in the Java ecosystem, basically Hazelcast is like a distributed data structure to make it very simple and then we have another product called Jet
which builds upon it and which does stream processing using Hazelcast MDG, so in memory, which it needs to be very, very fast. Okay, now probably you might have heard already about domain specific languages. Like a couple of years ago, they were very, very hot.
I even think there is like an early book or a many book about them. And basically a domain specific language narrows the scope and the features of a general-purpose language in order to guide you to make development on this narrow scope much easier.
And for example, we can think as XML as a general-purpose language, even though, yeah, I know it's not really a language, and then you can create those narrow scopes, languages such as SVG on top of XML. Or if you are using Java,
you can have those DSLs which are used for assertions. I don't know why, but assertions seems to be very popular for DSLs. So a couple of years ago, there was Hamcrest, FestAssert. Now I think the most popular is AssertJ.
And in Kotlin, at some point, there was this way to create Android UIs, and they add a DSL called Encore. So you didn't need to write your UI in XML. You just like really coded it, so you didn't need to inflate it. It was pretty good. I think that they stopped the development.
I don't know why, because I'm not an Android developer. And then I created something called Kotlin that I will show you in the end. And in Java, you are pretty limited to create such DSL. And in general, what you are doing to create a DSL is just like you sequence your method in order.
The most popular method is actually method chaining. So basically, you are returning the current object at the end of each method, and then you can like chain the method together. You can also have nested method calls in lambda, but in the end, the best you can achieve
is something like that. So this is OCRG code. And yes, it reads like correct English, and you cannot do much better. So that's what at most you can do. I have an example in another project.
Here, this one. So here is like a DSL, which uses the Flutter PI, and you need formatting. But then when you are formatting, it reads pretty well.
It looks like the YAML. If you know about Kubernetes, it looks pretty much like YAML. But you cannot do much better with Java. So I want to create a DSL,
and I want it to look like declarative and still to be code. And let's use Kotlin to do that. So let's start. So I will start with this very simple sample,
which is Vardin codes. And Vardin is a web framework. Who knows about Vardin, by the way? Couple of people. So I assume half the room are Android developers, right? In general, the Java server side people know about Vardin
because it's the way that you can create web apps without coding a single line of HTML. So if you already are a front-end developer or an Android developer, you don't care that much. Now, even if you don't know Vardin, you understand, I think, pretty well what this does.
So you set the theme, you create a vertical layout, you set the content of the UI to the vertical layout, then you add the margin, then you add components, and yeah, then you've got your stuff. This is pretty cool to write. However, I think there is this big issue
that basically you can just change the order and nothing will happen. I mean, you will still have the same. The only thing that is really relevant are those two components. You can even set the margin at the end
or set the content at the end. So if you have a team of developers, they will write each in their own way, and unless you've got very, very strict guidelines that, for example, you should always set the content at the end or set the margin at the end or whatever, then it might be hard to get into some new code.
So how can Kotlin can help us? So first, what we will do is we'll create a new UI, Kotlin UI, and we will create this Kotlin UI.
So I want to create the same but using a DSL, but first, I will be very, very step-by-step. So the first thing that we can do is here, we have this set theme, and let's use some property access syntax, so that's one very nice way to do that. So if you have a setter, then you can just use this property access syntax.
It gets the things a bit better. Now, if we would be in Java here, in order to start, we would do something like that. So we would create these static methods, and we are in Java, so it's supposed to be object-oriented,
but basically, we also always have these UIs, classes that are not object-oriented at all, and then they create the layouts. So if I copy-paste or cut-paste this into Kotlin, thanks to IntelliJ, I already have this working for me,
so I can copy Java code, copy and paste it into some Kotlin, and then I've got already Kotlin. I can remove these objects, because with Kotlin, I can have top-level function, and it gets much, much better already, so basically, now I can say, hey, vertical layouts this,
and I get my vertical layouts, and then I can affect this to a vertical layout, and I can add some layouts, dots, add components or label, blah, blah, blah.
Label, okay, but still, I will have the same problem as before, but again, as I mentioned, we will do it like it's text fields. We will do it bit by bit, text fields.
I will call it hello world. So I have the same problem as before. I have this order problem. Okay, now what would be great is actually I have this vertical layout.
I can use those extension function in Kotlin, so instead of having like this function that use this parameter, I can say instead that vertical layout is called on UI, and then of course, I can remove that,
and here, I can have that. So it's a bit better already. Now, on vertical layouts, basically on every layout, I can have like margin and paddings.
So if I was in Java, I would create like an additional methods, and here, margin, boolean, and here, margin,
and here, I would create the padding one, padding, and here, say vertical layout.
It's called spacing, sorry. Spacing is spacing, and I can use this here. Okay, and now comes the problem. I can have, now I want to set the default value,
so here, I would say it return something, so return vertical layout, and I will say margin, let's say the default will be true, and here, I would say that it return a vertical layout,
and the default would be true, true, something like that. Now, issue with that is I need to choose what the default for spacing or margin.
I cannot have both, because actually, those are boolean parameters, so they share the same signature, they are conflicts, and it doesn't work anymore. So as the previous speaker told, we can wrap them inside an inline class, then it creates a new type,
but it's a lot for not much. So what can we do? Well, the first thing is we can provide defaults,
and now we can remove everything, and we have a single signature. Here, vertical layout, we can say this. It will work. It will be a bit smaller. Everybody still sees, even at the back, fine.
I'll create layout two, and here, I can pass nothing, so everything will be true. Now, I still have an issue, because if my spacing is true and my margin is false, sorry, it's the opposite that I wanted to do,
I still need to pass it as true, even though it's the default, which I don't like, because it's too much. So no worries, because we've named parameters, I can have exactly that. So right now, the only thing that we still have
as an issue is these, like, components ordering stuff. I tell you, it's a real issue. We didn't solve the initial problem, so we created everything that worked, but we still have this problem. So now comes something very, very great.
We can add a lambda here. We can add a lambda that will be called a receiver lambda. It takes nothing, it returns nothing, it's called, let's say, init,
and with this lambda, we can apply it. Sorry. We can apply it. So basically, apply means that we will execute
this lambda on this object. And now, we can get a bit better by doing this. Still not perfect, but it's a bit better.
And we can also here, we can actually like scope what we don't want to see, saying, hey, apply, and we can apply here the stuff that we did before.
And now it's this, put this everywhere, and I can chain it, and I don't even need this variable, so as a user, you don't care that much,
but as the code maintainer, it's interesting. And given that actually, it's pretty easy to understand, then we can use like a simple body, like an expression body, and it doesn't tell me how I can do it, so I will do it automatically
and remove the return type. Because now, even if you understand here, you return a vertical layout, the compiler understands it, and you don't need it anymore. There are two applies, and now as a like library designer,
you need to think what's more important. What do you want to override? For example, do you want first to apply the custom stuff, and then whatever happens, you will set the margin to the one that was given,
and the spacing to the one that was given? Or do you want to let the user, like full power, and then it can override saying, hey, you can set the content to something else? So as a library designer, that's something you need to do. Now here, I don't need this variable anymore, and I can create my vertical layout like this,
and the problem with that is you always need to pass a lambda. You cannot just say vertical layout like this, but that's fine. Just as we default parameters that are Boolean, we can pass a default parameter
that is like the empty lambda, and then it works again. I don't know what's your level in Kotlin, but this is made possible by the fact that normally this would be what should be expected,
but if a lambda is the last parameter in your method parameters, then you can extract it outside. It's just syntactic sugar, but actually it gets pretty good.
The fact that you can remove it, and I don't know if, so the question is whether this syntactic sugar has a name, and the answer is I don't know, so perhaps somebody in the audience knows the name.
I call it like lambda syntactic sugar. I know that this has a name. It's called lambda with parameter. That I know, but this one, that's a good question. I will check.
Sorry again. Yeah, it's just syntactic sugar. It's just like, hey, if lambda is the last parameter, you just extract it, and everything is fine. Okay, and I mean, now you know everything because the next step is to actually do the same
with like the level. So I can create a level, and it's exactly the same stuff that I used. So here I'm using the level, and I have like a lambda with parameter that has by default nothing. Then it creates a new label with this,
and now I can replace this like add component label with label, hello, and guess what? I can do the same thing with text field. Oops, not here. No, text field, field.
Nope, so I will copy paste it because I don't remember the shortcut, and so I will say text fields. Now should be caption, and here it's this, add text fields, and it's a text fields.
Yeah, once you understood the trick, it's a lot of copy paste, I agree. Here, and guess what? Now you can replace it with text fields with world,
and now you can do some stuff here, and here you can do some stuff also here, and the good thing is now they become nested, and now you understand what happens, and actually if you are not interested in something, given your ID, you can hide it.
So basically it's a master detail stuff. You can enter at any points and see everything and then go into the detail, but it doesn't stop there. Like imagine that you have a lot of people who create HTML labels. So here, as I did before, my sample UI here
was saying hey, hello in strong, and I need to set it as like it was content type. So I need to set this dot content mode, sorry, HTML.
No, you don't want it? What does it tell me? Okay, so perhaps it was not the right one. Content mode HTML, now it's the right one. Now I can remove this. No, it doesn't want to import. Please do it. No, okay, don't do it.
So imagine that every time I need to create that, that wouldn't be that great. So what I can do is I can create a dedicated one that will use the label function that I created above and that does it automatically. So if you have a lot of people that use this,
then just like make their life easier and just create an HTML function. And once you understand that, life is easy because you can do it for the whole framework.
And if I run that here,
you can see that I have created a sampler with every possible option of every possible widget and that's pretty stupid. Everybody can do it. It's just a lot of time. But basically, it's just like copy paste.
Everything is here. And for example, for Hasselt costs, I didn't know what to do in the plane. So actually, our configuration is in YAML or XML or JSON. Well, let's create a DSL because it's easier,
it's less error prone. So here, I didn't do everything but you can see that if you know Hasselt costs, it looks really nice. And it's compile time. So basically, you can check everything and it works pretty well.
And if you are using Spring, you might know that they are also using this stuff when they create their Spring BNDSL. And actually, this is what it looks like. And again, even if you don't know Spring, you can understand what this does.
And here, for example, that's what I like a lot that you create a bin of type person repository without passing the class. Again, thanks to the inline stuff which makes it possible to reify the classes
though it's not reification. It's just like since it's like copy pasting but still, it knows about the type and then it knows that it must create a bin of type person repository. Now, the question is, hey, we had Groovy before. We could create nice DSLs. Why don't you use Groovy?
Well, if you are a Groovy user, I guess that it's perfectly fine to use Groovy. However, I like my types. I like them. I know a lot of Groovy people. They prefer to say, oh, but you can do everything. And when you need types, you just put them. Well, I would reverse the stuff and say,
hey, you know what? I prefer to type everything and if I really cannot do that, then I can also cast to any if I cannot. Then perhaps there are Scala developers here because Scala is very powerful. You can do everything. Yes, you can do a DSL with basic. You can write basic using Scala.
Well, that's the problem. Scala is very, very powerful and then if you gather like 15 Scala developers in a room, then you will get 20 solution for the same problem. So, not my stuff either. Takeaways. So, the first thing, how to create a DSL
is basically you must start from Java and Java, whatever the API, you don't care because your Kotlin code is 100% interoperable with Java in both ways. So, you can call Kotlin from Java and Java from Kotlin. Of course, if you create a DSL in Kotlin, in Java, it won't look so great,
but you can build upon your existing Java API even if it's not your API. Then you can use the property syntax. So, basically, if you have like setters, just use the equal sign. It's always, it looks a bit cleaner. The third is extension function. A lot of people say, hey,
what's the best stuff in Kotlin? Oh, it's nullability handling. In my opinion, it's extension functions. You can achieve a lot with extension functions. My code becomes much more object-oriented when I use extension functions. And when I'm having, when I have to code back in Java,
it's really, really hard for me because I miss that feature. Name parameters and default values, they go hand in hand. You should really, really like consider them. So, instead of writing every, sorry, of overloading, you should consider using them. It makes your task much easier.
So, instead of like chaining your methods, just use them. Lambdas with receiver, they are the next big thing. Like for DSL, they are a must-have. Like everything is based on them. Some stuff that I didn't talk about, operator overloading.
So, in Kotlin, you can overload operators, but it's not like you can overload everything like in C or Scala. So, you cannot have like hash, hash, bang, bang function. You must have, you can only have a dedicated set. So, in some cases, depending on your DSL,
you might want to add persons together, for example. Then it's good to remember that you can overload the plus operator. Reify generics, I mentioned it when I showed you the SpringBeans DSL. It's really great. I mean, the fact that you can like make believe
that you have reify generics, even though the bytecode has no reify generics, is really great. And something that I also didn't use in my demo is the infix. So, if your function only has one parameter, you can annotate it with infix, and you can call in without parenthesis.
So, depending also on your domain, depending if you are using a math DSL or whatever, then you can create a nice DSL and remove the parenthesis, and it looks better. And so, thanks a lot for your attention. You can read my blog, follow me on Twitter, and more importantly, you can have the look
at what I just showed you. So, you can like git clone it and play with it. And also, I have this card inside. So, if you really want to see how it looks like when everything is finished, even if it's in the old version of Vaadin, then I encourage you to have a look,
and you will see it's only what I showed you here. So, basically, if you want to create a full-fledged DSL with the 10 bullet points that I showed you previously, you can already do it by yourself. I really must warn you that it's very easy to write them.
Again, it's a lot of copy-tasting, and it looks super nice. Beware, because once you start creating a DSL, then it's code, so you must maintain it. So, if you create a nice DSL for, I don't know, on top of Hazelcast, that means that you need to maintain it,
or to give it back to us so we maintain it, but anybody, I mean, at some point, somebody is going to have to maintain it. So, it looks nice, but it's like every time you write a line of code, you must think about, yeah, what's next, and next is maintenance. So, I guess we have some minutes left.
10 minutes. Is there, are there any questions? Yes. What about performance in the IDE,
especially IntelliJ, because I think when I was using libraries with some extension methods, it, I had to wait a lot for auto-completion to appear, like maybe one second or something. I, I, I. Is it okay? I didn't have such experience,
and to be honest, I didn't benchmark it, so I don't know, but as you could see, like on my demo, it's quite easy. Of course, when you create extension methods and lambdas and whatever, in all cases, you will have those long function classes, names, and of course, that's not super great.
I think that in the latest versions of Kotlin, you have incremental compilation, so I would suggest you to use that to speed up, if you, especially if you have big project, but everybody uses microservices anyway, so that's fine. Other questions?
Do you use Kotlin in Hazelcast, in production code? Nope, because I don't want to maintain that stuff,
because I know that if I write it, I will have to maintain it, and here, I have the main director of engineering, and he will chase my ass. You see, I don't want to put my finger in that,
so I can give it to engineering, and then they maintain it, but again, it's really, every line of code that you don't write, you don't need to maintain, so you really need to think about the trade-offs, and in our industry, that's funny, because we are supposed to be like logical people,
but it's either white or black, and most of my talks is it depends. It depends on your context, so if you think that you make, you will ease the way that your user are using your product, then of course, you should provide a DSL.
Now, I know that not many of our users are using Kotlin, so I will address only a small fraction of our community, and I will need to maintain it. The trade-off is not in my favor here. Now, if now everybody here decides that tomorrow, they will convince 10 other people
to use Hazelcast with Kotlin, then let's start talking. I must say that I've seen a lot of Kotlin DSL libraries being like stopped, like maintaining has stopped because they didn't want to maintain it. That's not my question.
In high-performance environments, do you think this should still be done? Especially, do you think there is like an overhead in calling init functions? Could they be inlined? Yes, you can. I mean, also, inline is not magical. Yes, you don't need to call afterwards,
but then you've got a lot of copy-paste of these codes, so if it's a lot of codes, then no, it's not a good idea. I think that when you have such questions, you should basically do the benchmark in your own context
with option A and option B and check which metrics matter to you. Other questions? Okay, let's call it a day. Thank you very much. I have some cool Hazelcast stickers,
and there are some cool Kotlin stickers left. I still have a lot of Kotlin stickers.