- Decorators can go inside a method declaration.
- The name "Kotlin" came from Kotlin Island, not an anagram of anything, such as Kinton.
- Kotlin was invented by JetBrains, the people who made Android Studio. It is impossible not to get first-class support for it.
- There is a repl (called
kotlinc-jvm
), but it's hella slow. Install with instructions. - Kotlin has longer compilation times compared to Java, with the exception of incremental builds, which may match Java's compile time. So, while developer efficiency goes up (with less boilerplate code), machine efficiency goes down. A fair tradeoff.
f() ?: g()
isf() ? f() : g()
, exceptf
doesn't get called twice.- Apparently, one of Kotlin's big selling points is null safety, where normal variables can never point to a
null
. Butnull
is still a thing and can be explicitly checked and/or allowed (by adding?
after the variable name declaration). Saying "no moreNullPointerException
" is not true. - In constrast, instead of using
?
to make something nullable, you can use!!
to make sure something absolutely isn't null, usually when you run java code, which has no null safety. (Yes, it then crashes if something is null.) - A data class (the Java equivalent would be a generic class with getters, setters,
hashCode()
, andtoString()
?) is built-in, usingdata class ClassName(*val fields)
. All it does is contain data. - A nullable variable cannot have its methods called unless its null-ness is checked (literally, in your code, write
!= null
). - Classes can have multiple constructors, but only one unique primary constructor. The primary one is just the stuff you put inside
class ClassName constructor(*args)
. All other constructors need to reference the primary constructor one way or the other. init
blocks are pre-constructor methods. A class can have any number of these, interleved with pretty much anything you like, including statements. And then constructors are called.- Kotlin does not have a
new
keyword. - The default base class is
Any
. All classes implicitly inherit fromAny
. - "Overridable" methods are called "open functions", and must be called that to be overridden (e.g.
open fun foo() { ... }
). Overridden methods must also call themselves overrides (e.g.override fun foo() { ... })
. Like Java, any function that is not open can havefinal
in front of it to ensure it is never overridden. - Classes themselves must also be marked as open/override and final with the
open class
syntax. - Properties (i.e. attributes) must also be marked as open/override and final.
- A file can contain multiple classes. See also: coding conventions.
- So Kotlin classes ("KClass") are not Java classes. To get the reference to a class, use
ClassName::class
(a KClass) instead of justClassName
. To get the Java class equivalent, useSomeJavaClass::class.java
instead. - Method calls can seemingly contain bodies for no reason. See this example:
assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
- A lambda's parameters are declared inside its braces, so
onClick({ view -> doSomething() })
is a lambda. If you hate that, you're in luck, because if you don't need any arguments, you can skipview ->
and make it look like something sane, i.e.onClick({ doSomething() })
. - For some reason, instead of stopping there, kotlin enjoys having function arguments outside the parents iff it is the last argument of the function call, so you get
onClick() { doSomething() }
instead. But wait, there's fucking more. If the function call takes just one thing, and that one thing is a function, then you have to skip the parentheses anyway, resulting in the final form:onClick { doSomething() }
. - But if you want to pass in a named function? Fuck you, use parens:
onClick(doSomething)
. - The
with(obj, func)
built-in (bearing in mind the last argument is a function, so the lambda stuff above syntactically applies) is the same as what you used to use in VB6: unresolved names are to be found in the object's attributes. - Comment styles are the same as the majority of others (
//
,/* */
). - Built-in keywords can be hard or soft. You cannot change hard ones, like
if
/else
,class
, andfun
. You can change soft keywords likefile
,get
, andset
. - ALL functions with blocks, i.e. not a one-liner, need an explicit
return
statement if they have a return type. - Because you need to declare parameter types now, the type of a lambda is usually
() -> Unit
, unless they take arguments. That's becauseUnit
maps to a javavoid
by default.() -> Unit
means an anoymous function that returns nothing. - You can also use
() -> Any?
for "function type", for functions that can literally return anything. - The function that accepts a lambda specifies what types the lambda needs to take. The lambdas themselves do not need to (but can) do that.
- "In most cases, Kotlin follows the Java coding conventions", where the official Oracle Java convention says "Avoid lines longer than 80 characters ... Examples for use in documentation should have a shorter line length—generally nomore than 70 characters."
- A one-liner lambda that takes a single argument can be written as something like
it % 2
instead ofnum -> num % 2
. - Java's "anything of some type" syntax,
<?>
, might have been replaced by<*>
. - An array of strings is
Array<String>
. An array of ints is eitherIntArray
, because it's a modern language and is very consistent, orArray<Int>
, which is not proven to work. - A google map won't load until you add the key.
- unlike Java, functions can be top-level. It has however no static methods. The "static method" equivalent would be setting up a
companion object
. Any method you put in that object (similar syntax to how to put methods in ES6 classes) will be effectively static. - Coroutines are not strictly-speaking threads, but in some cases they are implemented as such.
- The built-in
arrayOf(...args)
gives you an array of those args. You don't need to specify the types. If you want to have an empty array, guess what?emptyArray()
getApplicationContext()
becomesapplicationContext
in Kotlin, even though it is a "global".- Double quotes are still strings. Single quotes are still chars.
- Then
when
built-in, actually justswitch-case
, requires you to specify->
in front of each case's code block, i.e.1 -> { ... }
. /* Block comments /* can */ be nested. */
- Strings can have
"substitutions like $this"
(whereval this = "this"
). - It is possible to suffix something to a class, including seemingly built-in ones like
Number
, and instantly create a new attribute. klock does it like so:DateTime.now() + 10.seconds
(whereseconds
is an attribute onNumber
now.) - Nested
this
can be a problem sometimes. JS tackles this by allowing you to assignthis
to some variable. Kotlin allows you to refer tothis
withthis@OuterClassName
. This works at any level. vararg
(*args
equivalent) can only be used once in a function signature, and everything after thevararg
must be named (**kwargs
equivalent).- The spread operator is still
*
. - Kotlin occasionally uses something called the infix notation. Method calls like
a.to(b).as(c)
can simply be written asa to b as c
... but only if you mark the function asinfix
, i.e.infix fun to(b: Int)
, and the function must accept exactly one parameter. Example. tl;dr: for reduce overhead on readability, just don't useinfix
.
suspend fun
declares an async function, just not using theasync
keyword. To use asuspend fun
, you callval foo = async { doStuff() }
, and then sayfoo.await()
to get the result.async { foo() }
can also beasync(start = CoroutineStart.LAZY) { foo() }
, if you want the task to start only when the result is needed.- Return statements can have qualified scopes too:
return@foo ...
. However, it is impossible to return a function from inside a async method. - Primitive function arguments are not mutable. Make another variable.
{ ... }
is simultaneously a "lambda", as well as a "block of code". There seems to be no difference between the two, except you don't hear about the docs talking about code blocks with parameters.- So how do you build a dictionary then? Turns out you don't really do that in any meaningful way yet. You can make a
hashMapOf
something but the"a" to "b"
syntax relies on infix function calls ofto
. - The
{}
in things likesetListener { foo() }
may seem kind of pointless, and it is in other languages, but that's because the{}
helps with type conversion. You can't justsetListener(foo)
. - Private members/methods cannot be accessed by a subclass, even if it itself inherits the method. To access it, use
protected
.
- String interpolation is done with
"this $syntax"
or"that ${syntax(its, up, to, you)}"
. - All functions return
: Unit
(which is void) by default; there is no need to specify it. You can also omit the return type when the compiler can infer it, which is most of the time. - Triple-quoted strings are raw strings (not docstrings). Raw strings don't support escaping but support interpolation (wtf?), so if you want a
$
sign inside your raw string literal, guess what you'll have to do:"""That sucks a${"$$"}"""
trimMargin()
andtrimMargin('|')
(optional margin character) lets you trim off each line of the string, and return one where it starts after the margin character.- I don't think there is a difference between
arrayOf<Int>()
andemptyArray<Int>()
. Both throwArrayIndexOutOfBoundsException
when you try to access an element. But there is also anIntArray
class, and its helper functionintArrayOf()
. AnIntArray(size)
is equivalent java'sint[size]
, which (if I may take an educated guess) is a primitive array, storing literal values insteaad of objects, that is faster than theArray<T>
or something. A good rule of thumb is to useArray
unless a function explicitly asks for anIntArray
(or of any other primitive type). You may encounter primitive arrays of type:booleanArrayOf
(boolean[]
),byteArrayOf
(byte[]
),charArrayOf
(char[]
),doubleArrayOf
(double[]
),floatArrayOf
(float[]
),intArrayOf
(int[]
),longArrayOf
(long[]
), andshortArrayOf
(short[]
). There is nostring[]
; a string is achar[]
. - There is no way to print an array like you would print a python
list
. Use something likearray.forEach(::println)
to achieve a similar effect, but each item will be on a different line. - But you know what you can print in one line?
list
s,map
s, andset
s.list
s are effectively tuples because they are not mutable. - Sets and Lists print out in the same style:
[1, 2, 3]
, with square brackets. - Arrays are fixed-length. Lists may change in size later.
- But wait, what the fuck is a
mutableList
then? (It's a list that is mutable, yes. But, at the same time, this seems to raise more questions about a java/kotlin developer's long-term mental health.) - BUT WAIT. If you think that isn't complicated enough, there is more for you, you mastermind. I present to you: the
ArrayList
(arrayListOf
), a mutable data type that stores values in anarray
, but can also be resized. Also, fuck you. ::function
will reference the function without calling it. So functions aren't exactly first-class in terms of syntax. If you justfunction
, it is not a silent statement; it isFunction invocation 'function()' expected
.- Inline functions (
inline fun
vs justfun
) are like lambdas, except they have a name. Use inline functions for functions that accept another function or block of code, where declaring a function asinline
may occasionally speed up the function by not requiring a new function object to be declared within the callee. You should definitely look more into it. - A
for
loop like1..10
includes 10. To not include 10, use1 until 10
. - If a
for
loop is labelled (e.g.outer@ for(i in 0..10)
), abreak@outer
will break that loop. This is useful for nested loops. - Because of the unique way the Kotlin team is funded, to loop from 1 to 5, you write
for (i in 1..5)
, but if you want to loop from 5 to 1, you writefor(i in 5 downTo 1)
. - There is no such thing as an
open data class
. That means all data classes are final, and are not extendable or reusable in any way. var foo: Type by Bar()
works through delegating getting and setting that variable to a delegate class. A delegate is a class withgetValue()
andsetValue()
defined.