KMP Tutorial #1: What is Kotlin Multiplatform and Why Should You Learn It?

You are a Kotlin developer. You build Android apps. But your company also needs an iOS app. And maybe a desktop app. And a web app. Do you write everything four times? Do you switch to Flutter and learn Dart? Do you hire a separate iOS team? Or do you use the Kotlin you already know — and share your code across all platforms? That is what Kotlin Multiplatform (KMP) does. ...

April 1, 2026 · 8 min

Python Cheat Sheet 2026 — Syntax, Data Structures, and Common Patterns

Bookmark this page. Use Ctrl+F (or Cmd+F on Mac) to find what you need. This cheat sheet covers Python syntax from basics to advanced patterns. Try examples at pythontutor.com. Last updated: March 2026 Variables and Types name = "Alex" # str age = 25 # int height = 1.75 # float is_active = True # bool nothing = None # NoneType Type Example Notes int 42 No size limit float 3.14 64-bit decimal str "hello" Immutable bool True, False Capitalized None None Null equivalent list [1, 2, 3] Mutable, ordered tuple (1, 2, 3) Immutable, ordered dict {"a": 1} Key-value pairs set {1, 2, 3} Unique values, unordered Type Conversions int("42") # 42 float("3.14") # 3.14 str(42) # "42" list((1, 2, 3)) # [1, 2, 3] tuple([1, 2, 3]) # (1, 2, 3) set([1, 1, 2]) # {1, 2} bool(0) # False bool("") # False bool([]) # False bool("hello") # True Strings name = "Alex" f"Hello {name}" # f-string: Hello Alex f"Age: {age + 1}" # f-string with expression f"{price:.2f}" # format: 9.99 f"{name!r}" # repr: 'Alex' f"{num:,}" # thousands separator: 1,000,000 f"{value:>10}" # right-align, width 10 f"{value:<10}" # left-align, width 10 # Common methods "hello".upper() # "HELLO" "HELLO".lower() # "hello" "hello world".title() # "Hello World" " hello ".strip() # "hello" "hello world".split() # ["hello", "world"] "hello world".split("o") # ["hell", " w", "rld"] ", ".join(["a", "b", "c"]) # "a, b, c" "hello".replace("l", "r") # "herro" "hello".startswith("he") # True "hello".endswith("lo") # True "hello world".find("world") # 6 (-1 if not found) "hello world".count("l") # 3 "42".isdigit() # True # Multi-line strings text = """ First line Second line """ # Raw strings (no escape processing) path = r"C:\Users\name\folder" Lists nums = [1, 2, 3, 4, 5] # Access nums[0] # 1 (first) nums[-1] # 5 (last) nums[1:3] # [2, 3] (slice) nums[:3] # [1, 2, 3] (first 3) nums[2:] # [3, 4, 5] (from index 2) nums[::2] # [1, 3, 5] (every 2nd) nums[::-1] # [5, 4, 3, 2, 1] (reversed) # Modify nums.append(6) # add to end nums.insert(0, 0) # insert at index nums.extend([7, 8]) # add multiple nums.remove(3) # remove first occurrence nums.pop() # remove and return last nums.pop(0) # remove and return at index nums.sort() # sort in place nums.sort(reverse=True) # sort descending nums.reverse() # reverse in place nums.clear() # remove all # Functions len(nums) # length min(nums) # smallest max(nums) # largest sum(nums) # total sorted(nums) # new sorted list reversed(nums) # reversed iterator Dictionaries user = {"name": "Alex", "age": 25, "city": "Berlin"} # Access user["name"] # "Alex" (KeyError if missing) user.get("name") # "Alex" user.get("phone", "N/A") # "N/A" (default if missing) # Modify user["age"] = 26 # update user["email"] = "alex@mail.com" # add new key del user["city"] # delete key user.pop("age") # remove and return value # Iterate user.keys() # dict_keys(["name", "age", ...]) user.values() # dict_values(["Alex", 25, ...]) user.items() # dict_items([("name", "Alex"), ...]) for key, value in user.items(): print(f"{key}: {value}") # Merge (Python 3.9+) merged = dict1 | dict2 # dict2 values win on conflict Sets and Tuples # Sets — unique values, unordered colors = {"red", "green", "blue"} colors.add("yellow") colors.remove("red") # KeyError if missing colors.discard("red") # no error if missing a | b # union a & b # intersection a - b # difference a ^ b # symmetric difference # Tuples — immutable point = (10, 20) x, y = point # unpacking name, *rest = ("Alex", 25, "Berlin") # name="Alex", rest=[25, "Berlin"] Control Flow # if / elif / else if age < 18: print("minor") elif age < 65: print("adult") else: print("senior") # Ternary status = "adult" if age >= 18 else "minor" # for loop for item in items: print(item) for i in range(5): # 0, 1, 2, 3, 4 for i in range(2, 10): # 2, 3, ..., 9 for i in range(0, 10, 2): # 0, 2, 4, 6, 8 for i, item in enumerate(items): # index + value print(f"{i}: {item}") for a, b in zip(list1, list2): # parallel iteration print(a, b) # while loop while count > 0: count -= 1 # break / continue for item in items: if item == "skip": continue # skip this iteration if item == "stop": break # exit loop Pattern Matching (Python 3.10+) match status_code: case 200: print("OK") case 404: print("Not Found") case 500: print("Server Error") case _: print(f"Unknown: {status_code}") # Match with destructuring match point: case (0, 0): print("Origin") case (x, 0): print(f"On x-axis at {x}") case (0, y): print(f"On y-axis at {y}") case (x, y): print(f"Point at ({x}, {y})") # Match with guards match user: case {"role": "admin", "name": name}: print(f"Admin: {name}") case {"role": "user", "name": name} if name != "blocked": print(f"User: {name}") Comprehensions # List comprehension squares = [x**2 for x in range(10)] evens = [x for x in nums if x % 2 == 0] pairs = [(x, y) for x in range(3) for y in range(3)] # Dict comprehension word_lengths = {word: len(word) for word in words} filtered = {k: v for k, v in data.items() if v > 0} # Set comprehension unique_lengths = {len(word) for word in words} # Generator expression (lazy, memory-efficient) total = sum(x**2 for x in range(1000000)) Functions # Basic function def greet(name): return f"Hello {name}" # Default parameters def greet(name="World"): return f"Hello {name}" # *args and **kwargs def func(*args, **kwargs): print(args) # tuple of positional args print(kwargs) # dict of keyword args # Lambda double = lambda x: x * 2 sorted(users, key=lambda u: u["age"]) # Type hints (Python 3.10+) def greet(name: str) -> str: return f"Hello {name}" def process(items: list[int]) -> dict[str, int]: return {"sum": sum(items), "count": len(items)} Classes class User: def __init__(self, name: str, age: int): self.name = name self.age = age def greet(self) -> str: return f"Hi, I'm {self.name}" def __repr__(self) -> str: return f"User({self.name!r}, {self.age})" user = User("Alex", 25) # Dataclass (Python 3.7+) — auto-generates __init__, __repr__, __eq__ from dataclasses import dataclass @dataclass class User: name: str age: int city: str = "Unknown" # Inheritance class Admin(User): def __init__(self, name, age, level): super().__init__(name, age) self.level = level Error Handling try: result = 10 / 0 except ZeroDivisionError: print("Cannot divide by zero") except (ValueError, TypeError) as e: print(f"Error: {e}") else: print("Success") # runs if no exception finally: print("Always runs") # cleanup # Raise an exception raise ValueError("Invalid input") File I/O # Read entire file with open("file.txt", "r") as f: content = f.read() # Read lines with open("file.txt", "r") as f: lines = f.readlines() # list of lines # or for line in f: print(line.strip()) # Write with open("file.txt", "w") as f: # overwrite f.write("Hello\n") with open("file.txt", "a") as f: # append f.write("More text\n") # JSON import json data = json.loads('{"name": "Alex"}') # parse string text = json.dumps(data, indent=2) # to string with open("data.json", "r") as f: data = json.load(f) # parse file with open("data.json", "w") as f: json.dump(data, f, indent=2) # write file Async / Await import asyncio async def fetch_data(url: str) -> str: # simulate async work await asyncio.sleep(1) return f"Data from {url}" # Run async function async def main(): result = await fetch_data("https://api.example.com") print(result) asyncio.run(main()) # Run tasks in parallel async def main(): results = await asyncio.gather( fetch_data("https://api1.example.com"), fetch_data("https://api2.example.com"), ) print(results) # both complete in ~1 second, not 2 Common Built-in Functions Function Description Example len(x) Length len([1,2,3]) → 3 range(n) Sequence 0..n-1 range(5) → 0,1,2,3,4 enumerate(x) Index + value enumerate(["a","b"]) zip(a, b) Pair elements zip([1,2], ["a","b"]) map(fn, x) Apply function map(str, [1,2,3]) filter(fn, x) Filter elements filter(bool, [0,1,"",2]) any(x) True if any truthy any([False, True]) → True all(x) True if all truthy all([True, True]) → True sorted(x) New sorted list sorted([3,1,2]) → [1,2,3] reversed(x) Reversed iterator list(reversed([1,2,3])) isinstance(x, type) Type check isinstance(42, int) → True type(x) Get type type(42) → <class 'int'> dir(x) List attributes dir([]) help(x) Show docs help(str.split) Virtual Environments python -m venv .venv # create source .venv/bin/activate # activate (macOS/Linux) .venv\Scripts\activate # activate (Windows) pip install requests # install package pip freeze > requirements.txt # save dependencies pip install -r requirements.txt # install from file deactivate # deactivate Common Mistakes Mutable default arguments — def add(item, items=[]) shares the same list across all calls. Use def add(item, items=None) and items = items or [] inside the function. ...

