ks-materials/notebooks/Idioms.ipynb
2024-08-06 09:38:15 +03:00

2440 lines
56 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"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<out T>{\n",
" fun produce(): T\n",
"}\n",
"\n",
"interface Consumer<in T>{\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 <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
},
{
"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<Int>.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<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 = $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<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
},
{
"cell_type": "code",
"source": [
"\n",
"/**\n",
" * This one creates a mutable ArrayList.\n",
" */\n",
"val arrayList: ArrayList<String> = arrayListOf(\"a\", \"b\", \"c\")\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": [
"\n",
"//Bonus\n",
"\n",
"val lambdaList = List(3){ it.toString() }\n",
"println(lambdaList)\n",
"\n",
"\n",
"val builderList: List<Int> = 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<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
},
{
"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<String, String> = 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<Int> = ArrayList<Int>()\n",
" val list: List<Int> 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<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",
"}"
],
"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<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",
"}"
],
"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<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",
"\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<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",
"}\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": [
"\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<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() {\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 <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",
"/**\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": {
"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
}