<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ivan Osipov</title>
    <description>The latest articles on Forem by Ivan Osipov (@ivanosipov).</description>
    <link>https://forem.com/ivanosipov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F51348%2F1498f79d-4e2c-4c8d-b7d4-8bb2ad2518a9.jpeg</url>
      <title>Forem: Ivan Osipov</title>
      <link>https://forem.com/ivanosipov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ivanosipov"/>
    <language>en</language>
    <item>
      <title>Kotlin DSL: From Theory to Practice</title>
      <dc:creator>Ivan Osipov</dc:creator>
      <pubDate>Wed, 17 Jan 2018 08:36:40 +0000</pubDate>
      <link>https://forem.com/ivanosipov/kotlin-dsl-from-theory-to-practice-6h7</link>
      <guid>https://forem.com/ivanosipov/kotlin-dsl-from-theory-to-practice-6h7</guid>
      <description>&lt;p&gt;SQL, RegExp, Gradle — what do they have in common? All of them represent an example of using domain-specific languages, or DSLs. Languages of this type aim to solve a specific problem, such as database querying, finding matches in the text, or build process description. Kotlin offers a large number of features for building your own domain-specific language. In this article, we’ll discover the developer’s toolkit and implement a DSL for a real-world domain.&lt;/p&gt;

&lt;p&gt;I'll try to explain the language syntax as simple as possible, however, the article still appeals to developers who consider Kotlin as a language for custom DSL building. At the end of the article, I'll mention Kotlin drawbacks worth taking into account. The presented code snippets are relevant for Kotlin version 1.2.0 and are available on GitHub.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Is a DSL?
&lt;/h1&gt;

