title | date | author | tags | keywords | categories | reward | reward_title | reward_wechat | reward_alipay | source_url | translator | translator_url |
---|---|---|---|---|---|---|---|---|---|---|---|---|
M8 is out! |
2014-07-01 17:00:00 -0700 |
Hadi Hariri |
官方动态 |
false |
Have a nice Kotlin! |
It’s been a really busy couple of months since the last release and we’ve been working hard on making substantial improvements, particularly in terms of speed. We have a lot of goodies for this release. Let’s get started
As a first peek into the future reflective capabilities of Kotlin, you can now access properties as first-class objects in Kotlin:
{% raw %}
{% endraw %}var x = 1
fun main(args: Array<String>) {
println(::x.get()) // prints "1"
::x.set(2)
println(x) // prints "2"
}
{% raw %}
{% endraw %}The “::propertyName” syntax gives a property object so you can get or set its value. You can also access the name of the property (will be useful for frameworks of all sorts). We will add more capabilities in the future. To access a property that is a member of a class, you can say
{% raw %}
{% endraw %}class A(val p: Int)
fun main(args: Array<String>) {
val prop = A::p
println(prop.get(A(1))) // prints "1"
}
{% raw %}
{% endraw %}And, of course, it works for extensions as well:
{% raw %}
{% endraw %}val String.lastChar: Char
get() = this[size - 1]
fun main(args: Array<String>) {
println(String::lastChar.get("abc")) // prints "c"
}
{% raw %}
{% endraw %}Another side of Kotlin’s reflection is its interoperability with Java’s reflection. For example, to find a backing field or a Java method that serves as a getter for a Kotlin property, you can say something like this:
{% raw %}
{% endraw %}import kotlin.reflect.jvm.*
class A(val p: Int)
fun main(args: Array<String>) {
println(A::p.javaGetter) // prints "public final int A.getP()"
println(A::p.javaField) // prints "private final int A.p"
}
{% raw %}
{% endraw %}We will develop reflection capabilities further in the next few months. The ultimate goal is to provide framework writers with really powerful tools for their needs. Things on the agenda include proper Kotlin class introspection, making types available through reflection, bringing reflection capabilities to callable references (::functionName) and more. Stay tuned.
Some enhances for inlining functions including:
-
Support for functions with default parameters.
-
Inlines into objects are supported.
To demonstrate these two features together, let’s look at the following example. Say, we have an Value interface:
{% raw %}
{% endraw %}trait Value<V> {
fun get() : V
}
{% raw %}
{% endraw %}Now, let’s say we want to create values whose computations are guarded by a lock:
{% raw %}
{% endraw %}inline fun <T> guardedValue(
lock: Lock = ReentrantLock(),
compute: () -> T
) : Value<T> {
return object : Value<T> {
override fun get(): T {
return lock.withLock {
compute()
}
}
}
}
{% raw %}
{% endraw %}Our guardedValue() is an inline function. Now, the lock parameter has a default value (a new ReentrantLock is created for every value). Then, the object expression inside this function “captures” the compute parameter, and inlines it directly inside the anonymous class created. This results in only one class and one object emitted (and stored) per value, instead of two classes and two objects for the non-inline case.
{% raw %}
{% endraw %}The compiler now emits errors when some JVM signatures it generates are going to clash in the byte code (previously this could lead to ClassFormatError’s or to accidentally overriding a superclass’ method without knowing it). For example, the following Kotlin code looks harmless, but breaks on the JVM:
{% raw %}
{% endraw %}val x = 1
fun getX() = 1
{% raw %}
{% endraw %}Now, Kotlin complains about this code:
{% raw %}
{% endraw %}Error:(1, 1) Kotlin: Platform declaration clash:
The following declarations have the same JVM signature (getX()I):
fun <get-x>(): kotlin.Int
fun getX(): kotlin.Int
{% raw %}
{% endraw %}The reason is that the getter for x has the same name (getX) and signature (takes no parameters, returns Int) as the function declared next to it and JVM does not allow such things in class files. Another case is an accidental override:
{% raw %}
{% endraw %}open class Base {
fun getX() = 1
}
class Derived(val x: Int) : Base()
{% raw %}
{% endraw %}Here, the getter for x again has the same signature as getX(), but they are now in different classes, so the getter would silently override the function, so that Derived(2).getX() would return 2 instead of 1. Now the compiler catches this and the error is
{% raw %}
{% endraw %}Error:(1, 15) Kotlin: Accidental override:
The following declarations have the same JVM signature (getX()I):
fun <get-x>(): kotlin.Int
fun getX(): kotlin.Int
{% raw %}
{% endraw %}One may wonder why wouldn’t we, say, rename one of the functions automatically instead of emitting an error? The answers lie in the realm of Java interoperability (nobody likes names invented by the compiler) and binary compatibility (names of things must never change silently, or all dependent code will unexpectedly break). On the other hand, you can specify desired JVM names manually with the platformName annotation:
{% raw %}
{% endraw %}import kotlin.platform.platformName
val x = 1
[platformName("doGetX")]
fun getX() = 1
{% raw %}
{% endraw %}Note that nothing changes when for the Kotlin clients of this code, but Java clients must use the platform name (doGetX) instead of Kotlin name (getX). WARNING: This is a breaking change, some of your existing code may need to be fixed.
In addition to the long-available volatile. We now support transient, synchronized and strictfp as annotations. The semantics are exactly like in Java:
{% raw %}
{% endraw %}class FlagDemo {
volatile var s = ""
transient var list = listOf(1, 2, 3)
strictfp fun math() { /* strict floating-point available here */ }
synchronized fun sync() { /* synchronized on this */ }
}
{% raw %}
{% endraw %}- Generated code for delegated properties works much faster now, and make a lot fewer memory allocations.
- In addition when statements with constants are faster because of dedicated bytecode instructions now being used.
- You now have Data Classes support in JavaScript. This means that you can now get toString, equals and hashCode generated automatically when annotating classes with the data annotation in JavaScript too, as well as in Java.
- In addition, LinkedHashSet and LinkedHashMap are also supported in JavaScript.
A few language changes, all of which are breaking changes, so important to take note:
- private in a package now means private to the current package inside the module. Packages with the same name in other modules won’t see these definitions. Note that packages are nested, so privates are also visible to subpackages in the same module.
- Extension Properties cannot have backing fields. This was never recommended anyway.
- If you ever discovered that Kotlin allowed “@” and “@@” as label names, we are sorry to tell you that this is no longer so.
The standard library gets some new functionality also:
- slice() function added that takes an iterable of integers and returns a list containing the elements in said positions.
- join() works on iterables (array, lists, etc.) of strings and combines them into one string
- joinToString() works on iterables or arrays of any type and is equivalent to .map { it.toString() }.join()
- Maps now have overloaded functions contains()., thus enabling things like “key in map” by convention
- Strings now can take advantage of collection like functions including
substringBefore, substringBeforeLast and substringAfter, substringAfterLast allowing to find string before and after a certain character or string. replaceBefore, replaceBeforeLast and replaceAfter, replaceAfterLast allowing to replace strings before and after a certain character or string. appendln added to StringBuilder A new StringBuilder function that takes a String builder extensions, allowing for code such as:
val information = StringBuilder {
append("A first entry")
appendln()
appendln("Some other line")
}
12345
val information = StringBuilder { append("A first entry") appendln() appendln("Some other line") }
-
substringBefore, substringBeforeLast and substringAfter, substringAfterLast allowing to find string before and after a certain character or string.
-
replaceBefore, replaceBeforeLast and replaceAfter, replaceAfterLast allowing to replace strings before and after a certain character or string.
-
appendln added to StringBuilder
-
A new StringBuilder function that takes a String builder extensions, allowing for code such as:
-
Iterables now have merge function which returns a new list containing elements merged from two collections on which a transformation has been applied