property that calls a specified callback function when changed. var maxCount: Int by observable(initialValue = 0) { property, oldValue, newValue -> println("${property.name} is being changed from $oldValue to $newValue") }
{ private var value: T? = null override fun getValue(thisRef: Any, property: KProperty<*>) = value override fun setValue(thisRef: Any, property: KProperty<*>, value: T?) { this.value = value } } private var someNum by SimpleDelegate<Int>() private var someStr by SimpleDelegate<String>() <R> (“Any”) is the containing class (“thisRef”), so usually Any is suffiicient.
value: T? = null operator fun getValue(thisRef: Any, property: KProperty<*>) = value operator fun setValue(thisRef: Any, property: KProperty<*>, value: T?) { this.value = value } } // Lazy.kt does it as an extension function public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer) public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
T> { private var value = initialValue /** * If the callback returns `true` the value of the property is being set to the new value, * and if the callback returns `false` the new value is discarded. */ protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {} public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { val oldValue = this.value if (!beforeChange(property, oldValue, value)) { return } this.value = value afterChange(property, oldValue, value) } public override fun getValue(thisRef: Any?, property: KProperty<*>): T { return value }
T) { val prefs: SharedPreferences by lazy { context.getSharedPreferences(PREFS_FILE_NAME, Context.MODE_PRIVATE) } operator fun getValue(thisRef: Any?, property: KProperty<*>) = with(prefs) { when (defaultValue) { is Boolean -> getBoolean(key, defaultValue) is Int -> getInt(key, defaultValue) ... else -> throw IllegalArgumentException() } } as T operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = with(prefs.edit()) { when (value) { is Boolean -> putBoolean(key, value) is Int -> putInt(key, value) ... }.apply() } } val myStringPref by SharedPrefDelegate<String>(key, defaultValue = "") val myIntPref by SharedPrefDelegate<Int>(key, defaultValue = 0)
value left by the [bitCount] number of bits. */ public infix fun shl(bitCount: Int): Int /** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with copies of the sign bit. */ public infix fun shr(bitCount: Int): Int /** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with zeros. */ public infix fun ushr(bitCount: Int): Int /** Performs a bitwise AND operation between the two values. */ public infix fun and(other: Int): Int /** Performs a bitwise OR operation between the two values. */ public infix fun or(other: Int): Int /** Performs a bitwise XOR operation between the two values. */ public infix fun xor(other: Int): Int
public infix fun CharSequence.zip(other: CharSequence): List<Pair<Char, Char>> public infix fun <T, R> Iterable<T>.zip(other: Array<out R>): List<Pair<T, R>> public infix fun <T> Iterable<T>.intersect(other: Iterable<T>): Set<T> public infix fun <T> Iterable<T>.union(other: Iterable<T>): Set<T> public infix fun <T> Iterable<T>.subtract(other: Iterable<T>): Set<T>
T) = items.takeWhile { it != stopAt }.let { println(it) } // Only one upper bound can be specified inside the angle brackets // Number does not implement Comparable fun <T : Number> printUntil(items: List<T>, stopAt: T) = items.takeWhile { it < stopAt }.let { println(it) }
@param:ParamAnnotation val first: String, @field:FieldAnnotation val last: String ) { // ... } public final class Person { @NotNull private final String first; @FieldAnnotation @NotNull private final String last; @NotNull public final String getFirst() { return this.first; } @NotNull public final String getLast() { return this.last; } public Person(@ParamAnnotation @NotNull String first, @NotNull String last) { super(); this.first = first; this.last = last; } }
annotation class PropertyAnnotation class SomeClass1( @property:PropertyAnnotation val constructorProp: String ) { @property:PropertyAnnotation val regProp = "Test" } fun main(args: Array<String>) { for (property in SomeClass1::class.memberProperties) { println("Property ${property.name} has annotations ${property.annotations}") } val primaryConstructor = SomeClass1::class.primaryConstructor!! for (param in primaryConstructor.parameters) { println("Parameter ${param.name} has annotations ${param.annotations}") } } Property constructorProp has annotations [@com.brentwatson.droidcon.targets.PropertyAnnotation()] Property regProp has annotations [@com.brentwatson.droidcon.targets.PropertyAnnotation()] Parameter constructorProp has annotations []
val name by lazy { "something" } } public final class MyDel { @DelegateAnnotation @NotNull private final Lazy name$delegate; @GetAnnotation @NotNull public final String getName() { Lazy var1 = this.name$delegate; KProperty var3 = $$delegatedProperties[0]; return (String)var1.getValue(); } public MyDel() { this.name$delegate = LazyKt.lazy((Function0)null.INSTANCE); } }
var something: String? = null } public final class SetParamAnnTest { @Nullable private String something; @Nullable public final String getSomething() { return this.something; } @SetAnnotation public final void setSomething( @SetParamAnnotation @Nullable String var1 ) { this.something = var1; } }
calculating before returning a value Is limited by the heap size. Corecursive functions calls itself indefinitely (like a infinite loop) Each step is evaluated as it happens Builds up values Is not limited by the heap size Usually easiest to think about solving a problem backwards
x 3 x 2 x 1 == 120 // recursion fun factorial(n: Int): Int = if (n == 1) n else n * factorial(n - 1) // corecursion fun factorial(next: Int, total: Int): Int = when (next) { 1 -> total else -> factorial(next - 1, total * next) }
x 3 x 2 x 1 == 120 // recursion tailrec fun factorial(n: Int): Int = if (n == 1) n else n * factorial(n - 1) // corecursion tailrec fun factorial(next: Int, total: Int): Int = when (next) { 1 -> total else -> factorial(next - 1, total * next) }
x 1 == 120 // recursion tailrec fun factorial(n: Int): Int = if (n == 1) n else n * factorial(n - 1) // corecursion tailrec fun factorial(next: Int, total: Int): Int = when (next) { 1 -> total else -> factorial(next - 1, total * next) } public final class RecursionKt { public static final int factorial(int n) { return n == 1 ? n : n * factorial(n - 1); } public static final int factorial(int next, int total) { while(next != 1) { int var = next - 1; total *= next; next = var; } return total; } }
for loop for (item in items) { • used as an infix operator to check that a value belongs to a range (or anything that defines the contains() method). val isInRange = 5 in 1..10 • in when expressions for the same purpose when(size) { in 1..10 -> println("small") in 11..100 -> println("medium") in 101..1000 -> println("large") else -> println("Fuhgeddaboudit") } • marks a type parameter as contravariant
class Android( val manufacturer: String, val sdkVersion: Int ) : Phone() class BlackBerry( val obsolete: Boolean = true, val sdkVersion: Int ) : Phone() } }
class Android( val manufacturer: String, val sdkVersion: Int ) : Phone() class BlackBerry( val obsolete: Boolean = true, val sdkVersion: Int ) : Phone() } } class Manufacturer<out T: Hardware> { fun create(): T { } } class MyDriveWay<in T: Hardware> { fun pleaseShatterMyScreen(t: T) {} }
class Android( val manufacturer: String, val sdkVersion: Int ) : Phone() class BlackBerry( val obsolete: Boolean = true, val sdkVersion: Int ) : Phone() } } class Manufacturer<out T: Hardware> { fun create(): T { } } class MyDriveWay<in T: Hardware> { fun pleaseShatterMyScreen(t: T) {} } val producer = Manufacturer<Hardware.Phone>() val consumer = MyDriveWay<Hardware.Phone>() val phone: Hardware.Phone = producer.create() consumer.pleaseShatterMyScreen(phone)
class Android( val manufacturer: String, val sdkVersion: Int ) : Phone() class BlackBerry( val obsolete: Boolean = true, val sdkVersion: Int ) : Phone() } } class Manufacturer<out T: Hardware> { fun create(): T { } } class MyDriveWay<in T: Hardware> { fun pleaseShatterMyScreen(t: T) {} } val producer = Manufacturer<Hardware.Phone>() val consumer = MyDriveWay<Hardware.Phone>() val hardware: Hardware = producer.create() val phone: Hardware.Phone = producer.create() consumer.pleaseShatterMyScreen(phone) consumer.pleaseShatterMyScreen(android)
class Android( val manufacturer: String, val sdkVersion: Int ) : Phone() class BlackBerry( val obsolete: Boolean = true, val sdkVersion: Int ) : Phone() } } class Manufacturer<out T: Hardware> { fun create(): T { } } class MyDriveWay<in T: Hardware> { fun pleaseShatterMyScreen(t: T) {} } val producer = Manufacturer<Hardware.Phone>() val consumer = MyDriveWay<Hardware.Phone>() val hardware: Hardware = producer.create() val phone: Hardware.Phone = producer.create() val android: Hardware.Phone.Android = producer.create() consumer.pleaseShatterMyScreen(hardware) consumer.pleaseShatterMyScreen(phone) consumer.pleaseShatterMyScreen(android)
public val isFinal: Boolean public val isOpen: Boolean public val isAbstract: Boolean public val isSealed: Boolean public val isData: Boolean public val isInner: Boolean public val isCompanion: Boolean public val visibility: KVisibility? public val simpleName: String? public val qualifiedName: String? override val members: Collection<KCallable<*>> // KDeclarationContainer override val annotations: List<Annotation> // KAnnotatedElement public val constructors: Collection<KFunction<T>> public val nestedClasses: Collection<KClass<*>> public val supertypes: List<KType> public val typeParameters: List<KTypeParameter> }
... } @Suppress("UPPER_BOUND_VIOLATED") public val <T> KClass<T>.java: Class<T> @JvmName("getJavaClass") get() = (this as ClassBasedDeclarationContainer).jClass as Class<T>
Int by observable(initialValue = 0) { property: KProperty<*>, oldValue, newValue -> println("${property.name} is being changed from $oldValue to $newValue") }
Int by observable(initialValue = 0) { property: KProperty<*>, oldValue, newValue -> println("${property.name} is being changed from $oldValue to $newValue") } fun KProperty<*>.log() { println("${this.name} is set to ${this.getter.call()}") } demo::p1.log()
by Jake Wharton • Kotlin 102 - Beyond the basics by Hadi Hariri • Christina Lee - Advanced Kotlin (Øredev 2017) • Kotlin Puzzlers by Anton Keks (KotlinConf 2017)