Implemented delegated properties.

This commit is contained in:
Igor Chevdar
2017-02-28 12:25:24 +03:00
parent 02d0307609
commit 94fd86f906
15 changed files with 684 additions and 74 deletions
@@ -54,6 +54,16 @@ public annotation class FixmeVariance
*/
public annotation class FixmeRegex
/**
* Need to be fixed because of reflection.
*/
public annotation class FixmeReflection
/**
* Need to be fixed because of concurrency.
*/
public annotation class FixmeConcurrency
/**
* Need to be fixed.
*/
+206
View File
@@ -0,0 +1,206 @@
package kotlin
import kotlin.reflect.KProperty
/**
* Represents a value with lazy initialization.
*
* To create an instance of [Lazy] use the [lazy] function.
*/
public interface Lazy<out T> {
/**
* Gets the lazily initialized value of the current Lazy instance.
* Once the value was initialized it must not change during the rest of lifetime of this Lazy instance.
*/
public val value: T
/**
* Returns `true` if a value for this Lazy instance has been already initialized, and `false` otherwise.
* Once this function has returned `true` it stays `true` for the rest of lifetime of this Lazy instance.
*/
public fun isInitialized(): Boolean
}
/**
* Creates a new instance of the [Lazy] that is already initialized with the specified [value].
*/
public fun <T> lazyOf(value: T): Lazy<T> = InitializedLazyImpl(value)
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
* the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
*/
@FixmeConcurrency
public fun <T> lazy(initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)//SynchronizedLazyImpl(initializer)
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and thread-safety [mode].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* Note that when the [LazyThreadSafetyMode.SYNCHRONIZED] mode is specified the returned instance uses itself
* to synchronize on. Do not synchronize from external code on the returned instance as it may cause accidental deadlock.
* Also this behavior can be changed in the future.
*/
@FixmeConcurrency
public fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
LazyThreadSafetyMode.SYNCHRONIZED -> TODO()//SynchronizedLazyImpl(initializer)
LazyThreadSafetyMode.PUBLICATION -> TODO()//SafePublicationLazyImpl(initializer)
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
}
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* The returned instance uses the specified [lock] object to synchronize on.
* When the [lock] is not specified the instance uses itself to synchronize on,
* in this case do not synchronize from external code on the returned instance as it may cause accidental deadlock.
* Also this behavior can be changed in the future.
*/
@FixmeConcurrency
public fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = TODO()//SynchronizedLazyImpl(initializer, lock)
/**
* An extension to delegate a read-only property of type [T] to an instance of [Lazy].
*
* This extension allows to use instances of Lazy for property delegation:
* `val property: String by lazy { initializer }`
*/
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
/**
* Specifies how a [Lazy] instance synchronizes access among multiple threads.
*/
public enum class LazyThreadSafetyMode {
/**
* Locks are used to ensure that only a single thread can initialize the [Lazy] instance.
*/
SYNCHRONIZED,
/**
* Initializer function can be called several times on concurrent access to uninitialized [Lazy] instance value,
* but only first returned value will be used as the value of [Lazy] instance.
*/
PUBLICATION,
/**
* No locks are used to synchronize the access to the [Lazy] instance value; if the instance is accessed from multiple threads, its behavior is undefined.
*
* This mode should be used only when high performance is crucial and the [Lazy] instance is guaranteed never to be initialized from more than one thread.
*/
NONE,
}
private object UNINITIALIZED_VALUE
//private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
// private var initializer: (() -> T)? = initializer
// @Volatile private var _value: Any? = UNINITIALIZED_VALUE
// // final field is required to enable safe publication of constructed instance
// private val lock = lock ?: this
//
// override val value: T
// get() {
// val _v1 = _value
// if (_v1 !== UNINITIALIZED_VALUE) {
// @Suppress("UNCHECKED_CAST")
// return _v1 as T
// }
//
// return synchronized(lock) {
// val _v2 = _value
// if (_v2 !== UNINITIALIZED_VALUE) {
// @Suppress("UNCHECKED_CAST") (_v2 as T)
// }
// else {
// val typedValue = initializer!!()
// _value = typedValue
// initializer = null
// typedValue
// }
// }
// }
//
// override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
//
// override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
//
// private fun writeReplace(): Any = InitializedLazyImpl(value)
//}
internal class UnsafeLazyImpl<out T>(initializer: () -> T) : Lazy<T>/*, Serializable*/ {
private var initializer: (() -> T)? = initializer
private var _value: Any? = UNINITIALIZED_VALUE
override val value: T
get() {
if (_value === UNINITIALIZED_VALUE) {
_value = initializer!!()
initializer = null
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
private class InitializedLazyImpl<out T>(override val value: T) : Lazy<T>/*, Serializable*/ {
override fun isInitialized(): Boolean = true
override fun toString(): String = value.toString()
}
//private class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
// private var initializer: (() -> T)? = initializer
// @Volatile private var _value: Any? = UNINITIALIZED_VALUE
// // this final field is required to enable safe publication of constructed instance
// private val final: Any = UNINITIALIZED_VALUE
//
// override val value: T
// get() {
// if (_value === UNINITIALIZED_VALUE) {
// val initializerValue = initializer
// // if we see null in initializer here, it means that the value is already set by another thread
// if (initializerValue != null) {
// val newValue = initializerValue()
// if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
// initializer = null
// }
// }
// }
// @Suppress("UNCHECKED_CAST")
// return _value as T
// }
//
// override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
//
// override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
//
// private fun writeReplace(): Any = InitializedLazyImpl(value)
//
// companion object {
// private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
// SafePublicationLazyImpl::class.java,
// Any::class.java,
// "_value")
// }
//}
@@ -0,0 +1,55 @@
package kotlin.properties
import kotlin.reflect.KProperty
/**
* Standard property delegates.
*/
public object Delegates {
/**
* Returns a property delegate for a read/write property with a non-`null` value that is initialized not during
* object construction time but at a later time. Trying to read the property before the initial value has been
* assigned results in an exception.
*/
public fun <T: Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
/**
* Returns a property delegate for a read/write property that calls a specified callback function when changed.
* @param initialValue the initial value of the property.
* @param onChange the callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
/**
* Returns a property delegate for a read/write property that calls a specified callback function when changed,
* allowing the callback to veto the modification.
* @param initialValue the initial value of the property.
* @param onChange the callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* 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 and the property remains its old value.
*/
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
}
private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
@@ -0,0 +1,49 @@
package kotlin.properties
import kotlin.reflect.KProperty
/**
* Base interface that can be used for implementing property delegates of read-only properties.
*
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
public interface ReadOnlyProperty<in R, out T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
}
/**
* Base interface that can be used for implementing property delegates of read-write properties.
*
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
public interface ReadWriteProperty<in R, T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
@@ -0,0 +1,38 @@
package kotlin.properties
import kotlin.reflect.KProperty
/**
* Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
* @param initialValue the initial value of the property.
*/
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
/**
* The callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* 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 and the property remains its old value.
*/
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
/**
* The callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
protected open fun afterChange (property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
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)
}
}
@@ -0,0 +1,14 @@
package kotlin.reflect
/**
* Represents an annotated element and allows to obtain its annotations.
* See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/annotations.html)
* for more information.
*/
@FixmeReflection
public interface KAnnotatedElement {
// /**
// * Annotations which are present on this element.
// */
// public val annotations: List<Annotation>
}
@@ -0,0 +1,75 @@
package kotlin.reflect
/**
* Represents a callable entity, such as a function or a property.
*
* @param R return type of the callable.
*/
@FixmeReflection
public interface KCallable<out R> : KAnnotatedElement {
/**
* The name of this callable as it was declared in the source code.
* If the callable has no name, a special invented name is created.
* Nameless callables include:
* - constructors have the name "<init>",
* - property accessors: the getter for a property named "foo" will have the name "<get-foo>",
* the setter, similarly, will have the name "<set-foo>".
*/
public val name: String
// /**
// * Parameters required to make a call to this callable.
// * If this callable requires a `this` instance or an extension receiver parameter,
// * they come first in the list in that order.
// */
// public val parameters: List<KParameter>
//
// /**
// * The type of values returned by this callable.
// */
// public val returnType: KType
//
// /**
// * The list of type parameters of this callable.
// */
// @SinceKotlin("1.1")
// public val typeParameters: List<KTypeParameter>
//
// /**
// * Calls this callable with the specified list of arguments and returns the result.
// * Throws an exception if the number of specified arguments is not equal to the size of [parameters],
// * or if their types do not match the types of the parameters.
// */
// public fun call(vararg args: Any?): R
//
// /**
// * Calls this callable with the specified mapping of parameters to arguments and returns the result.
// * If a parameter is not found in the mapping and is not optional (as per [KParameter.isOptional]),
// * or its type does not match the type of the provided value, an exception is thrown.
// */
// public fun callBy(args: Map<KParameter, Any?>): R
//
// /**
// * Visibility of this callable, or `null` if its visibility cannot be represented in Kotlin.
// */
// @SinceKotlin("1.1")
// public val visibility: KVisibility?
//
// /**
// * `true` if this callable is `final`.
// */
// @SinceKotlin("1.1")
// public val isFinal: Boolean
//
// /**
// * `true` if this callable is `open`.
// */
// @SinceKotlin("1.1")
// public val isOpen: Boolean
//
// /**
// * `true` if this callable is `abstract`.
// */
// @SinceKotlin("1.1")
// public val isAbstract: Boolean
}
@@ -0,0 +1,67 @@
package kotlin.reflect
/**
* Represents a property, such as a named `val` or `var` declaration.
* Instances of this class are obtainable by the `::` operator.
* See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/reflection.html)
* for more information.
*
* @param R the type of the property.
*/
@FixmeReflection
public interface KProperty<out R> : KCallable<R> {
// /**
// * `true` if this property is `lateinit`.
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties)
// * for more information.
// */
// @SinceKotlin("1.1")
// public val isLateinit: Boolean
//
// /**
// * `true` if this property is `const`.
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants)
// * for more information.
// */
// @SinceKotlin("1.1")
// public val isConst: Boolean
//
// /** The getter of this property, used to obtain the value of the property. */
// public val getter: Getter<R>
//
// /**
// * Represents a property accessor, which is a `get` or `set` method declared alongside the property.
// * See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/properties.html#getters-and-setters)
// * for more information.
// *
// * @param R the type of the property, which it is an accessor of.
// */
// public interface Accessor<out R> {
// /** The property which this accessor is originated from. */
// public val property: KProperty<R>
// }
//
// /**
// * Getter of the property is a `get` method declared alongside the property.
// */
// public interface Getter<out R> : Accessor<R>, KFunction<R>
}
/**
* Represents a property declared as a `var`.
*/
@FixmeReflection
public interface KMutableProperty<R> : KProperty<R> {
// /** The setter of this mutable property, used to change the value of the property. */
// public val setter: Setter<R>
//
// /**
// * Setter of the property is a `set` method declared alongside the property.
// */
// public interface Setter<R> : KProperty.Accessor<R>, KFunction<Unit>
}
@FixmeReflection
public class KPropertyImpl<out R>(override val name: String) : KProperty<R> {
}