March 22, 2026 · 7 min

Jetpack Compose Tutorial #5: State — The Most Important Concept

This is the most important tutorial in the entire series. If you don’t understand state, nothing in Compose will make sense. If you do understand it, everything clicks. State is the reason the login form from the previous tutorial worked. It is the reason buttons can toggle, text fields can update, and screens can change. Without state, your UI is frozen — it shows something once and never changes. Let’s fix that. ...

March 17, 2026 · 10 min

Kotlin Cheat Sheet 2026 — Quick Reference Guide

Bookmark this page. Use Ctrl+F (or Cmd+F on Mac) to find what you need. This cheat sheet covers Kotlin syntax from basics to coroutines. Try examples live at play.kotlinlang.org. Last updated: April 2026 Variables Syntax Description val name = "Alex" Immutable (read-only) — cannot reassign var count = 0 Mutable — can reassign val age: Int = 25 Explicit type annotation const val PI = 3.14 Compile-time constant (top-level or object only) val name = "Alex" // type inferred as String var score = 0 // type inferred as Int score = 10 // OK — var can be reassigned // name = "Sam" // ERROR — val cannot be reassigned Basic Types Type Example Notes Int 42 32-bit integer Long 42L 64-bit integer Double 3.14 64-bit decimal Float 3.14f 32-bit decimal Boolean true, false String "hello" Immutable Char 'A' Single character Type Conversions val x: Int = 42 val d: Double = x.toDouble() // 42.0 val s: String = x.toString() // "42" val i: Int = "123".toInt() // 123 val safe: Int? = "abc".toIntOrNull() // null Null Safety Syntax Description String? Nullable type — can hold null name?.length Safe call — returns null if name is null name ?: "default" Elvis operator — use default if null name!! Not-null assertion — throws if null (avoid this) name?.let { ... } Execute block only if not null val name: String? = null val len = name?.length // null (no crash) val safe = name ?: "Unknown" // "Unknown" // val crash = name!!.length // throws NullPointerException String Templates val name = "Alex" println("Hello $name") // Hello Alex println("Length: ${name.length}") // Length: 4 println("Sum: ${2 + 3}") // Sum: 5 Functions // Regular function fun greet(name: String): String { return "Hello $name" } // Single-expression function fun greet(name: String) = "Hello $name" // Default parameters fun greet(name: String = "World") = "Hello $name" // Named arguments greet(name = "Alex") // Unit return type (void equivalent) fun log(message: String) { println(message) } Control Flow if / else (is an expression) val max = if (a > b) a else b when (replaces switch) when (x) { 1 -> println("one") 2, 3 -> println("two or three") in 4..10 -> println("between 4 and 10") is String -> println("it is a string") else -> println("something else") } // Guard conditions in when (Kotlin 2.2+) when (val result = fetchData()) { is Result.Success if result.data.isNotEmpty() -> show(result.data) is Result.Success -> showEmpty() is Result.Error -> showError(result.message) } // when as expression val label = when { score >= 90 -> "A" score >= 80 -> "B" else -> "C" } Loops for (i in 1..5) { } // 1, 2, 3, 4, 5 for (i in 1 until 5) { } // 1, 2, 3, 4 (or 1..<5) for (i in 1..<5) { } // 1, 2, 3, 4 (open-ended range, Kotlin 1.8+) for (i in 5 downTo 1) { } // 5, 4, 3, 2, 1 for (i in 0..10 step 2) { } // 0, 2, 4, 6, 8, 10 for (item in list) { } // iterate a collection list.forEachIndexed { index, item -> } Collections Type Create Mutable Version List listOf(1, 2, 3) mutableListOf(1, 2, 3) Set setOf(1, 2, 3) mutableSetOf(1, 2, 3) Map mapOf("a" to 1) mutableMapOf("a" to 1) Common Operations val numbers = listOf(1, 2, 3, 4, 5) numbers.filter { it > 2 } // [3, 4, 5] numbers.map { it * 2 } // [2, 4, 6, 8, 10] numbers.first() // 1 numbers.last() // 5 numbers.firstOrNull { it > 10 } // null numbers.any { it > 3 } // true numbers.all { it > 0 } // true numbers.count { it % 2 == 0 } // 2 numbers.sum() // 15 numbers.sorted() // [1, 2, 3, 4, 5] numbers.reversed() // [5, 4, 3, 2, 1] numbers.distinct() // remove duplicates numbers.take(3) // [1, 2, 3] numbers.drop(2) // [3, 4, 5] numbers.groupBy { it % 2 } // {1=[1,3,5], 0=[2,4]} numbers.associate { it to it * it } // {1=1, 2=4, 3=9, ...} numbers.flatMap { listOf(it, it * 10) } // [1,10,2,20,...] Map Operations val map = mapOf("a" to 1, "b" to 2) map["a"] // 1 map.getOrDefault("c", 0) // 0 map.keys // [a, b] map.values // [1, 2] map.entries // [a=1, b=2] map + ("c" to 3) // new map with c added Lambdas val double = { x: Int -> x * 2 } double(5) // 10 // Single parameter uses "it" val numbers = listOf(1, 2, 3) numbers.filter { it > 1 } // Trailing lambda numbers.fold(0) { acc, n -> acc + n } Classes // Data class — equals, hashCode, toString, copy generated data class User(val name: String, val age: Int) val user = User("Alex", 25) val copy = user.copy(age = 26) // Enum class enum class Color { RED, GREEN, BLUE } // Sealed class — restricted hierarchy sealed class Result { data class Success(val data: String) : Result() data class Error(val message: String) : Result() data object Loading : Result() } // Object — singleton object Database { fun connect() { } } // Companion object — static-like members class MyClass { companion object { fun create(): MyClass = MyClass() } } Extension Functions fun String.addExclamation() = "$this!" "Hello".addExclamation() // "Hello!" fun List<Int>.secondOrNull(): Int? = if (size >= 2) this[1] else null Scope Functions Function Object ref Return Use case let it Lambda result Null checks, transformations run this Lambda result Object config + compute result with this Lambda result Group calls on an object apply this Object itself Object configuration also it Object itself Side effects (logging, validation) // let — execute block if not null val length = name?.let { it.length } // apply — configure a builder/mutable object val paint = Paint().apply { color = Color.RED strokeWidth = 4f } // also — side effects val list = mutableListOf(1, 2).also { println("Before: $it") } // run — compute a result val result = service.run { connect() fetchData() } // with — group calls val info = with(user) { "$name is $age years old" } Coroutines Basics // Launch — fire and forget scope.launch { val data = fetchData() // suspend function updateUi(data) } // Async — returns a Deferred (future) val deferred = async { fetchData() } val result = deferred.await() // Parallel execution coroutineScope { val a = async { fetchA() } val b = async { fetchB() } println("${a.await()} ${b.await()}") } // Switch context withContext(Dispatchers.IO) { // Run on background thread readFile() } // Flow — reactive stream fun numbers(): Flow<Int> = flow { for (i in 1..3) { delay(100) emit(i) } } // collect is a suspend function — must be called inside a coroutine scope.launch { numbers().collect { println(it) } } Dispatcher Use case Dispatchers.Main UI updates Dispatchers.IO Network, database, file I/O Dispatchers.Default CPU-heavy computation Smart Casts // Kotlin auto-casts after a type check — no explicit cast needed fun printLength(x: Any) { if (x is String) { println(x.length) // x is auto-cast to String } } // Works with when too when (result) { is Result.Success -> println(result.data) is Result.Error -> println(result.message) } Value Classes // Wraps a value with zero runtime overhead (no extra object allocation) @JvmInline value class Email(val address: String) val email = Email("alex@example.com") // At runtime, this is just a String — no wrapper object Multi-line Strings val json = """ { "name": "Alex", "age": 25 } """.trimIndent() val sql = """ SELECT * FROM users WHERE age > 18 ORDER BY name """.trimIndent() Common Patterns Safe casting val x: Any = "hello" val s: String? = x as? String // "hello" val i: Int? = x as? Int // null (no crash) Destructuring val (name, age) = User("Alex", 25) val (key, value) = mapEntry takeIf / takeUnless val positiveNumber = number.takeIf { it > 0 } // number or null val nonBlank = name.takeUnless { it.isBlank() } // name or null // Chain with Elvis val port = config.getPort().takeIf { it in 1..65535 } ?: 8080 Lazy initialization val heavy: String by lazy { println("Computed!") "result" } Common Mistakes Mutable vs immutable collections — listOf() returns a read-only List. Use mutableListOf() if you need add() or remove(). Casting a List to MutableList is unsafe. ...