&lt;p&gt;All programming languages can be divided into general-purpose and domain-specific languages. SQL, regular expressions, and build.gradle are often cited as examples of DSLs. These languages are limited in functionality, but they are able to effectively address a certain problem. They allow you to write imperative code (we shouldn't explain how to solve the problem) but in more or less a declarative way (we just declare the task) in order to obtain the solution based on the given data.&lt;/p&gt;

&lt;p&gt;Let's say you have the standard process definition that can be eventually changed and enhanced but generally, you want to use it with different data and result formats. By creating a DSL, you create a flexible tool for solving various problems within one subject domain, no matter how the solution is obtained. So, you create a sort of API that, if mastered, can simplify your life and make it easier to keep the system up-to-date in the long-term.&lt;/p&gt;

&lt;p&gt;The article deals with building an "embedded" DSL in Kotlin as a language implemented on the general-purpose language syntax. You can read more about it &lt;a href="https://en.wikipedia.org/wiki/Domain-specific_language#Usage_patterns"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation area
&lt;/h1&gt;

&lt;p&gt;To my mind, one of the best ways to use and demonstrate Kotlin DSL is testing.&lt;/p&gt;

&lt;p&gt;Suppose that you've come from the Java world. How often have you been faced with declaring entity instances of an extensive data model? You've been likely using some builders or, even worse, special utility classes to fill the default values under the hood. How many overridden methods have you had? How often do you have to make little changes from default values, and how much effort does this require today?&lt;/p&gt;

&lt;p&gt;If these questions stir up nothing but negative feelings, this article is for you.&lt;/p&gt;

&lt;p&gt;That's the way we've been doing it for a long time in our project in the area of education: We used builders and utility classes to cover one of our most important modules (school timetable scheduling) with tests. Now this approach has given way to the Kotlin language and DSL, which is used to describe test scenarios and check the results. Throughout the article, you can see how we took advantage of Kotlin so that testing of the scheduling subsystem is not a torture anymore.&lt;/p&gt;

&lt;p&gt;In this article, we will dive into details of constructing a DSL that helps to test an algorithm building teachers and students schedules.&lt;/p&gt;

&lt;h1&gt;
  
  
  Key Tools
&lt;/h1&gt;

&lt;p&gt;Here are the basic language features that allow you to write cleaner code in Kotlin and create your own DSL. The table below demonstrates the main syntax enhancements that are worth using. Take a look at it carefully. If most these tools are unfamiliar to you, you might want to read the whole article. If you don't know one or two of them, feel free to fast forward to corresponding sections. In case there's nothing new for you, just skip to the DSL drawbacks review at the end of the article. Feel free to propose more tools in the comments.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;DSL syntax&lt;/th&gt;
&lt;th&gt;General syntax&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operators overloading&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collection += element&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collection.add(element)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type aliases&lt;/td&gt;
&lt;td&gt;&lt;code&gt;typealias Point = Pair&amp;lt;Int, Int&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creating empty inheritor classes and other duct tape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;get/set methods convention&lt;/td&gt;
&lt;td&gt;&lt;code&gt;map["key"] = "value"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;map.put("key", "value")&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destructuring declaration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;val (x, y) = Point(0, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;val p = Point(0, 0); val x = p.first; val y = p.second&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda out of parentheses&lt;/td&gt;
&lt;td&gt;&lt;code&gt;list.forEach { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;list.forEach({...})&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extension functions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mylist.first(); // there isn’t first() method in mylist collection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Utility functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infix functions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1 to "one"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.to("one")&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda with receiver&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Person().apply { name = «John»  }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context control&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@DslMarker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Found anything new? If so, let’s move on.&lt;/p&gt;

&lt;p&gt;I omitted delegated properties intentionally, as, in my opinion, they are useless for building DSLs, at least in our case. Using the features above, we can write cleaner code and get rid of voluminous "noisy" syntax, making development even more pleasant (could it be?).&lt;/p&gt;

&lt;p&gt;I liked the comparison I met in the "Kotlin in Action" book: In natural languages, like English, sentences are built out of words, and grammar rules define the way of combining these words.&lt;/p&gt;

&lt;p&gt;Similarly, in DSLs, one operation can be constructed from several method calls, and the type check guarantees that the construction makes sense. For sure, the order of callings cannot always be obvious, but it is entirely up to the DSL designer.&lt;/p&gt;

&lt;p&gt;It is important to stress that this article examines an "embedded DSL", so it is based on a general-purpose language, which is Kotlin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Result Example
&lt;/h2&gt;

&lt;p&gt;Before we begin to design our own domain-specific language, I'd like to show you an example of what you'll be able to create after reading this article. The whole code is available on the GitHub repository at this &lt;a href="https://github.com/ivan-osipov/kotlin-dsl-example"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The DSL-based code below is designed to test the allocation of a teacher for students for the defined disciplines. In this example, we have a fixed timetable, and we check if classes are placed in both teacher's and students' schedules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;startFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"08:00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;subjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Russian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"Literature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"Algebra"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"Geometry"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;student&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ivanov"&lt;/span&gt;
            &lt;span class="nf"&gt;subjectIndexes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;student&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Petrov"&lt;/span&gt;
            &lt;span class="nf"&gt;subjectIndexes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;teacher&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;subjectIndexes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nf"&gt;availability&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="nf"&gt;monday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"08:00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="nf"&gt;wednesday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"09:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"16:00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;teacher&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;subjectIndexes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;availability&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;thursday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"08:00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sameDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"11:00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sameDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"14:00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// data { } won't be compiled here because there is scope control with&lt;/span&gt;
        &lt;span class="c1"&gt;// @DataContextMarker&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;assertions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;teacher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;scheduledEvents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;teacherSchedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Schedule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;teacher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;
            &lt;span class="n"&gt;teacherSchedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;shouldNotEqual&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
            &lt;span class="n"&gt;teacherSchedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt; &lt;span class="n"&gt;shouldEqual&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;studentSchedule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;
            &lt;span class="n"&gt;studentSchedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;shouldNotEqual&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
            &lt;span class="n"&gt;studentSchedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;teacher&lt;/span&gt; &lt;span class="n"&gt;shouldEqual&lt;/span&gt; &lt;span class="n"&gt;teacher&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Toolkit
&lt;/h2&gt;

&lt;p&gt;All the features for building a DSL have been listed above. Each of them is used in the example from the previous section. You can examine how to define such DSL constructs in my &lt;a href="https://github.com/ivan-osipov/kotlin-dsl-example"&gt;project&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;We will refer to this example again below in order to demonstrate the usage of different tools. Please bear in mind that the described approaches are for illustrative purposes only, and there may be other options to achieve the desired result.&lt;/p&gt;

&lt;p&gt;So, let's discover these tools one by one. Some language features are most powerful when combined with the others, and the first in this list is the lambda out of parentheses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Out of Parentheses
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/lambdas.html#higher-order-functions"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lambda expression is a code block that can be passed into a function, saved or called. In Kotlin, the lambda type is defined in the following way: (list of param types) -&amp;gt; returned type. Following this rule, the most primitive lambda type is () -&amp;gt; Unit, where Unit is an equivalent of Void with one important exception. At the end of the lambda, we don't have to write the &lt;em&gt;return...&lt;/em&gt; construction. Therefore, we always have a returned type, but in Kotlin, this is done implicitly.&lt;/p&gt;

&lt;p&gt;Below is a basic example of assigning a lambda to a variable:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val helloPrint: (String) -&amp;gt; Unit = { println(it) }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Usually, the compiler tries to infer the type from the already known ones. In our case, there is a parameter. This lambda can be invoked as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helloPrint("Hello")&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;In the example above, the lambda takes one parameter. Inside the lambda, this parameter is called by default, but if there were more, you would have to specify their names explicitly or use the underscore to ignore them. See such a case below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;helloPrint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Do nothing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="nf"&gt;helloPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Does not matter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//output: Do nothing &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The base tool — which you may already know from Groovy — is the lambda out of parentheses. Look again at the example from the very beginning of the article: Almost every use of curly brackets, except the standard constructions, is a lambda. There are at least two ways of making an x { ... }:-like construction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The object x and its unary operator &lt;em&gt;invoke&lt;/em&gt; (we'll discuss it later);&lt;/li&gt;
&lt;li&gt;  The function x that takes a lambda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In both cases, we use lambdas. Let's suppose there is a function x(). In Kotlin, if a lambda is the last argument of a function, it can be placed out of parentheses. Furthermore, if a lambda is the only function's parameter, the parentheses can be omitted. As a result, the construction x({...}) can be transformed into x() {}, and then, by omitting the parentheses, we get x {}. This is how we declare such functions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun x( lambda: () -&amp;gt; Unit ) { lambda() }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In a concise form, a single-line function can be also written like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun x( lambda: () -&amp;gt; Unit ) = lambda()&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;But what if x is a class instance or an object instead of a function? Below is another interesting solution based on a fundamental domain-specific concept: operator overloading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operator Overloading
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/operator-overloading.html"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kotlin provides a wide, but somewhat limited variety of operators. The &lt;em&gt;operator&lt;/em&gt; modifier enables to define functions by conventions that will be called under certain conditions. As an obvious example, the plus function is executed if you use the "+" operator between two objects. The complete list of operators can be found in the docs by the link above.&lt;/p&gt;

&lt;p&gt;Let's consider a less trivial operator: &lt;em&gt;invoke&lt;/em&gt;. This article's main example starts with the &lt;em&gt;schedule { }&lt;/em&gt; construct that defines the code block responsible for testing the schedule. This construct is built in a slightly different way to the one mentioned above: We use the invoke operator + "lambda out of parentheses".&lt;/p&gt;

&lt;p&gt;Having defined the invoke operator, we can now use the &lt;em&gt;schedule(...)&lt;/em&gt; construct, although &lt;em&gt;schedule&lt;/em&gt; is an object. In fact, when you call &lt;em&gt;schedule(...)&lt;/em&gt;, the compiler interprets it as &lt;em&gt;schedule.invoke(...)&lt;/em&gt;. Let's see how &lt;em&gt;schedule&lt;/em&gt; is declared:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;schedule {
    operator fun invoke(init: &lt;/span&gt;&lt;span class="nc"&gt;SchedulingContext&lt;/span&gt;&lt;span class="p"&gt;.()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nc"&gt;SchedulingContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;schedule&lt;/em&gt; identifier refers us to the only &lt;em&gt;schedule&lt;/em&gt; class instance (singleton) that is marked by the special keyword &lt;em&gt;object&lt;/em&gt; (you can find more information about such objects &lt;a href="https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations"&gt;here&lt;/a&gt;). Thus, we call the &lt;em&gt;invoke&lt;/em&gt; method of the &lt;em&gt;schedule&lt;/em&gt; instance, receiving a lambda as a single parameter and placing it outside of the parentheses. As a result, the &lt;em&gt;schedule {... }&lt;/em&gt; construction matches the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;schedule.invoke( { code inside lambda } )&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;However, if you look at the invoke method carefully, you'll see not a common lambda, but a "lambda with receiver" or "lambda with context", whose type is defined as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SchedulingContext.() -&amp;gt; Unit&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;Let's examine it in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda With Receiver
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kotlin enables us to set a context for lambda expressions (context and receiver mean same thing here). Context is just an object. The context type is defined together with the lambda expression type. Such a lambda acquires the properties of a non-static method in the context class, but it only has access to the public methods of this class.&lt;/p&gt;

&lt;p&gt;While the type of a normal lambda is defined like () -&amp;gt; Unit, the type of a lambda with X context is defined as follows: X.()-&amp;gt; Unit. And, if normal, lambdas can be called in a usual way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meanwhile, a lambda with context requires a context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyContext&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;.()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;//x() //won’t be compiled, because a context isn’t defined &lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;//create the context&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;//works&lt;/span&gt;

&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//works as well&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'd like to remind you that we have defined the invoke operator in the schedule object (see the preceding paragraph) that allows us to use the construct:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;schedule { }&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;The lambda we are using has the context of the SchedulingContext type. This class has a data method in it. As a result, we get the following construct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schedule { 
    data { 
        //... 
    } 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you have probably guessed, the data method also takes a lambda with context. However, it is a different context. Thus, we get nested structures having several contexts inside simultaneously. To get the idea of how it works, let's remove all syntactic sugar from the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; 
&lt;span class="p"&gt;})&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it's all fairly simple. Let's take a look at the invoke operator implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SchedulingContext&lt;/span&gt;&lt;span class="p"&gt;.()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nc"&gt;SchedulingContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We call the constructor for the context SchedulingContext(), and then, with the created object (&lt;em&gt;context&lt;/em&gt;), we call the lambda with the &lt;em&gt;init&lt;/em&gt; identifier that we passed as a parameter. This resembles a general function call quite a bit.&lt;/p&gt;

&lt;p&gt;As a result, in one single line — SchedulingContext().init() — we create the context and call the lambda passed to the operator. For more examples, consider the &lt;em&gt;apply&lt;/em&gt; and &lt;em&gt;with&lt;/em&gt; methods from Kotlin standard library.&lt;/p&gt;

&lt;p&gt;In the last examples, we discovered the &lt;em&gt;invoke&lt;/em&gt; operator and its combination with other tools. Next, we will focus on the tool that is formally an operator and makes the code cleaner — the &lt;em&gt;get/set methods convention&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  get/set Method Conventions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/operator-overloading.html#indexed"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When creating a DSL, we can implement a way to access maps by one or more keys. Let's look at the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;availabilityTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MONDAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; 
&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;availabilityTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MONDAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;//output: true &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to use square brackets, we need to implement the &lt;em&gt;get&lt;/em&gt; or &lt;em&gt;set&lt;/em&gt; methods (depending on what we need — read or update) with an &lt;em&gt;operator&lt;/em&gt; modifier. You can find an example of such an implementation in the &lt;em&gt;Matrix&lt;/em&gt; class on &lt;a href="https://github.com/ivan-osipov/kotlin-dsl-example"&gt;GitHub&lt;/a&gt;. It is a simple wrapper for matrix operations. Below, you can see a code snippet on the subject:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use any &lt;em&gt;get&lt;/em&gt; and &lt;em&gt;set&lt;/em&gt; parameter types, the only limit is your imagination. You are free to use one or more parameters for get/set functions to provide a convenient syntax for data access. Operators in Kotlin provide lots of interesting features that are described in the &lt;a href="https://kotlinlang.org/docs/reference/operator-overloading.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Surprisingly, there is a &lt;em&gt;Pair&lt;/em&gt; class in the Kotlin standard library. A larger part of the developer community finds &lt;em&gt;Pair&lt;/em&gt; harmful: When you use &lt;em&gt;Pair&lt;/em&gt;, the logic of linking two objects is lost, and thus it is not transparent why they are paired. The two tools I'll show you next will demonstrate how to keep the pair making sense without creating additional classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type Aliases
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/type-aliases.html"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose we need a wrapper class for a geo point with integer coordinates. Actually, we could use the Pair class, but having such a variable, we can lose the understanding of why we have paired these values.&lt;/p&gt;

&lt;p&gt;A straightforward solution is either to create a custom class or something even worse. Kotlin enriches the developer's toolkit via type aliases with the following notation:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;typealias Point = Pair&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;In fact, it is nothing but renaming a construct. Due to this approach, we don't need to create the &lt;em&gt;Point&lt;/em&gt; class anymore, as it would only duplicate the &lt;em&gt;Pair&lt;/em&gt;. Now we can create a point in this way:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val point = Point(0, 0)&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;However, the &lt;em&gt;Pair&lt;/em&gt; class has two attributes, &lt;em&gt;first&lt;/em&gt; and &lt;em&gt;second&lt;/em&gt;, that we need to rename somehow to blur any differences between the needed &lt;em&gt;Point&lt;/em&gt; and the initial &lt;em&gt;Pair&lt;/em&gt; class. For sure, we are not able to rename the attributes themselves (however, you can create &lt;a href="https://kotlinlang.org/docs/reference/extensions.html#extension-properties"&gt;extension properties&lt;/a&gt;), but there is one more notable feature in our toolkit called &lt;em&gt;destructuring declarations&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Destructuring Declarations
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/multi-declarations.html#destructuring-declarations"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's consider a simple case: Suppose we have an object of the &lt;em&gt;Point&lt;/em&gt; type that is, as we already know, just a renamed type Pair. If we look at the &lt;em&gt;Pair&lt;/em&gt; class implementation in the standard library, we'll see that it has a data modifier that directs the compiler to implement &lt;em&gt;componentN&lt;/em&gt; methods within this class. Let's learn more about it.&lt;/p&gt;

&lt;p&gt;For any class, we can define the &lt;em&gt;componentN&lt;/em&gt; operator that will be in charge of providing access to one of the object attributes. That means that calling &lt;em&gt;point.component1&lt;/em&gt; will be equal to calling &lt;em&gt;point.first&lt;/em&gt;. Why do we need such a duplication?&lt;/p&gt;

&lt;p&gt;A destructuring declaration is a means of "decomposing" an object to variables. This functionality allows us to write constructions of the following kind:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val (x, y) = Point(0, 0)&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;We can declare several variables at once, but what values will they be assigned? That's why we need the generated &lt;em&gt;componentN&lt;/em&gt; methods: Using the index starting from 1 instead of N, we can decompose an object to a set of its attributes. So, the above construct is equal to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pair&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which, in turn, is equal to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pair&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;em&gt;first&lt;/em&gt; and &lt;em&gt;second&lt;/em&gt; are the Point object attributes.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;for&lt;/em&gt; loop in Kotlin looks as follows, where x takes the values 1, 2, and 3:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;for(x in listOf(1, 2, 3)) { ... }&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;Pay attention to the assertions block in the DSL from the main example. I'll repeat a part of it for convenience:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;for ((day, lesson, student, teacher) in scheduledEvents) { ... }&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;This line should be evident. We iterate through a collection of &lt;em&gt;scheduledEvents&lt;/em&gt;, each element of which is decomposed into four attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extension Functions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/extensions.html#extensions"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding new methods to objects from third-party libraries or to the Java Collection Framework is what a lot of developers have been dreaming about. Now we have such opportunity. This is how we declare extension functions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun AvailabilityTable.monday(from: String, to: String? = null)&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;Compared to the standard method, we add the class name as a prefix to define the class we extend. In the example above, AvailabilityTable is an alias for the Matrix type and, as aliases in Kotlin are nothing but renaming, this declaration is equal to the one below, which is not always convenient:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun Matrix.monday(from: String, to: String? = null)&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;Unfortunately, there's nothing we can do here except not using the tool or adding methods only to a specific context class. In this case, the magic only appears where you need it. Moreover, you can use such functions even for extending interfaces. As a good example, the &lt;em&gt;first&lt;/em&gt; method extends any &lt;em&gt;iterable object&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun Iterable.first(): T&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;In essence, any collection based on the &lt;em&gt;Iterable&lt;/em&gt; interface, despite the element type, gets the &lt;em&gt;first&lt;/em&gt; method. It is worth mentioning that we can place an extension method in the context class and thereby have access to the extension method only in this very context (similarly to a lambda with a context). Furthermore, we can create extension functions for &lt;em&gt;Nullable&lt;/em&gt; types (the explanation of &lt;em&gt;Nullable&lt;/em&gt; types is out of the scope here, but for more details, see &lt;a href="https://kotlinlang.org/docs/reference/null-safety.html#nullable-types-and-non-null-types"&gt;this link&lt;/a&gt;). For example, that's how we can use the function &lt;em&gt;isNullOrEmpty&lt;/em&gt; from the standard Kotlin library that extends the &lt;em&gt;CharSequence&lt;/em&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;//true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is this function's signature:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun CharSequence?.isNullOrEmpty(): Boolean&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;When working with such Kotlin extension functions from Java, they are accessible as static functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infix Functions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/functions.html#infix-notation"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One more way to sugarcoat our syntax is to use infix functions. Simply said, this tool helps us to get rid of excessive code in simple cases. The assertions block from the main snippet demonstrates this tool's use case:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;teacherSchedule[day, lesson] shouldNotEqual null&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This construction is equivalent to the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;teacherSchedule[day, lesson].shouldNotEqual(null)&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;In some cases, brackets and dots can be redundant. For such cases, we can use the &lt;em&gt;infix&lt;/em&gt; modifier for functions.&lt;/p&gt;

&lt;p&gt;In the code above, the construct teacherSchedule[day, lesson] returns a schedule element, and the function shouldNotEqual checks that this element is not null.&lt;/p&gt;

&lt;p&gt;To declare an infix function, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Use the infix modifier.&lt;/li&gt;
&lt;li&gt;  Use only one parameter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combining the last two tools, we can get the code below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;infix fun  T.shouldNotEqual(expected: T)&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;Note that the generic type, by default, is an Any inheritor (not Nullable). However, in such cases, we cannot use null — that's why you should explicitly define the type Any.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Control
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-dsl-marker/index.html"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we use a lot of nested contexts, in the lower level, we risk getting a wild mix. Due to the lack of control, the following meaningless construct becomes possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//context SchedulingContext&lt;/span&gt;
    &lt;span class="nf"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//context DataContext + external context SchedulingContext&lt;/span&gt;
        &lt;span class="nf"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;//possible, as there is no context control&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before Kotlin v.1.1, there had already been a way to avoid such a mess. It lies in creating custom method data in a nested context, DataContext, and then marking it with the Deprecated annotation with the ERROR level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Deprecated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DeprecationLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Incorrect context"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataContext&lt;/span&gt;&lt;span class="p"&gt;.()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach eliminates the possibility of building an incorrect DSL. Nevertheless, a big number of methods in SchedulingContext would have made us do a lot of routine work discouraging people from any context control.&lt;/p&gt;

&lt;p&gt;Kotlin 1.1 offers a new control tool—- the @DslMarker annotation. It is applied to your own annotations, which, in turn, are used for marking your contexts. Let's create an annotation and mark it with the new tool from our toolkit:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@DslMarker annotation class MyCustomDslMarker&lt;/code&gt;    &lt;/p&gt;

&lt;p&gt;Now we need to mark up the contexts. In the main example, these are SchedulingContext and DataContext. As far as we annotate both classes with the common DSL marker, the following happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@MyCustomDslMarker&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SchedulingContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@MyCustomDslMarker&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//context SchedulingContext&lt;/span&gt;
        &lt;span class="nf"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//context DataContext + external context SchedulingContext is forbidden&lt;/span&gt;
            &lt;span class="c1"&gt;// data { } //will not compile, as contexts are annotated with the same DSL marker&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all the benefits of this cool approach saving so much time and effort, one problem still remains. Take a look at the main example, or, more precisely, to this part of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;student&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Petrov"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the third nesting level, we get the new context, Student, which is, in fact, an entity class. So we are expected to annotate part of the data model with @MyCustomDslMarker, which is incorrect in my opinion. In the Student context, the data {} calls are still forbidden, as the external DataContext is still in its place, but the following constructions remain valid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;student&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;student&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attempts to solve the problem with annotations will lead to mixing business logic and testing code, and that is certainly not the best idea. Three solutions are possible here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Using an extra context for creating a student — for example, StudentContext. This smells like madness and outweighs the benefits of @DslMarker.&lt;/li&gt;
&lt;li&gt; Creating interfaces for all entities — for example, IStudent (no matter the name), then creating stub contexts that implement these interfaces, and, finally, delegating the implementation to the student objects. That verges on madness, too.
&lt;code&gt;@MyCustomDslMarker&lt;/code&gt;
&lt;code&gt;class StudentContext(val owner: Student = Student()): IStudent by owner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Using the &lt;a class="mentioned-user" href="https://dev.to/deprecated"&gt;@deprecated&lt;/a&gt;
 annotation, as in the examples above. In this case, it looks like the best solution to use: We just add a deprecated extension method for all Identifiable objects.
&lt;code&gt;@Deprecated("Incorrect context", level = DeprecationLevel.ERROR)&lt;/code&gt;
&lt;code&gt;fun Identifiable.student(init: () -&amp;gt; Unit) {}&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To sum it up, combining various tools empowers you to build a very convenient DSL for your real-world purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cons of DSL use
&lt;/h2&gt;

&lt;p&gt;Let's try to be more objective concerning the use of DSLs in Kotlin and find the drawbacks of using DSLs in your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reuse of DSL Parts
&lt;/h3&gt;

&lt;p&gt;Imagine you have to reuse a part of your DSL. You want to take a piece of your code and make it easy to replicate. Of course, in the simplest cases with a single context, we can hide the repeatable part of a DSL in an extension function, but this will not work in most cases.&lt;/p&gt;

&lt;p&gt;Perhaps you could point me toward some better options in the comments because for now, only two solutions come to my mind: adding "named callbacks" as a part of the DSL or spawning lambdas. The second one is easier but can result in a living hell when you try to understand the call sequence. The problem is that the more imperative behavior we have, the fewer benefits remain from a DSL approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  This?! It?!
&lt;/h3&gt;

&lt;p&gt;Nothing's easier than losing the meaning of the current "this" and "it" while working with your DSL. If you use "it" as a default parameter name where it can be replaced by a meaningful name, you'd better do so. It's better to have a bit of obvious code than non-obvious bugs in it.&lt;/p&gt;

&lt;p&gt;The notion of context can confuse someone who has never faced it. Now, as you have "lambdas with receiver" in your toolkit, unexpected methods inside DSLs are less likely to appear. Just remember, in worst case, you can set the context to a variable, for example, val mainContext = this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nesting
&lt;/h3&gt;

&lt;p&gt;This issue relates closely to the first drawback in this list. The use of nested in nested in nested constructions shifts all your meaningful code to the right. Up to a certain limit, this shift may be acceptable, but when it's shifted too much, it would be reasonable to use lambdas. Of course, this will not decrease your DSL's readability, but it can be a compromise in case your DSL implies not only compact structures, but also some logic. When you create tests with a DSL (the case covered by this article), this issue is not acute, as the data is described with compact structures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Are the Docs, Lebowski?
&lt;/h3&gt;

&lt;p&gt;When you first try to cope with somebody's DSL, you will almost certainly wonder where the documentation is. On this point, I believe that if your DSL is to be used by others, usage examples will be the best docs. Documentation itself is important as an additional reference, but it is not very friendly to a reader. A domain-specific practitioner will normally start with the question "What do I call to get the result?" So in my experience, the examples of similar cases will better speak for themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We've got an overview of the tools that enable you to design your own custom domain-specific language with ease. I hope you now see how it works. Feel free to suggest more tools in the comments.&lt;/p&gt;

&lt;p&gt;It is important to remember that DSL is not a panacea. Of course, when you get such a powerful hammer, everything looks like a nail, but it isn't. Start small, create a DSL for tests, learn from your mistakes, and then, once you're more experienced, consider other usage areas.&lt;/p&gt;

&lt;h2&gt;
  
  
  About author
&lt;/h2&gt;

&lt;p&gt;I'm a software developer at Haulmont. Last year my area of responsibility was table scheduling in education. I have applied the described above technologies while developing applications based on &lt;a href="https://www.cuba-platform.com/"&gt;CUBA Platform&lt;/a&gt; Java framework. I spend free time with Spring, with Kotlin DSL for Telegram bot development and of course with my wife.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>dsl</category>
      <category>java</category>
      <category>jvm</category>
    </item>
  </channel>
</rss>
