{
 "cells": [
  {
   "cell_type": "markdown",
   "source": "* Official list of idioms: https://kotlinlang.org/docs/idioms.html\n",
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "e5U9H2j8YPqeTklThKWtLy",
     "type": "MD",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "xIF3Up82GVsiV1Ceze6Si3",
      "relativeY": 0
     }
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Preamble/Important notes\n",
    "\n",
    "* \"Syntactic sugar\" is a false concept. Each language feature affects how we use the language.\n",
    "* One can adopt different programming styles in Kotlin. Idiomatic kotlin is an unofficial combination of practices developed by experienced Kotlin users.\n",
    "* One of the key features of idiomatic kotlin is to use scopes instead of objects to provide incapsulation and limit visible mutable state.\n",
    "\n",
    "### What is idiomatic Kotlin (roughly)?\n",
    "\n",
    "* Less \"ceremony\". Pragmatic approach.\n",
    "* Hybrid object/functional paradigm (objects for data, functions for interactions).\n",
    "* Don't use mutable state wherever read-only is enough.\n",
    "* Don't use classes when functions are enough.\n",
    "* Don't use inheritance when composition is enough.\n",
    "* Function is a first-class citizen.\n",
    "* Scope is a first-class citizen.\n",
    "* Use extensions to separate inner workings from utilities.\n",
    "\n",
    "### Do not do\n",
    "\n",
    "* Scope pollution.\n",
    "* Scope function abuse.\n",
    "* Rely on initialization order."
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "ARXeE5sXcjig7Oxpa5hdTG",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## String interpolation\n",
    "\n",
    "Interpolated string allows constructing string fast"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "LVICJjSl3FQ9CWiBWDaNlp",
     "type": "MD",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "xIF3Up82GVsiV1Ceze6Si3",
      "relativeY": 6
     }
    }
   }
  },
  {
   "cell_type": "code",
   "source": "println(\"This is a plain string\")",
   "metadata": {
    "datalore": {
     "node_id": "FFW0GaV6uhemvZxlpnjpFL",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "ypTKLK2KvAZfnMbTgaVqNK",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "val arg = \"Interpolated\"\n",
    "println(\"This is an $arg string\")"
   ],
   "metadata": {
    "datalore": {
     "node_id": "ZsQ4OOCMRSSkquucGThKYh",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "qyGLHGsLl6mRCaOjpZBTD3",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "val number = 1\n",
    "\n",
    "fun increment(num: Int) = num + 1\n",
    "println(\"This is an $arg string number ${increment(number) + 1}\")"
   ],
   "metadata": {
    "datalore": {
     "node_id": "7V2Dsj0FwQaSqFJcYcWsz9",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "7tql3kbsQ9JIbbEfghi48B",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": "println(\"This is a string with \\$a\")",
   "metadata": {
    "datalore": {
     "node_id": "hm9iYlWj1B2S0469GtxDrf",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "BQz86nEWOj77fxXQ8iS47U",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "println(\n",
    "    \"\"\"\n",
    "    \\\\\\\n",
    "    This is a \n",
    "        multi\n",
    "            line\n",
    "                raw\n",
    "                    string\n",
    "\"\"\".trimIndent()\n",
    ")"
   ],
   "metadata": {
    "datalore": {
     "node_id": "h6GsBoqNfrx3k1edy3hjKZ",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "RTl3zV3tStzlLoIHSvEZiV",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": "println(\"\"\"This is a raw string number ${number + 1} with \\ and ${'$'} \"\"\")",
   "metadata": {
    "datalore": {
     "node_id": "KDL3D9lOVn6vX3iTAY50gb",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "xmBQdVRhRGLsw0t87vxQW7",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Make `val`, not `var`!\n",
    "\n",
    "`val` means read-only property\n",
    "\n",
    "`var` means writable property\n",
    "\n",
    "Unnecessary use of `var` is not recommended.\n",
    "\n",
    "**NOTE:** In performance critical cases, explicit cycles are better, but mutable state should be encapsulated."
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "mz5BUTYWXHfIAjGOyinhqi",
     "type": "MD",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "MpSiMp90k75zOtoELK5XSp",
      "relativeY": 0
     }
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/* Not recommended */\n",
    "var counter = 0\n",
    "for (i in 0..20) {\n",
    "    counter += i\n",
    "}\n",
    "counter"
   ],
   "metadata": {
    "datalore": {
     "node_id": "KyyAj8GiWSE3ZOFi2Ct8pD",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 0
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "/* recommended */\n",
    "val sum = (0..20).sum()\n",
    "sum"
   ],
   "metadata": {
    "datalore": {
     "node_id": "NKkj9bAwRFxueaMe7iiov6",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 6
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "val intArray: IntArray = IntArray(21) { it -> it + 1 }\n",
    "intArray.sum()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "icUKtPZGuhHjb95pFh77cl",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 12
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "var _a = 2\n",
    "val a: Int get() = _a\n",
    "\n",
    "println(a)\n",
    "_a = 3\n",
    "println(a)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Top level functions\n",
    "\n",
    "Don't create a class when a function is enough.\n",
    "\n",
    "Use access modifiers for incapsulation."
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "PSmFAqLCw6ko0q3IWbHk4x",
     "type": "MD",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 18
     }
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Functions could be defined everywhere in kotlin code. This is a so-called top-level function.\n",
    " */\n",
    "fun doSomething() {\n",
    "    println(\"I did it\")\n",
    "}\n",
    "\n",
    "doSomething()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "pKnOC6YRLvZ7Xj6SWth2bP",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 24
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "interface AnInterface {\n",
    "    fun doSomethingInAnObject()\n",
    "}\n",
    "\n",
    "object AnObject : AnInterface {\n",
    "    /**\n",
    "     * This is a member-function\n",
    "     */\n",
    "    override fun doSomethingInAnObject() {\n",
    "        println(\"I did it in an object\")\n",
    "    }\n",
    "}\n",
    "\n",
    "AnObject.doSomethingInAnObject()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "z1PRFmypCJbpbsxEaiVol5",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 30
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "fun doSomethingSpecial() {\n",
    "    val base = \"base\"\n",
    "    val special = \"special\"\n",
    "\n",
    "    /**\n",
    "     * This one is inside another function\n",
    "     */\n",
    "    fun String.doSomethingInside() {\n",
    "        println(\"I did $special inside another function on $this\")\n",
    "    }\n",
    "    base.doSomethingInside()\n",
    "}\n",
    "//\"ddd\".doSomethingInside()\n",
    "\n",
    "doSomethingSpecial()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "w8hub7Az3lxh78KXeq7Cpv",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 36
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "fun returnFunction(): (String) -> Unit {\n",
    "    fun printStringWithPrefix(str: String) {\n",
    "        println(\"Prefixed: $str\")\n",
    "    }\n",
    "    return ::printStringWithPrefix\n",
    "    //return { printStringWithPrefix(it) }\n",
    "    //return { println(\"Prefixed: $it\") }\n",
    "}\n",
    "\n",
    "returnFunction()(\"Haskel, Boo!\")"
   ],
   "metadata": {
    "datalore": {
     "node_id": "QxeCTOYkFSZi5tvWoUvRwU",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 42
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Unit"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "0zwWQ2uPSUrlAoyy1k0GlZ",
     "type": "MD",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 48
     }
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "fun returnUnit(): Unit {\n",
    "    // no return statement `Unit` is returned implicitly\n",
    "    val b = Unit\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "UxEwPmJN8zFnMxBiL1Kd2W",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 54
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "fun doNothing() {\n",
    "\n",
    "}\n",
    "\n",
    "val a = doNothing()\n",
    "a::class"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Default parameters"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "2ZAyWaX4qnYZefjc4US2Yj",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "fun doSomethingWithDefault(a: Int = 0, b: String = \"\") {\n",
    "    println(\"A string with a == $a and b == \\\"$b\\\"\")\n",
    "}\n",
    "\n",
    "doSomethingWithDefault()\n",
    "doSomethingWithDefault(4)\n",
    "doSomethingWithDefault(2, \"aaa\")\n",
    "doSomethingWithDefault(b = \"fff\", a = 8)\n",
    "doSomethingWithDefault(6, b = \"fff\")\n",
    "doSomethingWithDefault(a = 2, \"fff\")// don't do that"
   ],
   "metadata": {
    "datalore": {
     "node_id": "Pds7b8enkYPmA9KAaO20zI",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 60
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "fun integrate(\n",
    "    from: Double = 0.0,\n",
    "    to: Double = 1.0,\n",
    "    step: Double = 0.01,\n",
    "    function: (Double) -> Double,\n",
    "): Double {\n",
    "    require(to > from)\n",
    "    require(step > 0)\n",
    "    var sum = 0.0\n",
    "    var pos = from\n",
    "    while (pos < to) {\n",
    "        sum += function(pos)\n",
    "        pos += step\n",
    "    }\n",
    "    return sum * step\n",
    "}\n",
    "\n",
    "integrate { x ->\n",
    "    x * x + 2 * x + 1\n",
    "}\n",
    "integrate(0.0, PI) { sin(it) }\n",
    "// integrate(0.0, PI)  //error\n",
    "integrate(0.0, step = 0.02, to = PI) { sin(it) }\n",
    "//integrate(0.0, step = 0.02, PI) { sin(it) }\n",
    "\n",
    "integrate(0.0, step = 0.02, function = { sin(it) }, to = PI)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "LT2YprLmzrgVcyBo3GKilz",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "fun functionWithParameters() {\n",
    "    println(\"without default\")\n",
    "}\n",
    "\n",
    "//@JvmOverloads\n",
    "@JvmName(\"functionWithDefaultParameters\")\n",
    "fun functionWithParameters(a: Int = 2) { // don't do that\n",
    "    println(\"with default\")\n",
    "}\n",
    "\n",
    "functionWithParameters()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Function body shortcut"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "lAXRHN4vpo98h93qMABm3D",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "fun theSameAsBefore(a: Int = 0, b: String = \"\"): String = \"A string with a == $a and b == $b\"\n",
    "\n",
    "class Context(val a: String, val b: String)\n",
    "\n",
    "fun somethingWith(context: Context) = with(context) {\n",
    "    println(a + b)\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "wEpzn9oKJBKKsBDGytj92U",
     "type": "CODE",
     "hide_input_from_viewers": false,
     "hide_output_from_viewers": false,
     "report_properties": {
      "rowId": "vqa5BMfmP7oZwt8sdVLKi8",
      "relativeY": 66
     }
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Trailing lambda\n",
    "\n",
    "Scope is a separate important concept in Kotlin"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "YWQvNkVDKL8m8jqIg1bwLu",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "data class BuildResult internal constructor(val str: String, val int: Int, val optional: Double?) {\n",
    "    init {\n",
    "        require(optional != null) { \"null!\" }\n",
    "    }\n",
    "}\n",
    "\n",
    "class Builder(\n",
    "    var str: String = \"\",\n",
    "    var int: Int = 0\n",
    ") {\n",
    "    var optional: Double? = null\n",
    "\n",
    "    fun build() = BuildResult(str, int, optional)\n",
    "}\n",
    "\n",
    "fun BuildResult(defaultInt: Int, block: Builder.() -> Unit): BuildResult =\n",
    "    Builder(int = defaultInt).apply(block).build()\n",
    "\n",
    "val res = BuildResult(2) {\n",
    "    str = \"ff\"\n",
    "    optional = 1.0\n",
    "}\n",
    "\n",
    "res"
   ],
   "metadata": {
    "datalore": {
     "node_id": "0KGHAp1kvSWJaLGhdf5xk2",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Inheritance"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "qBWuWasNK9nrp0iqoE1ZPA",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "//Interfaces and objects\n",
    "\n",
    "fun interface AnInterface {\n",
    "    val a: Int\n",
    "        get() = 4\n",
    "\n",
    "    // set(value){\n",
    "    //     println(value)\n",
    "    // }\n",
    "    fun doSomething() //= println(\"From interface\")\n",
    "\n",
    "    fun doSomething2() = Unit\n",
    "}\n",
    "\n",
    "abstract class AnAbstractClass(override val a: Int) : AnInterface {\n",
    "    override final fun doSomething() = println(\"From a class\")\n",
    "    abstract fun doSomethingElse()\n",
    "}\n",
    "\n",
    "class AClass(override val a: Int) : AnInterface {\n",
    "    override fun doSomething() = println(\"From a class\")\n",
    "}\n",
    "\n",
    "class BClass(a: Int) : AnAbstractClass(a) {\n",
    "    override fun doSomethingElse() = println(\"something else\")\n",
    "}\n",
    "\n",
    "/**\n",
    " * A singleton (object) is a type (class) which have only one instance\n",
    " */\n",
    "object AnObject : AnInterface {\n",
    "    override fun doSomething(): Unit = TODO(\"Not yet implemented\")\n",
    "}\n",
    "\n",
    "/**\n",
    " * Creating an instance\n",
    " */\n",
    "val instance = AClass(3)\n",
    "\n",
    "/**\n",
    " * Using singleton reference without constructor invocation\n",
    " */\n",
    "val obj: AnInterface = AnObject\n",
    "\n",
    "/**\n",
    " * Anonymous object\n",
    " */\n",
    "val anonymous = object : AnInterface {\n",
    "    override fun doSomething(): Unit = TODO(\"Not yet implemented\")\n",
    "    override fun doSomething2(): Unit = TODO(\"Not yet implemented\")\n",
    "}\n",
    "\n",
    "val anonymous2 = AnInterface {\n",
    "    println(\"Do something\")\n",
    "}\n",
    "\n",
    "/**\n",
    " * The one that should not be named\n",
    " */\n",
    "val voldemort = object {\n",
    "    fun doSomething(): Unit = TODO()\n",
    "}\n",
    "\n",
    "// voldemort.doSomething()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "aW9cBvDwbbUsi2CBRrXDPB",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "fun interface Float64Function : (Double) -> Double {\n",
    "    override operator fun invoke(arg: Double): Double\n",
    "\n",
    "    operator fun invoke(doubles: DoubleArray): DoubleArray = DoubleArray(doubles.size) { invoke(doubles[it]) }\n",
    "}\n",
    "\n",
    "val sin = object : Float64Function {\n",
    "    override fun invoke(p1: Double): Double = sin(p1)\n",
    "}\n",
    "\n",
    "val cos = Float64Function { kotlin.math.cos(it) }\n",
    "\n",
    "val tg = Float64Function(::tan)\n",
    "\n",
    "sin(PI / 2)\n",
    "\n",
    "sin(doubleArrayOf(0.0, PI / 2))"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Declaration site variance\n",
    "\n",
    "In consumes, out produces."
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "IvTjF8aNlaknQt9252Tzwl",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "interface Producer<out T> {\n",
    "    fun produce(): T\n",
    "}\n",
    "\n",
    "interface Consumer<in T> {\n",
    "    fun consume(value: T)\n",
    "}\n",
    "\n",
    "interface Doer<T> : Producer<T>, Consumer<T> {\n",
    "\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "O0HQehHaiD0QUaFi62N6C2",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Return on when\n",
    "https://kotlinlang.org/docs/idioms.html#return-on-when-statement"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "YDCyDwHaw8LGUsRYGvgnRA",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "fun transform(color: String): Int = when (color) {\n",
    "    \"Red\" -> 0\n",
    "    \"Green\" -> 1\n",
    "    \"Blue\" -> 2\n",
    "    else -> throw IllegalArgumentException(\"Invalid color param value\")\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "fCgUSk32WDSfR1GjIKa4tH",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "fun transformIf(flag: Boolean): Int = if (flag) 1 else 0 ",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Runtime type dispatch\n",
    "\n",
    "In Java it is called DOP (Data Oriented Programming).\n",
    "\n",
    "Also, sometimes (wrongly) called pattern matching."
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "GI03Lj2Li76ORUHS53nTIx",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Matching by type\n",
    " */\n",
    "fun checkType(arg: Any): Unit = when (arg) {\n",
    "    is String -> println(\"I am a String. Length is ${arg.length}\")\n",
    "    is Int -> println(\"I am an Int.\")\n",
    "    is Double -> println(\"I am a Double\")\n",
    "    //2==2 -> println(\"Wat?\")\n",
    "    else -> println(\"I don't know who am I?\")\n",
    "}\n",
    "\n",
    "fun checkType2(arg: Any): Unit = when {\n",
    "    arg is String -> println(\"I am a String\")\n",
    "    arg is Int -> println(\"I am an Int\")\n",
    "    arg is Double -> println(\"I am a Double\")\n",
    "    2 == 2 -> println(\"Wat?\")\n",
    "    else -> println(\"I don't know who am I?\")\n",
    "}\n",
    "\n",
    "checkType(true)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "tJXxwCbGkVrfybQ0WZBOtt",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Try-catch expression\n",
    "https://kotlinlang.org/docs/idioms.html#try-catch-expression"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "f0bGwDoiIdt91b3tSeL1rn",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "fun tryCatch() {\n",
    "    val result: Int = try {\n",
    "        22\n",
    "    } catch (e: ArithmeticException) {\n",
    "        throw IllegalStateException(e)\n",
    "    } finally {\n",
    "        println(\"finally\")\n",
    "    }\n",
    "\n",
    "    // Working with result\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "qT7cCbqiG1c4Agyc9qD5I3",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "val res: Result<Int> = runCatching<Int> {\n",
    "    //error(\"Error happened\")\n",
    "    4\n",
    "}\n",
    "\n",
    "println(res.exceptionOrNull())\n",
    "(res.getOrNull() ?: 0) + 1"
   ],
   "metadata": {
    "datalore": {
     "node_id": "MslvYANHimu0ByBevtI4NY",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "val dataFlow = sequence {\n",
    "    var i = 0\n",
    "    while (true) {\n",
    "        yield(i++)\n",
    "    }\n",
    "}\n",
    "\n",
    "dataFlow.map {\n",
    "    runCatching {\n",
    "        if (it % 2 == 0) error(\"Even: $it\") else it\n",
    "    }\n",
    "}.take(10).toList().joinToString(separator = \"\\n\")"
   ],
   "metadata": {
    "datalore": {
     "node_id": "4B3Hw7znY3cEDxBmytUJCV",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Nothing"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "cXeTiH13nXoPhTXZLkRnLj",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * The declaration if valid because [TODO] returns Nothing\n",
    " */\n",
    "fun getSomething(): Int? = TODO()\n",
    "\n",
    "fun findSomething(): Int {\n",
    "    // early return is valid because `return` operator result is Nothing\n",
    "    val found: Int = getSomething() ?: return 2\n",
    "    return found + 2\n",
    "}\n",
    "\n",
    "//FIXME don't do that\n",
    "fun dontDoThat() {\n",
    "    if (true) return\n",
    "    println(false)\n",
    "}\n",
    "\n",
    "fun checkCondition(): Int {\n",
    "    fun conditionSatisfied() = false\n",
    "\n",
    "    return if (conditionSatisfied()) {\n",
    "        1\n",
    "    } else {\n",
    "        //error is Nothing\n",
    "        error(\"Condition is not satisfied\")\n",
    "    }\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "h11q8FWGKYIcuFOnFOLmBl",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "fun loop(block: () -> Unit): Nothing {\n",
    "    while (true) {\n",
    "        block()\n",
    "    }\n",
    "}"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Data class"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "vOQiEaU7CW3kIB3K4W2hEK",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "class SimpleClass(val a: Int, val b: Double, c: Double) {\n",
    "    override fun toString() = \"SimpleClass(a=$a, b=$b)\"\n",
    "}\n",
    "\n",
    "\n",
    "data class DataClass(val a: Int, var b: Double /*, d: Double */) {\n",
    "    init {\n",
    "        require(b >= 0) { \"B should be positive\" }\n",
    "    }\n",
    "\n",
    "    val c get() = b + 1\n",
    "}\n",
    "\n",
    "val simple = SimpleClass(1, 2.0, 3.0)\n",
    "\n",
    "println(simple)\n",
    "\n",
    "val data = DataClass(2, 2.0)\n",
    "val copy = data.copy(b = 22.2)\n",
    "println(copy)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "B7unRz7w7U8OhXejJeFspj",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Nullable truth"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "clBRddjfvKnMe2EMSmDhLd",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Nullable truth.\n",
    " */\n",
    "fun nullableTruth() {\n",
    "    class A(val b: Boolean?)\n",
    "\n",
    "    val a: A? = A(null) // Compilator warning here\n",
    "    //use\n",
    "    a?.b == true\n",
    "    //instead of\n",
    "    a?.b ?: false\n",
    "\n",
    "    // The old way\n",
    "    val res = if (a == null) {\n",
    "        false\n",
    "    } else {\n",
    "        if (a.b == null) {\n",
    "            false\n",
    "        } else {\n",
    "            a.b\n",
    "        }\n",
    "    }\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "5BN3u1gHkSamtLIJiQicsV",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "import java.util.Optional\n",
    "import kotlin.reflect.typeOf\n",
    "\n",
    "println(typeOf<Optional<Boolean>>() == typeOf<Optional<Optional<Boolean>>>())\n",
    "\n",
    "println(typeOf<Boolean?>() == typeOf<Boolean??>())"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "mapOf<String, String>().get(\"f\")!!",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Safe call"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "5wCQZq5qasoVCldxVSxxBK",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "import java.io.File\n",
    "\n",
    "/**\n",
    " * Safe call and elvis operator\n",
    " */\n",
    "fun idiom12() {\n",
    "    val files = File(\"Test\").listFiles()\n",
    "    println(files?.size ?: \"empty\")\n",
    "}\n",
    "idiom12()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "v4cP31zyrmBkHP7lnYZWN0",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "fun printNotNull(any: Any) = println(any)\n",
    "\n",
    "// printNotNull(null) does not work\n",
    "\n",
    "val value: Int? = 2\n",
    "//val value: Int? by lazy { 2 }\n",
    "\n",
    "//printNotNull(value) // Error\n",
    "if (value != null) {\n",
    "    //not guaranteed to work with mutable variable\n",
    "    printNotNull(value)\n",
    "}\n",
    "\n",
    "var value1: Int? = 2\n",
    "\n",
    "// Safe call here\n",
    "value1?.let {\n",
    "    printNotNull(it) // execute this block if not null\n",
    "    //printNotNull(value1) // value is not null here\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "hGZ9h4H8TaYZefCkAmP3Gd",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Nullable assignment"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "hzXkbfAThQ4cKtdGYuLejZ",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Dart-like (?=) nullable assignment\n",
    " */\n",
    "fun idiom11() {\n",
    "    var x: String? = null\n",
    "    x = x ?: \"Hello\"\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "di2EXkn35CFEja9KMK1Ur5",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Extension functions"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "aC24azwiFpZfA2v3umRb7p",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Extension function on a String. It is not monkey-patching.\n",
    " */\n",
    "fun String.countOs(): Int = count { it == 'ы' } // implicit this points to String\n",
    "\n",
    "fun Int.printMe() = println(this) // explicit this\n",
    "\n",
    "fun Any?.doSomething(): Int = TODO(\"Don't do that\")\n",
    "\n",
    "fun ((Int) -> Int).evalAndIncrement(): (Int) -> Int = { this.invoke(it) + 1 }\n",
    "\n",
    "// val intFunction: (Int)->Int = {it -1}\n",
    "\n",
    "// val modifiedFunction = intFunction.evalAndIncrement()\n",
    "\n",
    "// println(modifiedFunction(0))\n",
    "\n",
    "\"вылысыпыдыстычка\".countOs().printMe()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "li65OumXRClbEIwURW9DEE",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "infix fun <T : Comparable<T>> ClosedRange<T>.intersect(other: ClosedRange<T>): ClosedRange<T>? {\n",
    "    val start = maxOf(this.start, other.start)\n",
    "    val end = minOf(this.endInclusive, other.endInclusive)\n",
    "    return if (end >= start) start..end else null\n",
    "}\n",
    "\n",
    "(0..8).intersect(6..12)\n",
    "0..8 intersect 6..12"
   ],
   "metadata": {
    "datalore": {
     "node_id": "cyD7D8tmZJex8pJ3NsufHN",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "0.0..8.0 intersect 2.9..6.1",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "fun List<String>.concat() = joinToString(separator = \"\")\n",
    "listOf(\"a\", \"b\", \"c\").concat()\n",
    "listOf(1, 2, 3).concat()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "tnCskYd7474gKZiYnPHlx4",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "val functionWithReciever: List<String>.(arg: Int) -> Unit = { arg ->\n",
    "    println(get(arg))\n",
    "}\n",
    "\n",
    "listOf(\"1\", \"2\", \"3\").functionWithReciever(1)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Extension properties\n",
    "\n",
    "Remember [property usage guidelines](https://kotlinlang.org/docs/coding-conventions.html#functions-vs-properties)."
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "pJTxzy4MfR710OowVbvf6s",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Extension property (must be virtual)\n",
    " */\n",
    "val List<Number>.odd get() = filter { it.toInt() % 2 == 1 }\n",
    "\n",
    "List(10) { it }.odd"
   ],
   "metadata": {
    "datalore": {
     "node_id": "L7qpVNVtW0Fh6dMX4pR3il",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "var MutableMap<String, String>.a: String?\n",
    "    get() = this.get(\"a\")\n",
    "    set(value) {\n",
    "        if (value == null) {\n",
    "            this.remove(\"a\")\n",
    "        } else {\n",
    "            this.set(\"a\", value)\n",
    "        }\n",
    "    }\n",
    "\n",
    "val map = mutableMapOf(\n",
    "    \"a\" to \"a\",\n",
    "    \"b\" to \"b\"\n",
    ")\n",
    "val map2 = mutableMapOf(\n",
    "    Pair(\"a\", \"a\"),\n",
    "    Pair(\"b\", \"b\")\n",
    ")\n",
    "\n",
    "map.a = \"6\"\n",
    "\n",
    "map.a"
   ],
   "metadata": {
    "datalore": {
     "node_id": "9DG1gyyYvzjbg0EZFfP5Qo",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Extension variable (also must be virtual)\n",
    " */\n",
    "var Array<Int>.second: Int\n",
    "    get() = this[1]\n",
    "    set(value) {\n",
    "        this[1] = value\n",
    "    }\n",
    "\n",
    "\n",
    "val array = Array(5) { it }\n",
    "array.second = 9\n",
    "array"
   ],
   "metadata": {
    "datalore": {
     "node_id": "hAjUSxhPqTgmnz9WQYXg3U",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Scope functions (run, with, let)"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "Ziq72FmnnYUYPMy4CamsQ0",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "object AClass {\n",
    "    val a = \"a\"\n",
    "    val b = \"b\"\n",
    "    val c = \"c\"\n",
    "}\n",
    "\n",
    "fun getAClass(): AClass? = null\n",
    "\n",
    "/**\n",
    " * [with]/[run]/[let] are used to create a scope with given argument or receiver\n",
    " */\n",
    "\n",
    "\n",
    "// Simple print of AClass\n",
    "println(\"a = ${AClass.a}, b = ${AClass.b}, c = ${AClass.c}\")\n",
    "\n",
    "// Using `with`\n",
    "val res = with(AClass) {\n",
    "    // AClass type is the receiver in this scope\n",
    "    println(\"a = ${this.a}, b = $b, c = $c\")\n",
    "    /*return@with*/ \"some value\"\n",
    "}\n",
    "\n",
    "res"
   ],
   "metadata": {
    "datalore": {
     "node_id": "7wtXhm3FeLejbPp7NEWiz2",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "object AContext {\n",
    "    fun AClass.abc() = a + b + c // warning additional concatenation\n",
    "}\n",
    "\n",
    "fun printAbc(aClass: AClass) = with(AContext) {\n",
    "    aClass.abc()\n",
    "}"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "//using `run`\n",
    "getAClass()?.takeIf { it.a.isNotEmpty() }?.run {\n",
    "    // the same as above\n",
    "    println(\"a = $a, b= $b, c = $c\")\n",
    "    2\n",
    "}\n",
    "\n",
    "val runResult: Int = run {\n",
    "\n",
    "}\n",
    "\n",
    "//Using `let` to compose result. Not recommended using without a need\n",
    "val letResult = getAClass()?.let { arg ->\n",
    "    arg.c + arg.a\n",
    "}\n"
   ],
   "metadata": {
    "datalore": {
     "node_id": "aJGJ3ukmhCchnZwJEzLV3K",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "//Don't do that\n",
    "fun scopeAbuse(str: String?) =\n",
    "    str.takeIf { it?.isNotEmpty() == true }?.let { it.substring(0..4) }?.let { it.matches(\".*\".toRegex()) }\n",
    "\n",
    "fun withoutAbuse(str: String?): Boolean? = if (str?.isNotEmpty() == true) {\n",
    "    val substring = str.substring(0..4)\n",
    "    substring.matches(\".*\".toRegex())\n",
    "} else {\n",
    "    null\n",
    "}"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Scope functions (also, apply)"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "r6VfHIkDTBDCIotqNCslOH",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Using apply/also to add a finalizing action\n",
    " */\n",
    "var i = 2\n",
    "\n",
    "/**\n",
    " * [also] block does not affect the result\n",
    " */\n",
    "fun getAndIncrement() = i.also { i += 1 } //don't do that\n",
    "\n",
    "fun incrementAndPring(arg: Int) = (arg + 1).also{\n",
    "    println(it)\n",
    "}\n",
    "\n",
    "println(getAndIncrement())\n",
    "println(i)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "c0kY56DJne2lbwGShOgur6",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "class Rectangle {\n",
    "    var length: Number = 0\n",
    "    var breadth: Number = 0\n",
    "    var color: Int = 0xffffff\n",
    "}\n",
    "\n",
    "/**\n",
    " * Configure properties of an object (apply)\n",
    " * https://kotlinlang.org/docs/idioms.html#configure-properties-of-an-object-apply\n",
    " */\n",
    "val myRectangle = Rectangle().apply {\n",
    "    length = 4\n",
    "    breadth = 5\n",
    "    color = 0xFAFAFA\n",
    "}\n",
    "\n",
    "fun Rectangle(block: Rectangle.() -> Unit): Rectangle = Rectangle().apply(block)\n",
    "\n",
    "val myRectangle2 = Rectangle {\n",
    "    length = 4\n",
    "    breadth = 5\n",
    "    color = 0xFAFAFA\n",
    "}\n",
    "\n",
    "fun Rectangle(length: Number) = Rectangle().apply { this.length = length }\n",
    "\n",
    "Rectangle(8)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "m9HH2IzTy1dbYkBRUeFjh9",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Lists\n",
    "\n",
    "Do not cast List to MutableList!"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "lMgnCCxkRhs62cgTQN5eDK",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Lists and mutable lists\n",
    " */\n",
    "\n",
    "\n",
    "/**\n",
    " * This method creates a read-only list of strings. One should note that the type of the list is not specified\n",
    " */\n",
    "val list: List<String> = listOf(\"a\", \"b\", \"c\")\n",
    "\n",
    "println(list[0])\n",
    "println(list.get(1))\n",
    "//println(list.get(4))\n",
    "println(list.getOrNull(4) ?: \"nothing\")\n",
    "list::class"
   ],
   "metadata": {
    "datalore": {
     "node_id": "pP9PTSy6IXeTC6HITFtBoR",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * This one creates a mutable list\n",
    " */\n",
    "val mutableList: MutableList<String> = mutableListOf(\"a\", \"b\", \"c\")\n",
    "mutableList[2] = \"d\"\n",
    "mutableList.add(\"e\")\n",
    "mutableList += \"f\"\n",
    "mutableList"
   ],
   "metadata": {
    "datalore": {
     "node_id": "Kx565m7VjuF2RncqW7gw2i",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "//don't do that ever\n",
    "fun doBadThingWithList(list: List<String>): List<String> = (list as MutableList<String>).apply { add(\"something\") }\n",
    "\n",
    "doBadThingWithList(listOf(\"a\", \"b\", \"c\"))"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "listOf(\"a\")::class"
   ],
   "metadata": {
    "datalore": {
     "node_id": "zKxwfvdRQwsgqRxK5GPTIK",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "val mutableList = mutableListOf(1, 2, 3)\n",
    "\n",
    "fun consumeList(list: List<Int>) {\n",
    "    println(list.joinToString())\n",
    "}\n",
    "consumeList(mutableList)\n",
    "mutableList.add(4)\n",
    "consumeList(mutableList)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "listOf(1, 2) + listOf(3, 4)",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "var roList = listOf(\"a\", \"b\")\n",
    "roList += setOf(\"c\")\n",
    "roList"
   ],
   "metadata": {
    "datalore": {
     "node_id": "yK6QD0dvrT98t7dx0pWJ5s",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "val writableList = mutableListOf(\"a\", \"b\") // Warning!\n",
    "writableList += setOf(\"c\")\n",
    "writableList"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * This one creates a mutable ArrayList.\n",
    " */\n",
    "val arrayList: ArrayList<String> = arrayListOf(\"a\", \"b\", \"c\")\n",
    "\n",
    "//ArrayList<Int>()\n",
    "\n",
    "//Danger zone\n",
    "//\n",
    "//val newList: List<String> = list + \"f\" + mutableList\n",
    "//\n",
    "//println(newList)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "qSaaZGyHiH9dsL4dtQ8UyE",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "//Bonus\n",
    "\n",
    "val lambdaList = List(3) { it.toString() }\n",
    "println(lambdaList)\n",
    "\n",
    "val builderList: List<Int> = buildList {\n",
    "    add(2)\n",
    "    add(8)\n",
    "    remove(8)\n",
    "}\n",
    "\n",
    "builderList"
   ],
   "metadata": {
    "datalore": {
     "node_id": "JPSYaCAgOZRveNdFPO15SG",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "// val sequentialList = List(20){it}\n",
    "// sequentialList.zipWithNext{ l, r -> r - l }.forEach{println(it)}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "fQBhhTBHCdc9JkWiMZ6uEh",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Shortcut collection builders"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "rePWgKfjyysV69ubD4fWAR",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Use shortcut function to provide default values\n",
    " */\n",
    "fun doSomething(additionalArguments: List<String> = emptyList()) {\n",
    "    TODO()\n",
    "    emptyArray<String>()\n",
    "    emptySet<String>()\n",
    "    emptyMap<String, String>()\n",
    "}\n",
    "emptyList<String>()::class"
   ],
   "metadata": {
    "datalore": {
     "node_id": "F5RQ5108YJe3pzfN0eAWwm",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Maps"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "TSOQN81tDBKM3Z3oUOHGom",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "val map = mutableMapOf(\n",
    "    \"key\" to \"a\",\n",
    "    \"key2\" to \"b\",\n",
    ")\n",
    "\n",
    "//The map could be accessed via indexing operation\n",
    "println(map::class)\n",
    "println(map[\"key\"])\n",
    "map[\"key\"] = \"fff\"\n",
    "println(map[\"key\"])\n",
    "println(map[\"key3\"])"
   ],
   "metadata": {
    "datalore": {
     "node_id": "cZd2JPB72uAfnx1o8AYjOs",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "//val entry: MutableMap.MutableEntry<String, String> = map.iterator().next()\n",
    "\n",
    "//map.entries.first().component2()\n",
    "\n",
    "/**\n",
    " * The destructuring declaration for maps and other objects that support `operator fun componentN`\n",
    " */\n",
    "for ((k: String, v) in map) {\n",
    "//val (k, v) = entry\n",
    "//        val k = entry.component1()\n",
    "//        val v = entry.component2()\n",
    "    println(\"$k -> $v\")\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "hRuaLFdpTsdnt7lYKL2nbN",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "map.forEach { (k, v) -> println(\"$k -> $v\") }\n",
    "\n",
    "// java version\n",
    "map.forEach { k, v -> println(\"$k -> $v\") }"
   ],
   "metadata": {
    "datalore": {
     "node_id": "s1Q65aNWb9YNBZOgxmjotW",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "val (a, b) = Pair(1, 2)\n",
    "\n",
    "val coord = doubleArrayOf(0.0, 1.0, 2.0)\n",
    "\n",
    "val (x, y, z) = coord\n",
    "\n",
    "data class Coordinate(val x: Double, val y: Int)\n",
    "\n",
    "val (x1, y1) = Coordinate(1.0, 2)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "t8YITxVsoTt7o9KnnOvO0Z",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Mutable type access decorator\n",
    "\n",
    "To be replaced with qualified getter types soon"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "Ec2mbBaydQnVsjaiThy2rn",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "class AClassWithList {\n",
    "    var b: Double = 2.0\n",
    "        private set\n",
    "\n",
    "    init {\n",
    "        b = 5.0\n",
    "    }\n",
    "\n",
    "    private val _list: MutableList<Int> = ArrayList<Int>()\n",
    "    val list: List<Int> get() = _list\n",
    "\n",
    "    fun add(int: Int) {\n",
    "        require(int > 0)\n",
    "        _list.add(int)\n",
    "    }\n",
    "}\n",
    "\n",
    "\n",
    "val obj = AClassWithList()\n",
    "\n",
    "// obj.b = 10.0 //error\n",
    "obj.add(42)\n",
    "obj.list.add(43)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "H8VTPpGlV0VwsHL4Q8lJF9",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": "## Wrap mutable logic / Kotlin builder pattern",
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "k1eHOcIZbnHDJ8g7ZusArx",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "val list = buildList {\n",
    "    repeat(10) {\n",
    "        add(it)\n",
    "    }\n",
    "}\n",
    "println(list)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "pJfVynao7enb7Q07lJRGRl",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "data class ImmutableObject(val a: String, val b: String, val c: Int)\n",
    "\n",
    "class ImmutableObjectBuilder(a: String) {\n",
    "    var a: String = a\n",
    "    var b: String = \"\"\n",
    "    var c = 0\n",
    "\n",
    "    fun build() = ImmutableObject(a, b, c)\n",
    "}\n",
    "\n",
    "/*inline*/ fun ImmutableObject(a: String, block: ImmutableObjectBuilder.() -> Unit): ImmutableObject =\n",
    "    ImmutableObjectBuilder(a).apply(block).build()\n",
    "\n",
    "ImmutableObject(\"aValue\") {\n",
    "    c = 99\n",
    "}"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "GKoCVcgdnSYPjsNCAJIkBB",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "markdown",
   "source": "## Contains operator and ranges"
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "4mh1Lg6g8OWEIC1Qjgp9tN",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "code",
   "source": [
    "val emailsList = emptyList<String>()\n",
    "\n",
    "// When used directly infix in operator checks if the element is contained in a collection\n",
    "//using `operator fun contains`\n",
    "\n",
    "if (\"john@example.com\" in emailsList) {\n",
    "    println(\"is in list\")\n",
    "}\n",
    "\n",
    "if (\"jane@example.com\" !in emailsList) {\n",
    "    println(\"not in list\")\n",
    "}"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "1N4A00CAksn2nVg57DRKnp",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "code",
   "source": [
    "import java.time.*\n",
    "\n",
    "class DateRange(val start: Instant, val end: Instant)\n",
    "\n",
    "operator fun DateRange.contains(value: Instant): Boolean = value > start && value < end\n",
    "\n",
    "\n",
    "println(Instant.now() in DateRange(Instant.EPOCH, Instant.MAX))"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "hwJfUD7H5mDtjStAsGppk7",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "code",
   "source": [
    "// Another (different) use of `in` is iteration over range or collection using\n",
    "// using `operator fun iterator`\n",
    "\n",
    "for (i in 1..100) {\n",
    "    println(i)\n",
    "}  // closed range: includes 100\n",
    "\n",
    "(1..100).forEach { i ->\n",
    "    println(i)\n",
    "} //the same, but with boxing\n",
    "\n",
    "for (i in 1 ..< 100) {\n",
    "    println(i)\n",
    "} // half-open range: does not include 100\n",
    "\n",
    "for (x in 2..10 step 2) {\n",
    "    println(x)\n",
    "}\n",
    "\n",
    "for (x in 10 downTo 1) {\n",
    "    println(x)\n",
    "}\n",
    "\n",
    "infix fun ClosedRange<Double>.step(step: Double): Sequence<Double> {\n",
    "    //TODO check arguments\n",
    "    var current = start\n",
    "    return sequence {\n",
    "        do {\n",
    "            yield(current)\n",
    "            current += step\n",
    "        } while (current <= endInclusive)\n",
    "    }\n",
    "}\n",
    "\n",
    "for (x in 0.0..10.0 step 0.5) {\n",
    "    println(x)\n",
    "}"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "IsJiqd43JpY7BnZTeHNU4M",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "markdown",
   "source": "## Map-reduce"
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "KKT62bidVYF8I147heptAS",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "code",
   "source": [
    "val list: List<Int> = listOf(1, 2, 3, 4, 5, 6)\n",
    "\n",
    "val result = list\n",
    "    //.stream().parallel()\n",
    "    //.asSequence()\n",
    "    .filter { it % 2 == 0 } //select even numbers\n",
    "    .map { it * it } // get square of each element\n",
    "    //.onEach { println(it) }\n",
    "    //.sumOf { it } //use one of reduce operations\n",
    "    .reduce { acc: Int, i: Int -> acc + i }\n",
    "    //.fold(0.0) { acc: Double, i: Int -> acc + i }\n",
    "\n",
    "result"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {
    "datalore": {
     "node_id": "9qcw7ejFSF8QnAGdf1bAI0",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "cell_type": "code",
   "source": [
    "val sequence = sequence {\n",
    "    var counter = 1\n",
    "    while (true) {\n",
    "        yield(counter++)\n",
    "        yield(counter++)\n",
    "        // println(counter)\n",
    "    }\n",
    "}\n",
    "\n",
    "val result = sequence\n",
    "    .take(6)\n",
    "    .filter { it % 2 == 0 } //select even numbers\n",
    "    .map { it * it } // get square of each element\n",
    "    //.onEach { println(it) }\n",
    "    //.sumOf { it } //use one of reduce operations\n",
    "    .reduce { acc: Int, i: Int -> acc + i }\n",
    "\n",
    "result"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Scoped resource usage"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "ovz77VglMntuRrJ1uMtSEG",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "import java.nio.file.*\n",
    "\n",
    "\n",
    "val stream = Files.newInputStream(Paths.get(\"file.txt\"))\n",
    "// The resource is automatically closed  when leaving the scope\n",
    "stream.bufferedReader().use { reader ->\n",
    "    println(reader.readText())\n",
    "}"
   ],
   "metadata": {
    "datalore": {
     "node_id": "XIX7lDFJ0UiyiJAY4c3Oby",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Factory as parameter and companion factories"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "MizpHzkgkV5TzoM9HFS2zM",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "interface Factory<T : Any> {\n",
    "    fun build(str: String): T\n",
    "}\n",
    "\n",
    "data class IntContainer(val arg: Int) {\n",
    "\n",
    "    companion object : Factory<IntContainer> {\n",
    "        override fun build(str: String) = IntContainer(str.toInt())\n",
    "\n",
    "        fun buildSpecial(str: String) = IntContainer(str.toInt())\n",
    "    }\n",
    "}\n",
    "\n",
    "data class DoubleContainer(val arg: Double) {\n",
    "\n",
    "    companion object : Factory<DoubleContainer> {\n",
    "        override fun build(str: String) = DoubleContainer(str.toDouble())\n",
    "    }\n",
    "}\n",
    "\n",
    "fun <T : Any> buildContainer(str: String, factory: Factory<T>): T = factory.build(str)\n",
    "\n",
    "\n",
    "buildContainer(\"22\", IntContainer)\n"
   ],
   "metadata": {
    "datalore": {
     "node_id": "TAnNAjBb2Rc1RRTTICVuZg",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Initialization"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "l8Zp9Da24jvCFJd28sDNFj",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "open class Bad {\n",
    "    val value: Int = requestValue()\n",
    "\n",
    "    open fun requestValue(): Int {\n",
    "        doSomethingElse()\n",
    "        return 2\n",
    "    }\n",
    "\n",
    "    private fun doSomethingElse() {\n",
    "        println(value)\n",
    "    }\n",
    "}\n",
    "\n",
    "Bad()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "xZWJjxthdbhrVOMYfed6UV",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "class BadString {\n",
    "    val value: String = requestValue()\n",
    "\n",
    "    fun requestValue(): String {\n",
    "        doSomethingElse()\n",
    "        return \"2\"\n",
    "    }\n",
    "\n",
    "    private fun doSomethingElse() {\n",
    "        println(value)\n",
    "    }\n",
    "}\n",
    "\n",
    "BadString()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "//Factory functions are preferred to the initialization logic\n",
    "\n",
    "data class Good internal constructor(val value: Int) {\n",
    "    init {\n",
    "        //Initialization block is there to check arguments\n",
    "        require(value >= 0)\n",
    "    }\n",
    "\n",
    "    companion object\n",
    "}\n",
    "\n",
    "private fun requestValue(): Int = TODO()\n",
    "\n",
    "// This is the factory-function\n",
    "fun Good(): Good = Good(requestValue())\n",
    "\n",
    "// additional constructor-like builders could be added to the companion\n",
    "\n",
    "@OptIn(ExperimentalUnsignedTypes::class)\n",
    "fun Good.Companion.build(value: UInt) = Good(value.toInt())\n",
    "\n",
    "Good.build(32U)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "2oRxs51NNlsoJD7UIx3exC",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Delegates"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "jvl9An4EkBkWd9B1JX4ju9",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "class ClassWithALazyProperty {\n",
    "    //Use lazy delegate for something that should be calculated ones on first call\n",
    "    val lazyValue by lazy {\n",
    "        //Do dome heavy logic here\n",
    "        println(\"Initialized\")\n",
    "        22\n",
    "    }\n",
    "\n",
    "    val getterValue: Int\n",
    "        get() {\n",
    "            println(\"got\")\n",
    "            return 33\n",
    "        }\n",
    "}\n",
    "\n",
    "val lazyClass = ClassWithALazyProperty()\n",
    "println(lazyClass.lazyValue)\n",
    "println(lazyClass.lazyValue)\n",
    "println(lazyClass.getterValue)\n",
    "println(lazyClass.getterValue)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "CqN0VKctxRWd4N4RrKC90M",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "//Using other delegates\n",
    "val map = mutableMapOf(\"a\" to 1, \"b\" to 2)\n",
    "\n",
    "var a: Int by map\n",
    "\n",
    "println(a)\n",
    "a = 3\n",
    "println(map)"
   ],
   "metadata": {
    "datalore": {
     "node_id": "TYw8wCso8aGvqvd2XviRcH",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Inline functions"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "OkBtMlEkvfaglVXzlzq5dU",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Definition of inline function\n",
    " */\n",
    "inline fun List<Int>.forEachOdd(block: (Int) -> Unit) = forEach {\n",
    "    if (it % 2 == 1) block(it)\n",
    "}\n",
    "\n",
    "\n",
    "/**\n",
    " * The demonstration of use of inline [forEach] function with non-local return\n",
    " */\n",
    "fun foo(): Int {\n",
    "    listOf(1, 2, 3, 4, 5).forEachOdd {\n",
    "        if (it == 3) return it // non-local return directly to the caller of foo()\n",
    "        print(\"$it, \")\n",
    "    }\n",
    "    println(\"this point is unreachable\")\n",
    "    return 0\n",
    "}\n",
    "foo()"
   ],
   "metadata": {
    "datalore": {
     "node_id": "kz2Dq5cDNhfbfgI6mXv5yU",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Using inline function for type reification during the compile time\n",
    " */\n",
    "inline fun <reified T> List<T>.prettyPrint() = forEach {\n",
    "    when (T::class) {\n",
    "        Double::class -> println(\"Double: ${it as Double}\")\n",
    "        Int::class -> println(\"Int: ${it as Int}\")\n",
    "        else -> it.toString()\n",
    "    }\n",
    "}\n",
    "\n",
    "inline fun <reified T> prettyPrintOne(arg: T) = listOf(arg).prettyPrint()\n",
    "\n",
    "listOf(1, 2, 3).prettyPrint()\n",
    "\n",
    "/**\n",
    " * **WARNING** inline functions are an advanced feature and should be used only for\n",
    " * reification or non-local return\n",
    " * NOT for optimization.\n",
    " */"
   ],
   "metadata": {
    "datalore": {
     "node_id": "drMX3vZ5PBfpBXhCZM1zc5",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Collections and boxing"
   ],
   "attachments": {},
   "metadata": {
    "datalore": {
     "node_id": "6I3SqcgBGWPqpKZRhNDfAM",
     "type": "MD",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   }
  },
  {
   "cell_type": "code",
   "source": [
    "/**\n",
    " * Values are boxed. Each call is indirect\n",
    " */\n",
    "val list: List<Double> = List(20) { it.toDouble() }\n",
    "\n",
    "/**\n",
    " * Still boxed\n",
    " */\n",
    "val genericArray: Array<Double> = Array(20) { it.toDouble() }\n",
    "\n",
    "/**\n",
    " * Non-boxed\n",
    " */\n",
    "val specializedArray: DoubleArray = DoubleArray(20) { it.toDouble() }"
   ],
   "metadata": {
    "datalore": {
     "node_id": "ieHZ3zzSufTtNWM11pIuh1",
     "type": "CODE",
     "hide_input_from_viewers": true,
     "hide_output_from_viewers": true
    }
   },
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "",
   "outputs": [],
   "execution_count": null
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Kotlin",
   "language": "kotlin",
   "name": "kotlin"
  },
  "datalore": {
   "computation_mode": "JUPYTER",
   "package_manager": "pip",
   "base_environment": "default",
   "packages": [],
   "report_row_ids": [
    "xIF3Up82GVsiV1Ceze6Si3",
    "ypTKLK2KvAZfnMbTgaVqNK",
    "qyGLHGsLl6mRCaOjpZBTD3",
    "7tql3kbsQ9JIbbEfghi48B",
    "BQz86nEWOj77fxXQ8iS47U",
    "RTl3zV3tStzlLoIHSvEZiV",
    "xmBQdVRhRGLsw0t87vxQW7",
    "MpSiMp90k75zOtoELK5XSp",
    "vqa5BMfmP7oZwt8sdVLKi8"
   ],
   "report_link": "https://datalore.jetbrains.com/report/ptQDfQAcrjNxzIO0AEqovZ/VXj2xqMTETu24Qra9ydiLo",
   "version": 3
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}