March 16, 2026 · 7 min

Jetpack Compose Text, Button, Image, and TextField: Complete Guide

You know layouts. You know modifiers. Now let’s learn the components you will use in every single screen — Text, Button, Image, and TextField. These are the building blocks of every Android app. Get comfortable with them and you can build almost anything. Text — Showing Words on Screen You have already used Text, but there is much more to it. Basic Text Text("Hello, World!") Styling Text Text( text = "Styled Text", fontSize = 24.sp, fontWeight = FontWeight.Bold, color = Color.Blue, letterSpacing = 1.sp, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth() ) All the Style Options Property What It Does Example fontSize Text size 16.sp, 24.sp fontWeight Thickness FontWeight.Bold, FontWeight.Light fontStyle Italic or normal FontStyle.Italic color Text color Color.Red, Color(0xFF333333) textAlign Alignment TextAlign.Center, TextAlign.End letterSpacing Space between letters 2.sp lineHeight Space between lines 28.sp maxLines Maximum number of lines 1, 3 overflow What happens when text is too long TextOverflow.Ellipsis textDecoration Underline or strikethrough TextDecoration.Underline Truncating Long Text When text is too long for the available space: ...

March 16, 2026 · 9 min

Jetpack Compose Tutorial #3: Modifiers — The Secret to Styling Everything

