{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World\n"
     ]
    }
   ],
   "source": [
    "// simple print to stdout\n",
    "\n",
    "println(\"Hello World\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "stdin:Hello World\n",
      "Hello World\n"
     ]
    }
   ],
   "source": [
    "// simple read from stdin\n",
    "\n",
    "println(readLine())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Variable\n",
    "\n",
    "var x = 1\n",
    "x = 2\n",
    "println(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// constant\n",
    "\n",
    "val y = 9\n",
    "// y = 4\n",
    "println(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Different types of elements in Kotlin\n",
    "\n",
    "fun kotlinAndJavaType(value: Any): String {\n",
    "    return \"Kotlin: \" + value::class.simpleName + \" | Java: \" + value.javaClass.typeName\n",
    "}\n",
    "\n",
    "println(kotlinAndJavaType(3))\n",
    "println(kotlinAndJavaType(3.4))\n",
    "println(kotlinAndJavaType(\"something\"))\n",
    "println(kotlinAndJavaType(listOf(1, 2, 3)))\n",
    "println(kotlinAndJavaType(mapOf(1 to \"One\", 2 to \"Two\", 3 to \"Three\")))\n",
    "println(kotlinAndJavaType(setOf(1, 2, 3)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Immutability\n",
    "\n",
    "val lst = listOf(1, 2, 3)\n",
    "val lst2 = lst.reversed()\n",
    "val lst3 = listOf(6, 7, 8) + lst + listOf(9, 10)\n",
    "println(lst)\n",
    "println(lst2)\n",
    "println(lst3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Mutability\n",
    "\n",
    "val lst4 = mutableListOf(1, 2, 3)\n",
    "println(lst4)\n",
    "lst4.add(4)\n",
    "println(lst4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Nullability and Null safety\n",
    "\n",
    "// val nonNullable: Int = null\n",
    "// println(nonNullable)\n",
    "\n",
    "val nullable: Int? = null\n",
    "println(nullable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Conditional statement\n",
    "\n",
    "print(\"Enter your age: \")\n",
    "val age = Integer.parseInt(readLine())\n",
    "if (age >= 18)\n",
    "    println(\"You are allowed to drink\")\n",
    "else\n",
    "    println(\"It's illegal for you to drink\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Conditional expression\n",
    "\n",
    "print(\"Enter your age: \")\n",
    "val age = Integer.parseInt(readLine())\n",
    "val allowedToDrink = if (age >= 18) \"Allowed to drink\" else \"It's illegal for you to drink\"\n",
    "println(allowedToDrink)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// when (somewhat pattern matching, somewhat switch)\n",
    "\n",
    "fun checkIfIsValidNumberGreaterThan10(value: Int): String {\n",
    "    val validNumbers = listOf(13, 17, 19)\n",
    "    when(value) {\n",
    "        in 1..10 -> return \"x is in the range\"\n",
    "        in validNumbers -> return \"x is valid\"\n",
    "        !in 10..20 -> return \"x is outside the range\"\n",
    "        else -> return \"none of the above\"\n",
    "    }\n",
    "}\n",
    "checkIfIsValidNumberGreaterThan10(Integer.parseInt(readLine()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// functions as set of statements\n",
    "\n",
    "fun squareAsStatement(x: Int): Int {\n",
    "    return x * x\n",
    "}\n",
    "squareAsStatement(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// functions as expressions\n",
    "\n",
    "fun squareAsExpression(x: Int) = x * x\n",
    "squareAsExpression(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// functions with default args\n",
    "\n",
    "fun increment(x: Int, by_: Int=1) = x + by_\n",
    "println(increment(5))\n",
    "println(increment(5, by_=3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// functions to be used as infix\n",
    "\n",
    "infix fun Int.toThePower(power: Int): Int = if (power == 1) this else this * (this toThePower power -1)\n",
    "2 toThePower 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// lambdas as shorthand functions\n",
    "\n",
    "val incrementLambda = { i: Int -> i + 1 }\n",
    "incrementLambda(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// inline function using lambda\n",
    "\n",
    "import java.io.File\n",
    "inline fun withLock(name: String, block: () -> Unit) {\n",
    "    while (File(\"${name}.lock\").exists())\n",
    "        Thread.sleep(1000)\n",
    "    block()\n",
    "    File(\"${name}.lock\").delete()\n",
    "}\n",
    "\n",
    "withLock(\"write-to-shared-file\") {\n",
    "    println(\"access 1\")\n",
    "}\n",
    "\n",
    "withLock(\"write-to-shared-file\") {\n",
    "    println(\"access 2\")\n",
    "}\n",
    "withLock(\"write-to-shared-file\") {\n",
    "    println(\"access 3\")\n",
    "}\n",
    "withLock(\"write-to-shared-file\") {\n",
    "    println(\"access 4\")\n",
    "}\n",
    "withLock(\"write-to-shared-file\") {\n",
    "    println(\"access 5\")\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// simple class\n",
    "\n",
    "data class Product(val name: String, val cost: Int)\n",
    "interface Totalable {\n",
    "    fun total(): Int\n",
    "}\n",
    "class Cart(val products: List<Product>) : Totalable {\n",
    "    override fun total(): Int {\n",
    "        return products.fold(0) { total, product -> total + product.cost }\n",
    "    }\n",
    "}\n",
    "\n",
    "val products = listOf(Product(\"iPhone\", 1000), Product(\"iPhone Charger\", 3000))\n",
    "println(products)\n",
    "val cart = Cart(products)\n",
    "println(cart.total())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// objects\n",
    "\n",
    "import java.sql.*\n",
    "object loggedInUser {\n",
    "    var userName: String?=null\n",
    "}\n",
    "println(loggedInUser.userName)\n",
    "loggedInUser.userName = \"Someone\"\n",
    "println(loggedInUser.userName)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// ranges\n",
    "\n",
    "println(kotlinAndJavaType(1..10))\n",
    "println(kotlinAndJavaType(1 until 10))\n",
    "println(1..10)\n",
    "println(10..1)\n",
    "println(1 until 10)\n",
    "println(20 downTo 1 step 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// looping\n",
    "\n",
    "for (x in 20 downTo 1 step 2) {\n",
    "    println(x)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// map -> filter -> reduce\n",
    "val listOf100Elements = (1..100 step 1).toList()\n",
    "println(\"listOf100Elements: ${listOf100Elements}\")\n",
    "println()\n",
    "val squareOfAll200Elements = listOf100Elements.map { num -> num * 2 }\n",
    "println(\"squareOfAll200Elements: ${squareOfAll200Elements}\")\n",
    "println()\n",
    "val thoseWithNumbersDivisibleBy4FilteredOut = squareOfAll200Elements.filter { num -> num % 4 != 0 }\n",
    "println(\"thoseWithNumbersDivisibleBy4FilteredOut: ${thoseWithNumbersDivisibleBy4FilteredOut}\")\n",
    "println()\n",
    "val sumOfAllThoseNumbers = thoseWithNumbersDivisibleBy4FilteredOut.reduce { acc, num -> acc + num }\n",
    "println(\"sumOfAllThoseNumbers: ${sumOfAllThoseNumbers}\")\n",
    "println()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Kotlin",
   "language": "kotlin",
   "name": "kotlin"
  },
  "language_info": {
   "codemirror_mode": "text/x-kotlin",
   "file_extension": ".kt",
   "mimetype": "text/x-kotlin",
   "name": "kotlin",
   "pygments_lexer": "kotlin",
   "version": "1.4.20-dev-2342"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}