From d0d8e89c626708f33df186059c432c3db01314a1 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 6 Aug 2024 09:38:15 +0300 Subject: [PATCH] 2024 update --- build.gradle.kts | 14 +- gradle/wrapper/gradle-wrapper.properties | 2 +- notebooks/Idioms.ipynb | 2439 ++++++++++++++++++++++ notebooks/Types.ipynb | 192 ++ settings.gradle.kts | 2 +- 5 files changed, 2639 insertions(+), 10 deletions(-) create mode 100644 notebooks/Idioms.ipynb create mode 100644 notebooks/Types.ipynb diff --git a/build.gradle.kts b/build.gradle.kts index 9f3ad0a..e579e0e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - kotlin("jvm") version "1.6.10" + kotlin("jvm") version "2.0.0" } -group = "ru.mipt.npm" +group = "center.sciprog" version = "1.0" // Where to get dependencies @@ -12,12 +12,11 @@ repositories { dependencies { //loading coroutines - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") //testing libraries testImplementation(kotlin("test-junit5")) - testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3") } // Load testing platform @@ -25,7 +24,6 @@ tasks.test { useJUnitPlatform() } -// Set a byte-code target for JVM -tasks.withType { - kotlinOptions.jvmTarget = "11" +kotlin{ + jvmToolchain(11) } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d913..070cb70 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/notebooks/Idioms.ipynb b/notebooks/Idioms.ipynb new file mode 100644 index 0000000..a8ed4ea --- /dev/null +++ b/notebooks/Idioms.ipynb @@ -0,0 +1,2439 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "* Official list of idioms: https://kotlinlang.org/docs/idioms.html\n", + "\n", + "* Original repository: https://code.mipt.ru/SPC/education/ks-materials" + ], + "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." + ], + "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 \\$\")" + ], + "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", + " This is a \n", + " multi\n", + " line\n", + " raw\n", + " string\n", + "\"\"\".trimIndent())" + ], + "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 }\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 + }, + { + "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": [ + "\n", + "object AnObject{\n", + " /**\n", + " * This is a member-function\n", + " */\n", + " 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 special = \"special\"\n", + " /**\n", + " * This one is inside another function\n", + " */\n", + " fun doSomethingInside(){\n", + " println(\"I did $special inside another function\")\n", + " }\n", + " doSomethingInside()\n", + "}\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": [ + "\n", + "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 + }, + { + "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(2, \"aaa\")\n", + "doSomethingWithDefault(b = \"fff\", a = 8)\n", + "doSomethingWithDefault(4, 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, step = 0.02, to = PI) { sin(it) }\n", + "//integrate(0.0, step = 0.02, PI) { sin(it) }" + ], + "metadata": { + "datalore": { + "node_id": "LT2YprLmzrgVcyBo3GKilz", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "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(val str: String, val int: Int)\n", + "\n", + "class Builder(var str: String = \"\", var int: Int = 0){\n", + " fun build() = BuildResult(str, int)\n", + "}\n", + "\n", + "fun doWithBuilder(defaultInt: Int, block: Builder.() -> Unit): BuildResult = \n", + " Builder(int = defaultInt).apply(block).build()\n", + "\n", + "doWithBuilder(2){\n", + " str = \"ff\"\n", + "}" + ], + "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", + "interface AnInterface {\n", + " val a: Int\n", + " get() = 4\n", + " // set(value){\n", + " // println(value)\n", + " // }\n", + " fun doSomething() //= println(\"From interface\")\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", + "}\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 + }, + { + "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{\n", + " fun produce(): T\n", + "}\n", + "\n", + "interface Consumer{\n", + " fun consume(value: T)\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 + }, + { + "cell_type": "markdown", + "source": [ + "## Runtime type dispatch\n", + "\n", + "In Java it is called DOP (Data Oriented Programming).\n", + "\n", + "Also sometimes (wrongly) called patter 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\")\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 = try {\n", + " count()\n", + " } catch (e: ArithmeticException) {\n", + " throw IllegalStateException(e)\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": "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": [ + "\n", + "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, val b: Double) {\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": [ + "## 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", + "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 + }, + { + "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", + "/**\n", + " * idiom 10\n", + " * Nullable truth.\n", + " */\n", + "fun idiom10() {\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 + }, + { + "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": [ + "\n", + "\n", + "//TODO move up\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": "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", + "/**\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": [ + "## Safe calls" + ], + "attachments": {}, + "metadata": { + "datalore": { + "node_id": "u8kNpLP2GJ8TLRgyk3kI4Z", + "type": "MD", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + } + }, + { + "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": [ + "## 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() = TODO(\"Don't do that\")\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 > ClosedRange.intersect(other: ClosedRange): ClosedRange?{\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 + }, + { + "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", + "/**\n", + " * Extension property (must be virtual)\n", + " */\n", + "val List.odd get() = filter { it % 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": [ + "\n", + "/**\n", + " * Extension variable (also must be virtual)\n", + " */\n", + "var Array.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 = $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 + }, + { + "cell_type": "code", + "source": [ + "\n", + "//using `run`\n", + "getAClass()?.run {\n", + " // the same as above\n", + " println(\"a = $a, b= $b, c = $c\")\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 + }, + { + "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 }\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": [ + "\n", + "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" + ], + "metadata": { + "datalore": { + "node_id": "m9HH2IzTy1dbYkBRUeFjh9", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "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 = 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\")" + ], + "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", + "/**\n", + "* This one creates a mutable list\n", + "*/\n", + "val mutableList: MutableList = 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 + }, + { + "cell_type": "code", + "source": [ + "\n", + "/**\n", + " * This one creates a mutable ArrayList.\n", + " */\n", + "val arrayList: ArrayList = arrayListOf(\"a\", \"b\", \"c\")\n", + "\n", + "//Danger zone\n", + "\n", + "val newList: List = 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": [ + "\n", + "//Bonus\n", + "\n", + "val lambdaList = List(3){ it.toString() }\n", + "println(lambdaList)\n", + "\n", + "\n", + "val builderList: List = buildList{\n", + " add(2)\n", + " add(8)\n", + " remove(8)\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 = emptyList()){\n", + " TODO()\n", + " emptyArray()\n", + " emptySet()\n", + " emptyMap()\n", + "}\n", + "emptyList()::class" + ], + "metadata": { + "datalore": { + "node_id": "F5RQ5108YJe3pzfN0eAWwm", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "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[\"key\"])\n", + "map[\"key\"] = \"fff\"" + ], + "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": [ + "\n", + "//val entry: MutableMap.MutableEntry = map.iterator().next()\n", + "\n", + "/**\n", + " * The destructuring declaration for maps and other objects that support `operator fun componentN`\n", + " */\n", + "for ((k, 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\")}" + ], + "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": [ + "\n", + "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 = ArrayList()\n", + " val list: List get() = _list\n", + "}\n", + "\n", + "\n", + "\n", + "val obj = AClassWithList()\n", + "\n", + "// obj.b = 10.0 //error\n", + "obj.list\n" + ], + "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": [ + "## Contains operator and ranges" + ], + "attachments": {}, + "metadata": { + "datalore": { + "node_id": "GKoCVcgdnSYPjsNCAJIkBB", + "type": "MD", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + } + }, + { + "cell_type": "code", + "source": [ + "\n", + "val emailsList = emptyList()\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", + "}" + ], + "metadata": { + "datalore": { + "node_id": "4mh1Lg6g8OWEIC1Qjgp9tN", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "source": [ + "\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))" + ], + "metadata": { + "datalore": { + "node_id": "1N4A00CAksn2nVg57DRKnp", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "source": [ + "\n", + "// 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", + "for (x in 10 downTo 1) {\n", + " println(x)\n", + "}\n", + "\n", + "infix fun ClosedRange.step(step: Double): Sequence {\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", + "}" + ], + "metadata": { + "datalore": { + "node_id": "hwJfUD7H5mDtjStAsGppk7", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## Map-reduce" + ], + "attachments": {}, + "metadata": { + "datalore": { + "node_id": "IsJiqd43JpY7BnZTeHNU4M", + "type": "MD", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + } + }, + { + "cell_type": "code", + "source": [ + "val list: List = 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", + "\n", + "result" + ], + "metadata": { + "datalore": { + "node_id": "KKT62bidVYF8I147heptAS", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "source": [ + "val sequence = sequence{\n", + " var counter = 1\n", + " while(true){\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" + ], + "metadata": { + "datalore": { + "node_id": "9qcw7ejFSF8QnAGdf1bAI0", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## Wrap mutable logic" + ], + "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)\n" + ], + "metadata": { + "datalore": { + "node_id": "pJfVynao7enb7Q07lJRGRl", + "type": "CODE", + "hide_input_from_viewers": true, + "hide_output_from_viewers": true + } + }, + "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": [ + "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 {\n", + " fun build(str: String): T\n", + "}\n", + "\n", + "data class IntContainer(val arg: Int) {\n", + " \n", + " companion object : Factory {\n", + " override fun build(str: String) = IntContainer(str.toInt())\n", + " }\n", + "}\n", + "\n", + "data class DoubleContainer(val arg: Double) {\n", + " \n", + " companion object : Factory {\n", + " override fun build(str: String) = DoubleContainer(str.toDouble())\n", + " }\n", + "}\n", + "\n", + "fun buildContainer(str: String, factory: Factory): 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": [ + "\n", + "open class Bad{\n", + " val value: Int\n", + "\n", + " init {\n", + " value = requestValue()\n", + " }\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 + }, + { + "cell_type": "code", + "source": [ + "\n", + "\n", + "//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", + "fun requestValue(): Int = TODO()\n", + "\n", + "// This is the factory-function\n", + "fun Good() = Good(requestValue())\n", + "\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 get(){\n", + " println(\"got\")\n", + " return 33\n", + " }\n", + "}\n", + "val lazyClass = ClassWithALazyProperty()\n", + "lazyClass.lazyValue\n", + "lazyClass.lazyValue\n", + "lazyClass.getterValue\n", + "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": [ + "\n", + "//Using other delegates\n", + "val map = mapOf(\"a\" to 1, \"b\" to 2)\n", + "\n", + "val a: Int by map\n", + "\n", + "println(a)" + ], + "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", + "/**\n", + " * Definition of inline function\n", + " */\n", + "inline fun List.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() {\n", + " listOf(1, 2, 3, 4, 5).forEach {\n", + " if (it == 3) return // non-local return directly to the caller of foo()\n", + " print(\"$it, \")\n", + " }\n", + " println(\"this point is unreachable\")\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", + "/**\n", + " * Using inline function for type reification during the compile time\n", + " */\n", + "inline fun List.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 prettyPrintOne(arg: T) = listOf(arg).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 = List(20) { it.toDouble() }\n", + "\n", + "/**\n", + " * Still boxed\n", + " */\n", + "val genericArray: Array = 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": { + "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 +} diff --git a/notebooks/Types.ipynb b/notebooks/Types.ipynb new file mode 100644 index 0000000..905de41 --- /dev/null +++ b/notebooks/Types.ipynb @@ -0,0 +1,192 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "ExecuteTime": { + "start_time": "2023-03-17T14:00:30.580123Z", + "end_time": "2023-03-17T14:00:30.668303Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "4" + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2+2" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [], + "source": [ + "val a: Int = 2" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-03-17T14:00:30.950210Z", + "end_time": "2023-03-17T14:00:31.048695Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [ + { + "data": { + "text/plain": "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "val listOfInt: MutableList = ArrayList()\n", + "\n", + "for(i in (0 until 10)){\n", + " listOfInt.add(i)\n", + "}\n", + "\n", + "listOfInt" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-03-17T14:00:31.477441Z", + "end_time": "2023-03-17T14:00:31.931786Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [ + { + "data": { + "text/plain": "true" + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "listOfInt.add(11)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-03-17T14:00:32.050143Z", + "end_time": "2023-03-17T14:00:32.168752Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "data": { + "text/plain": "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11]" + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "listOfInt" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-03-17T14:00:32.498157Z", + "end_time": "2023-03-17T14:00:32.572039Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 9, + "outputs": [], + "source": [ + "%use plotly" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-03-17T14:06:08.235188Z", + "end_time": "2023-03-17T14:06:08.422903Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 8, + "outputs": [ + { + "data": { + "text/html": "
\n
\n \n
\n
\n" + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Plotly.plot {\n", + " scatter {\n", + " x(1,2,3)\n", + " y(1,2,3)\n", + " }\n", + "}" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2023-03-17T14:04:06.169017Z", + "end_time": "2023-03-17T14:04:06.433979Z" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Kotlin", + "language": "kotlin", + "name": "kotlin" + }, + "language_info": { + "name": "kotlin", + "version": "1.8.0", + "mimetype": "text/x-kotlin", + "file_extension": ".kt", + "pygments_lexer": "kotlin", + "codemirror_mode": "text/x-kotlin", + "nbconvert_exporter": "" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/settings.gradle.kts b/settings.gradle.kts index cb60dd4..4ea1627 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,3 @@ -rootProject.name = "jvm-demo" +rootProject.name = "ks-materials"