In the previous tutorial, we learned how to arrange things on screen with Column, Row, and Box. But everything looked plain. No padding. No colors. No borders. That is where Modifiers come in. Modifiers are how you control everything about how a Composable looks and behaves — size, spacing, color, shape, click behavior, scrolling, and more. If layouts are the skeleton, modifiers are the skin and muscles. What is a Modifier? A Modifier is a chain of instructions that you attach to a Composable. Each instruction changes one thing about how it looks or acts. ...

March 15, 2026 · 9 min

How to Set Up Claude Code: Complete Beginner Guide (2026)

Claude Code is one of the most powerful AI coding tools in 2026. But setting it up for the first time can be confusing. Terminal-based. No GUI. No install wizard. This guide will walk you through everything — from installation to your first real coding session. What is Claude Code? Claude Code is an AI coding agent that runs in your terminal. You type what you want in plain English, and it reads your code, makes changes, runs commands, and even handles git — all by itself. ...

March 14, 2026 · 9 min

7 Best Free AI Coding Tools in 2026 (I Tested All of Them)

You don’t need to pay $20/month to use AI for coding. There are free tools that are actually good — some are even better than what we had with paid tools two years ago. I tested every major free AI coding tool in 2026. Here is what works, what doesn’t, and which one you should pick. Quick Comparison Tool Free Completions Free Chat Works In Best For GitHub Copilot 2,000/month 50 messages VS Code, JetBrains, Neovim Best all-around free option Gemini Code Assist 180,000/month Yes VS Code, JetBrains, Android Studio Most generous free tier Cursor Limited Limited Cursor (VS Code fork) Best editor experience Windsurf Limited Yes Windsurf (VS Code fork) Good agent features for free Amazon Q Developer Unlimited 50/month VS Code, JetBrains AWS developers Continue Unlimited Unlimited VS Code, JetBrains Open source, use any AI model Claude.ai Daily limit Yes Browser Best for complex questions Now let me break down each one. ...

March 14, 2026 · 10 min

What Is Vibe Coding? Explained With a Real 8-Minute Build

In February 2025, Andrej Karpathy posted a simple tweet. He described how he codes now — just talking to AI, accepting whatever it produces, and barely reading the code. He called it “vibe coding.” That tweet changed how millions of developers think about writing software. Let me explain what it actually means, where it came from, and how to do it well. What is Vibe Coding? Vibe coding means you describe what you want in plain English, and AI writes the code for you. You don’t write the code yourself. You don’t even look at the code most of the time. You just tell the AI what to build, check if it works, and keep going. ...

March 14, 2026 · 13 min

Jetpack Compose Layouts: Column, Row, and Box Explained with Examples

In the previous tutorial, we wrote our first Composable. But one Text on the screen is not an app. You need to put things next to each other, below each other, and on top of each other. That is what layouts do. Compose gives you three main layout components: Column — puts things vertically (top to bottom) Row — puts things horizontally (left to right) Box — puts things on top of each other (like layers) Every screen you will ever build uses a combination of these three. Master them and you can build anything. ...

March 14, 2026 · 12 min