Language Overview
Skotch implements a growing subset of the Kotlin language. This page summarizes what works today and what is coming next.
Implemented and stable
Section titled “Implemented and stable”| Feature | Spec reference | Notes |
|---|---|---|
| Function declarations ↗ | §4.1 | Top-level fun, parameters, return types |
| Default parameters ↗ | §4.1.1 | fun f(x: Int = 10) — literal defaults injected at call sites |
| Named arguments ↗ | §7.2.2 | f(height = 3, width = 4) — arguments reordered to match parameter positions |
| Expression body functions ↗ | §4.1 | fun f() = expr shorthand |
| Extension functions ↗ | §4.1.3 | fun Int.isEven(), this receiver, method chaining |
| Local functions ↗ | §4.1.4 | fun inside blocks, recursive calls |
| Data classes ↗ | §4.5.6 | data class Point(val x: Int, val y: Int) — synthesized toString() producing "Point(x=1, y=2)" |
| Class declarations ↗ | §4.5 | Primary constructor with val/var, field access, instance methods, init blocks, invokevirtual dispatch |
| Mutable class fields ↗ | §4.2 | var fields in classes with method writeback; count++ in methods persists |
| Override toString() ↗ | §4.5.1 | override fun toString(): String on regular classes |
| Increment/decrement ↗ | §7.3.4 | x++, x-- — postfix operators on var locals and class fields |
| Object declarations ↗ | §4.5.4 | object Singleton { fun greet() {} } — methods as static functions; Singleton.greet() calls |
| Enum classes ↗ | §4.5.7 | enum class Color { RED, GREEN, BLUE } — entries accessed via Color.RED, usable in when |
| Companion objects ↗ | §4.5.4 | companion object { fun create() } — static methods via ClassName.method() |
| Const val ↗ | §4.2 | const val compile-time constants inlined at call site |
| Visibility modifiers ↗ | §4.3 | private, internal, protected, open, abstract — parsed and accepted (not yet enforced) |
| Java interop ↗ | §18 | Real .class parsing from JDK jmods + CLASSPATH; deferred resolution; clear classpath errors |
| Import declarations ↗ | §9.2 | import java.lang.Math, implicit java.lang.* |
| Variable declarations ↗ | §4.2 | val (immutable), var (mutable), type annotations |
| Integer literals ↗ | §7.1.1 | Decimal, hex (0xFF), binary (0b1010), underscores (1_000), L suffix |
| Character literals ↗ | §7.1.5 | 'A', escape sequences ('\n', '\t', '\\') |
| Boolean literals ↗ | §7.1.3 | true, false |
| String literals ↗ | §7.1.4 | Regular, raw ("""), templates ($x, ${expr}) |
| Long literals ↗ | §7.1.1 | 100L, 0xFFL — full 64-bit arithmetic (+, -, *, /, %), negation, values exceeding Int range |
| Double/Float literals ↗ | §7.1.2 | 3.14, 2.5e10, 1.0f, negative doubles, scientific notation |
| Null literal ↗ | §7.1.6 | null value, println(null) |
| Elvis operator ↗ | §7.4.3 | x ?: default — null-check with fallback, supports chaining |
| Nullable parameters ↗ | §3.3 | fun f(x: String?): String, nullable function parameters |
| Arithmetic operators ↗ | §7.5 | +, -, *, /, % on Int, Long, and Double |
| String concatenation ↗ | §7.5 | String + String, String + Int/Long/Double/Bool |
| Comparison operators ↗ | §7.6 | ==, !=, <, >, <=, >= (Int and String) |
| Logical operators ↗ | §7.8-7.9 | &&, || with short-circuit evaluation |
| Unary operators ↗ | §7.3 | - (negation), ! (not) |
| Compound assignment ↗ | §7.12 | +=, -=, *=, /=, %= |
| If expression ↗ | §7.4.1 | As statement and expression, with/without else |
| When expression ↗ | §7.4.2 | With subject, without subject, comma patterns, in range, string/int matching, nested |
| Else-if chains ↗ | §7.4.1 | if {} else if {} else {} (as statements) |
| For loop ↗ | §8.2 | .. (inclusive), until (exclusive), downTo (descending) |
| While loop ↗ | §8.3 | while (cond) { } |
| Do-while loop ↗ | §8.3 | do { } while (cond) |
| Break and continue ↗ | §7.10 | In for, while, and do-while loops (including nested in if) |
| Return ↗ | §7.10 | Early return from functions, guard clauses (if (cond) return expr without braces) |
| Recursive functions ↗ | §4.1 | Direct recursion (factorial, GCD, power), mutual recursion, multi-parameter |
| Function calls ↗ | §7.2 | Direct, nested, recursive, mutual recursion, extension method syntax |
println ↗ | stdlib | println(), println(Int), println(Double), println(String), println(Boolean), println(null) |
print ↗ | stdlib | print() without trailing newline — all type overloads |
| String templates ↗ | §7.1.4 | "$var", "${expr}" usable anywhere (val, return, args) |
| Try-finally ↗ | §7.4.5 | try { body } finally { cleanup } — finally always executes after body |
| String methods ↗ | stdlib | .length, .uppercase(), .lowercase(), .isEmpty(), .trim(), .substring(), .contains(), .startsWith(), .endsWith(), .indexOf(), .lastIndexOf(), .replace(), .get(), .equals(), .compareTo(), .toInt(), .toDouble(), .toLong() |
| Type conversions ↗ | stdlib | Int.toString(), Long.toString(), Double.toString(), String.toInt(), String.toLong(), String.toDouble() |
| Init blocks ↗ | §4.5.2 | init { } blocks execute during construction, access constructor params |
| Language Server Protocol | — | Real-time diagnostics, semantic tokens, hover, go-to-definition, completions via skotch lsp |
Not yet implemented
Section titled “Not yet implemented”| Feature | Spec reference | Difficulty | Notes |
|---|---|---|---|
| Inheritance and override | §4.5 ↗ | Hard | open class, override fun, super calls |
| Data class equals/hashCode/copy | §4.5.6 ↗ | Medium | toString() works; equals()/hashCode()/copy()/componentN() not yet synthesized |
| Interfaces | §4.5.3 ↗ | Hard | Declaration, implementation, default methods |
| Sealed classes | §4.5.5 ↗ | Hard | Sealed hierarchies, exhaustive when |
| Generics | §4.6 ↗ | Hard | Type parameters, bounds, variance |
| Lambdas | §7.2.10 ↗ | Hard | Lambda literals, closures, it parameter |
Safe call (?.) | §3.3 ↗ | Done | x?.length short-circuits to null if receiver is null |
Non-null assert (!!) | §3.3 ↗ | Done | x!! unwraps nullable to non-null type |
Type checks (is/!is) | §7.6.3 ↗ | Done | instanceof + smart cast narrowing in when/if with checkcast + unbox |
Type casts (as/as?) | §7.6.4 ↗ | Done | checkcast emission for safe and unsafe casts |
| Try/catch | §7.4.5 ↗ | Done | Full exception tables, try-as-expression, catch variable binding (e.message), multi-statement bodies |
| Throw expression | §7.4.6 ↗ | Done | athrow opcode, exception constructors (IllegalStateException, etc.), Nothing return type |
| Collections | stdlib | Done | listOf, map, filter, fold, 25+ HOF extensions via kotlin-stdlib.jar |
| kotlin.math | stdlib | Done | abs, sqrt, ceil, floor, round, pow, sin, cos, tan, log, exp |
| readLine/readln | stdlib | Done | readLine() reads stdin via Scanner(System.in).nextLine() |
| Varargs | §4.1.2 ↗ | Medium | vararg parameter, spread * |
| Type aliases | §4.7 ↗ | Easy | typealias erased at compile time |
| Destructuring | §8.1 ↗ | Medium | val (a, b) = pair via componentN() |
| Coroutines | §7.2.11 ↗ | Very Hard | suspend, state machine CPS transform |
| Annotations | §4.8 ↗ | Medium | Declaration, retention, reflection |
| Operator overloading | §7.5 ↗ | Medium | plus, minus, compareTo, invoke |
else if chains with return | — | Medium | All-branches-return in nested if (use when as workaround) |
Feature details
Section titled “Feature details”Functions
Section titled “Functions”Top-level functions with parameters, return types, expression bodies, extension receivers, local (nested) functions, default parameter values, named arguments, and mutual recursion.
fun greet(name: String = "World"): String = "Hello, $name!"
fun configure(host: String = "localhost", port: Int = 8080) { println("$host:$port")}
fun Int.isEven(): Boolean = this % 2 == 0
fun main() { println(greet()) // Hello, World! println(greet("Kotlin")) // Hello, Kotlin! configure() // localhost:8080 configure("example.com", 443) // example.com:443}Named arguments allow calling with arguments in any order:
fun rect(width: Int, height: Int): Int = width * heightrect(height = 4, width = 3) // 12, reordered to match paramsVariables
Section titled “Variables”Immutable val and mutable var with type inference from literals or
explicit type annotations.
val message = "hello"var counter = 0val typed: Int = 42Classes
Section titled “Classes”Classes with primary constructors, val/var parameters, field access,
instance methods, mutable field writeback, and init blocks:
class Counter { var count: Int = 0 fun increment() { count++ }}
fun main() { val c = Counter() c.increment() c.increment() c.increment() println(c.count) // 3}You can also override toString():
class Point(val x: Int, val y: Int) { override fun toString(): String = "($x, $y)"}println(Point(3, 4)) // (3, 4)Data classes
Section titled “Data classes”Data classes get a synthesized toString() matching Kotlin’s format:
data class Point(val x: Int, val y: Int)data class Person(val name: String, val age: Int)
fun main() { println(Point(1, 2)) // Point(x=1, y=2) println(Person("Alice", 30)) // Person(name=Alice, age=30)}Object declarations (singletons)
Section titled “Object declarations (singletons)”object MathUtils { fun square(x: Int): Int = x * x fun cube(x: Int): Int = x * x * x}
fun main() { println(MathUtils.square(5)) // 25 println(MathUtils.cube(3)) // 27}Enum classes
Section titled “Enum classes”enum class Color { RED, GREEN, BLUE }
fun describe(c: Color): String = when (c) { Color.RED -> "warm" Color.GREEN -> "cool" Color.BLUE -> "cool"}
fun main() { println(Color.RED) // RED println(describe(Color.BLUE)) // cool}Companion objects
Section titled “Companion objects”class Config { companion object { fun appName(): String = "MyApp" fun version(): Int = 1 }}
fun main() { println(Config.appName()) // MyApp println(Config.version()) // 1}Type conversions
Section titled “Type conversions”String-to-number conversions work in expressions:
val x = "42".toInt() + 8 // 50val y = "3.14".toDouble() // 3.14val z = "100".toLong() * 2L // 200val s = 42.toString() // "42"val u = "hello".uppercase() // "HELLO"println("hello".length + 1) // 6Nullable types and elvis operator
Section titled “Nullable types and elvis operator”Functions can accept nullable parameters (String?). The elvis operator
(?:) provides a default value when the left-hand side is null:
fun greet(name: String?): String = name ?: "anonymous"
fun first(a: String?, b: String?): String = a ?: b ?: "none"
fun main() { println(greet("Alice")) // Alice println(greet(null)) // anonymous println(first(null, null)) // none}Control flow
Section titled “Control flow”All core control-flow constructs are implemented:
- if/else as both statement and expression
- else-if chains for multi-branch conditions
- when with subject, without subject, comma patterns,
in rangepatterns, string/int matching,elsedefault, and nesting - for loops:
for (i in 0..9)(inclusive),for (i in 0 until 10)(exclusive),for (i in 10 downTo 1)(descending) - while and do-while loops
- break, continue, and return (including early return and
guard clauses:
if (n <= 1) return n) - try/finally — finally block always executes after try body
fun classify(n: Int): String = when { n < 0 -> "negative" n == 0 -> "zero" n in 1..10 -> "small" else -> "large"}String templates
Section titled “String templates”Both $identifier and ${expression} interpolation forms work in regular
and raw strings.
val x = 42println("The answer is $x")println("Double: ${x * 2}")String methods
Section titled “String methods”String instance methods are compiled to JVM invokevirtual calls:
val s = "Hello, World!"println(s.length) // 13println(s.uppercase()) // HELLO, WORLD!println(s.lowercase()) // hello, world!println(s.isEmpty()) // falseprintln(s.trim()) // Hello, World!println(s.substring(7)) // World!println(s.substring(0, 5)) // Helloprintln(s.contains("World")) // trueprintln(s.startsWith("Hello")) // trueprintln(s.endsWith("!")) // trueprintln(s.indexOf("World")) // 7println(s.replace("World", "Kotlin")) // Hello, Kotlin!println(42.toString()) // 42Const val
Section titled “Const val”Compile-time constants are inlined at their call site:
const val PI = 3.14159const val APP_NAME = "skotch"
fun main() { println(PI) // 3.14159 println(APP_NAME) // skotch}Stdlib functions
Section titled “Stdlib functions”println, print, maxOf, and minOf are available:
println(maxOf(10, 20)) // 20println(minOf(10, 20)) // 10What you can build today
Section titled “What you can build today”Skotch handles procedural and object-oriented Kotlin well: console programs, algorithms, classes with constructors, mutable fields, and methods, data classes, singletons, enums, companion objects, and null-safe code using the elvis operator. Programs that use functions, control flow, basic types, Double arithmetic, and nullable parameters compile and run correctly on all five targets.
Example: Fibonacci sequence
Section titled “Example: Fibonacci sequence”fun fibonacci(n: Int): Int { if (n <= 1) return n var a = 0 var b = 1 for (i in 2..n) { val temp = a + b a = b b = temp } return b}
fun main() { for (i in 0..10) { println(fibonacci(i)) }}Example: Data class with enum
Section titled “Example: Data class with enum”enum class Priority { LOW, MEDIUM, HIGH }
data class Task(val name: String, val priority: Priority)
fun main() { val task = Task("Deploy", Priority.HIGH) println(task) // Task(name=Deploy, priority=HIGH)}Example: Null-safe parameter handling
Section titled “Example: Null-safe parameter handling”fun greet(name: String?): String = name ?: "World"fun first(a: String?, b: String?): String = a ?: b ?: "none"Programs that depend on generics, lambdas, the Kotlin standard library collection APIs, or third-party libraries will need to wait for those features to land.