Delete docs folder with old confluence documentation and talks presentations
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,72 +0,0 @@
|
||||
Code Generation 2012 - Session Proposal Form
|
||||
|
||||
Submission Deadline: Friday December 9th 2011
|
||||
|
||||
Session title:
|
||||
|
||||
DSLs in Kotlin
|
||||
|
||||
Session type and duration:
|
||||
|
||||
Tutorial, 60 min
|
||||
|
||||
Session abstract:
|
||||
|
||||
Kotlin is a statically typed programming language for the JVM, proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. The language is fully Java compatible, so one can mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin.
|
||||
|
||||
In this session we will demonstrate Kotlin's abilities to define APIs as domain-specific languages (DSLs). This includes explanation of interesting language features illustrated with practical use-cases.
|
||||
|
||||
As a flagship example we will present Type-safe Builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. This enables specifying declarative data right inside the code. Want to describe a build file? Xml/HTML? Swing UI? Use builders! We will show how Kotlin compiler itself uses builders to specify modules. Along with this example we will show and explain a few other DSLs built in Kotlin.
|
||||
|
||||
Benefits of participating:
|
||||
|
||||
Participants will learn about Kotlin and how a few language features can be combined to create internal DSLs in a natural and flexible way.
|
||||
|
||||
Process & timetable:
|
||||
|
||||
Introduction to Kotlin — 7-10 minutes
|
||||
Q&A - 5 minutes
|
||||
DSL-enabling features - 15 minutes
|
||||
Q&A - 5 minutes
|
||||
Builders (live demo) - 20 minutes
|
||||
Q&A - 5 minutes
|
||||
|
||||
Session outputs:
|
||||
|
||||
Slides, example code
|
||||
|
||||
Intended Audience:
|
||||
|
||||
The session is intended for developers and tech leads.
|
||||
We expect the audience to be familiar with basic concepts of OOP and some of the statically typed languages (Java, Scala, C#, C++ etc).
|
||||
|
||||
Availability:
|
||||
|
||||
No constraints
|
||||
|
||||
Detailed Description / Supporting Information
|
||||
|
||||
Kotlin is a new statically typed JVM-targeted programming language developed by JetBrains and intended for industrial use. Kotlin is designed to be fully Java compatible, and at the same time safer, more concise than Java and way simpler than its main competitor, Scala. Also, IDE support is being developed in parallel with the language itself.
|
||||
|
||||
This session focuses on the language features that enable DSL creation and corresponding patterns.
|
||||
|
||||
During the introduction, we will give an overview of the language. The features we’re planning to cover include:
|
||||
* function literals (closures);
|
||||
* extension functions;
|
||||
* type inference;
|
||||
* operator overloading/overriding;
|
||||
* null safety and automatic casts.
|
||||
|
||||
As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. Builders are a flexible and clean way of describing declarative data in the code with very little syntactic overhead. The technique is so handy that Kotlin uses it instead of XML for compiler configuration, which we will show in action along with XML/HTML and Swing UI building.
|
||||
This part is presented as a live demo within the IntelliJ IDEA IDE for Kotlin. Along with this example we'll demonstrate a DSL for LINQ-like collection processing and how to turn any type into a Fluent interface (http://martinfowler.com/bliki/FluentInterface.html) with extension functions.
|
||||
|
||||
This session has not been run before, but the material we use is partly taken from Kotlin talks from OSCON, StrangeLoop and Devoxx.
|
||||
|
||||
Main presenter name, contact details and biography
|
||||
|
||||
Name: Andrey Breslav
|
||||
Affiliation: JetBrains
|
||||
Telephone / Skype: andrey.breslav @ skype
|
||||
Email: andrey.breslav@jetbrains.com
|
||||
Biography (up to 100 words):
|
||||
Andrey is the lead language designer working on Project Kotlin. He joined JetBrains in 2010.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,56 +0,0 @@
|
||||
{section}
|
||||
{column:width=512px}
|
||||
h3. What is [Kotlin]?
|
||||
"Project [Kotlin]" is a codename for a statically typed programming language compiled to JVM byte code and JavaScript.
|
||||
It is developed by [JetBrains|http://jetbrains.com] and distributed under [Apache 2 Open Source License|http://www.apache.org/licenses/LICENSE-2.0.html].
|
||||
{note:title=Kotlin is Under Development}Please report bugs to our [Issue Tracker|http://youtrack.jetbrains.com/issues/KT]{note}
|
||||
See our [*blog*|http://blog.jetbrains.com/kotlin/]. Follow us on [*Twitter*|http://twitter.com/#!/project_kotlin]. Join our [*forum*|http://devnet.jetbrains.net/community/kotlin].
|
||||
h3. Hello, world!
|
||||
{jet}
|
||||
package hello
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
println("Hello, world!")
|
||||
}
|
||||
{jet}
|
||||
h3. More Examples
|
||||
[Kotlin Web Demo|http://kotlin-demo.jetbrains.com] offers many runnable example programs.
|
||||
You can also *write your own programs* right in the browser and run them on JVM or JavaScript platform.
|
||||
h3. Documentation
|
||||
The [Getting Started] page describes the set-up process.
|
||||
The [Docs Home] page will guide you through the documentation.
|
||||
*New*: Documentation for the [Kotlin standard APIs|http://jetbrains.github.com/kotlin/apidoc/stdlib/].
|
||||
See this presentation for the introduction:
|
||||
{widget:url=http://www.slideshare.net/abreslav/kotlin-devoxx-2011}
|
||||
[*Slides* and *video* from StrangeLoop 2011|http://www.infoq.com/presentations/The-Kotlin-Programming-Language]
|
||||
h3. Source Code
|
||||
Check out the sources on [GitHub|http://github.com/jetbrains/kotlin].
|
||||
Sources are distributed under *Apache 2* license.
|
||||
Nightly builds can be downloaded from our [build server|https://teamcity.jetbrains.com/viewType.html?buildTypeId=bt345&tab=buildTypeStatusDiv&guest=1].
|
||||
You can also use [http://www.jetbrains.com/kotlin/eap-plugin-repository/updatePlugins.xml] to set up a *plugin repository* in IntelliJ IDEA.
|
||||
{info}
|
||||
The IDE plugin requires the latest EAP build of [IntelliJ IDEA 11.1|http://eap.jetbrains.com/idea].
|
||||
{info}
|
||||
|
||||
h3. Kontributions
|
||||
* [stdlib|https://github.com/JetBrains/kotlin/tree/master/stdlib] by James Strachan
|
||||
* [Ant, Maven etc integration|https://github.com/JetBrains/kotlin/tree/master/ant] by Evgeny Goldin
|
||||
* [Aztec|https://github.com/kondratovich/aztec] by Andrew Kondratovich
|
||||
* [Be the next Kontributor!|http://blog.jetbrains.com/kotlin/2012/03/contributing-to-kotlin/]
|
||||
{column}
|
||||
{column}
|
||||
h3. IDE
|
||||
{widget:width=500|url=http://www.youtube.com/watch?v=0jBPcIPVihI}
|
||||
|
||||
h3. Recommended reading
|
||||
* [The Kotlin Journey by Hadi Hariri|http://hadihariri.com/2012/02/17/the-kotlin-journey-part-i-getting-things-set-up/]
|
||||
* [Kotlin: The Language of the Month (Dr. Dobb's)|http://drdobbs.com/jvm/232600839]
|
||||
* [Язык программирования Kotlin|http://www.osp.ru/os/2011/09/13011550/] (in Russian)
|
||||
|
||||
h3. Twitter
|
||||
{widget:url=http://search.twitter.com/search?q=kotlin%20OR%20project_kotlin%20-kotlin_ru|width=500}
|
||||
|
||||
h3. Kotlin Events
|
||||
{widget:width=500px|height=300px|url=https://www.google.com/calendar/embed?mode=AGENDA&showPrint=0&showCalendars=0&showTitle=0&src=nvijaubrlepgko0alipqhpmtj8%40group.calendar.google.com&ctz=Europe/Moscow}
|
||||
{column}
|
||||
{section}
|
||||
@@ -1,89 +0,0 @@
|
||||
The most basic usage of *enum* classes is implementing [_type-safe enums_, like in *Java*|http://www.javacamp.org/designPattern/enum.html]:
|
||||
{jet}
|
||||
enum class Direction {
|
||||
NORTH; SOUTH; WEST; EAST
|
||||
}
|
||||
{jet}
|
||||
As everywhere in [Kotlin], one can omit semicolons if each enum constant is situated on its own line:
|
||||
{jet}
|
||||
enum class Direction {
|
||||
NORTH
|
||||
SOUTH
|
||||
WEST
|
||||
EAST
|
||||
}
|
||||
{jet}
|
||||
|
||||
{note:title=Enums are under development}See the corresponding [issues|http://youtrack.jetbrains.com/issues/KT?q=%23unresolved+enum].{note}
|
||||
|
||||
h4. Open enums
|
||||
|
||||
In [Kotlin] *enums* can be *open*, i.e. can be subclassed by other enums:
|
||||
{jet}
|
||||
open enum class OptionKeys {
|
||||
OPTION1
|
||||
}
|
||||
enum class ExtraOptionKeys : OptionKeys {
|
||||
OPTION2
|
||||
}
|
||||
fun demo() {
|
||||
ExtraOptionKeys.OPTION2 : ExtraOptionKeys // legal
|
||||
ExtraOptionKeys.OPTION1 : OptionKeys // legal
|
||||
OptionKeys.<unresolved desc="Unresolved symbol">OPTION2</unresolved> // error: OPTION2 is not a member of OptionKeys
|
||||
}
|
||||
{jet}
|
||||
Enums can extend other enums and traits as well.
|
||||
|
||||
h4. Enums constants are objects
|
||||
|
||||
Since enum constants are different instances of the *enum class*, they can be initialized differently:
|
||||
{jet}
|
||||
enum class Color(val rgb : Int) {
|
||||
RED : Color(0xFF0000)
|
||||
GREEN : Color(0x00FF00)
|
||||
BLUE : Color(0x0000FF)
|
||||
}
|
||||
{jet}
|
||||
|
||||
h4. Enum constants define (anonymous) classes
|
||||
|
||||
Each enum constant may declare its own members and override members of the *enum class*:
|
||||
{jet}
|
||||
enum class ProtocolState {
|
||||
WAITING {
|
||||
override fun signal() = TALKING
|
||||
}
|
||||
|
||||
TALKING {
|
||||
override fun signal() = WAITING
|
||||
}
|
||||
|
||||
abstract fun signal() : ProtocolState
|
||||
}
|
||||
{jet}
|
||||
|
||||
h4. Constructors in enum classes
|
||||
|
||||
Enum classes actually encode (generalized) Algebraic Data Types, and thus may have _named constructors_ instead of constants:
|
||||
{jet}
|
||||
enum class List<out T>(val size : Int) {
|
||||
Nil : List<Nothing>(0)
|
||||
Cons<T>(h : T, t : List<T>) : List<T>(t.size + 1)
|
||||
}
|
||||
{jet}
|
||||
|
||||
h4. Pattern matching
|
||||
|
||||
Enums classes are integrated with [pattern matching|Pattern matching]:
|
||||
{jet}
|
||||
fun List<String>.join(separator : String) =
|
||||
when (this) {
|
||||
is List.Nil -> "[]"
|
||||
is List.Cons#(val h, val tail) -> h + separator + tail.join(separator)
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Nested classes]
|
||||
* [Object expressions and Declarations]
|
||||
@@ -1,34 +0,0 @@
|
||||
Classes can be nested in other classes:
|
||||
{jet}
|
||||
class Outer() {
|
||||
private val bar : Int = 1
|
||||
class Nested() {
|
||||
fun foo() = 2
|
||||
}
|
||||
}
|
||||
|
||||
val demo = Outer.Inner().foo() // == 2
|
||||
{jet}
|
||||
|
||||
h3. Inner classes
|
||||
|
||||
A class may be marked as *inner* to be able to access members of outer class. Inner classes carry a reference to an object of an outer class:
|
||||
|
||||
{jet}
|
||||
class Outer() {
|
||||
private val bar : Int = 1
|
||||
inner class Inner() {
|
||||
fun foo() = bar
|
||||
}
|
||||
}
|
||||
|
||||
val demo = Outer().Inner().foo() // == 1
|
||||
{jet}
|
||||
|
||||
See [Qualified *this* expressions|This expressions#Qualified] to learn about disambiguation of *this* in inner classes.
|
||||
|
||||
{note:title=Inner classes are under development}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1174].{note}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Object expressions and Declarations]
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
Sometimes we need to create an object of a slight modification of some class, without explicitly declaring a new subclass for it. *Java* handles this case with _anonymous inner classes_. [Kotlin] slightly generalizes this concept with *object* expressions and *object* declarations.
|
||||
|
||||
h3. Object expressions
|
||||
|
||||
To create an object of an anonymous class that inherits from some type (or types), one writes:
|
||||
{jet}
|
||||
window.addMouseListener(object : MouseAdapter() {
|
||||
override fun mouseClicked(e : MouseEvent) {
|
||||
// ...
|
||||
}
|
||||
|
||||
override fun mouseEntered(e : MouseEvent) {
|
||||
// ...
|
||||
}
|
||||
})
|
||||
{jet}
|
||||
If a supertype has a constructor, appropriate constructor parameters must be passed to it. Many supertypes may be specified as a comma-separated list after the colon:
|
||||
{jet}
|
||||
open class A(x : Int) {
|
||||
public virtual val y : Int = x
|
||||
}
|
||||
|
||||
open class B(s : String)
|
||||
|
||||
val ab = object : A(1), B("abc") {
|
||||
override val y = 15
|
||||
}
|
||||
{jet}
|
||||
|
||||
If, by any chance, we need "just an object", with no nontrivial supertypes, we can simply say:
|
||||
{jet}
|
||||
val adHoc = object {
|
||||
var x : Int = 0
|
||||
var y : Int = 0
|
||||
}
|
||||
|
||||
print(adHoc.x + adHoc.y)
|
||||
{jet}
|
||||
|
||||
h3. Object declarations
|
||||
|
||||
[Singleton|http://en.wikipedia.org/wiki/Singleton_pattern] is a very useful pattern, and [Kotlin] (after *Scala*) makes it easy to declare singletons:
|
||||
{jet}
|
||||
object DataProviderManager {
|
||||
fun registerDataProvider(provider : DataProvider) {
|
||||
// ...
|
||||
}
|
||||
|
||||
val allDataProviders : Collection<DataProvider>
|
||||
get() = // ...
|
||||
}
|
||||
{jet}
|
||||
This is called an _object declaration_. If there's a name following the *object* keyword, we are not talking about an _expression_ any more. We cannot assign such a thing to a variable, but we can refer to it by its name. Such objects can have supertypes:
|
||||
{jet}
|
||||
object DefaultListener : MouseAdapter() {
|
||||
override fun mouseClicked(e : MouseEvent) {
|
||||
// ...
|
||||
}
|
||||
|
||||
override fun mouseEntered(e : MouseEvent) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. Semantical difference between object expressions and declarations
|
||||
|
||||
There is one important semantical difference between *object* expressions and *object* declarations:
|
||||
* *object* declarations are initialized lazily, when accessed for the first time
|
||||
* *object* expressions are executed (and initialized) immediately, where they are used
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Generics]
|
||||
@@ -1,19 +0,0 @@
|
||||
[Kotlin] preserves type information at runtime, including the [generic arguments of types and functions|Generics#Reified generics].
|
||||
|
||||
This information can be retrieved with the {{typeinfo()}} function:
|
||||
{jet}
|
||||
val typeinfo = typeinfo(list)
|
||||
{jet}
|
||||
|
||||
{{typeinfo()}} returns an object of the class {{TypeInfo}} that provides type information and reflective access to the members of the given type.
|
||||
|
||||
To retrieve a {{TypeInfo}} instance of a type expression, we can use an overloaded version of the {{typeinfo()}} function, but passing in a type argument:
|
||||
{jet}
|
||||
val typeinfo = typeinfo<List<Int>>
|
||||
{jet}
|
||||
|
||||
{note:title=TypeInfo is not supported yet}On the JVM you can say {{foo.javaClass}} to ge the Java class of {{foo}}.{note}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Null-safety]
|
||||
@@ -1,41 +0,0 @@
|
||||
Strings are represented by the type {{String}}. Strings are immutable. Elements of a string are [characters|Basic types#Characters] can be accessed by the indexing operation: {{s\[i\]}}. A string can be iterated over with a *for* loop:
|
||||
{jet}
|
||||
for (c in str) {
|
||||
println(c)
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. String literals
|
||||
|
||||
[Kotlin] has two types of string literals: _escaped_ strings that may have escaped characters in them and _raw_ strings that can contain newlines and arbitrary text. An escaped string is very much like a *Java* string:
|
||||
{jet}
|
||||
val s = "Hello, world!\n"
|
||||
{jet}
|
||||
Escaping is done in the conventional way, with a backslash.
|
||||
|
||||
A _raw_ string is delimited by a triple quote ({{"""}}), contains no escaping and can contain newlines and any other characters:
|
||||
{jet}
|
||||
val text = """
|
||||
for (c in "foo")
|
||||
print(c)
|
||||
"""
|
||||
{jet}
|
||||
|
||||
{anchor:Templates}
|
||||
|
||||
h3. Templates
|
||||
|
||||
Strings may contain _template expressions_, i.e. pieces of code that are evaluated and whose results are concatenated into the string. A template expression starts with a dollar sign ({{$}}) and consists of either a simple name:
|
||||
{jet}
|
||||
val i = 10
|
||||
val s = "i = $i" // evaluates to "i = 10"
|
||||
{jet}
|
||||
or an arbitrary expression in curly braces:
|
||||
{jet}
|
||||
val s = "abc"
|
||||
val str = "$s.length is ${s.length}" // evaluates to "abc.length is 3"
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Expressions]
|
||||
@@ -1,35 +0,0 @@
|
||||
h3. Equality
|
||||
|
||||
In [Kotlin] there are two types of equality:
|
||||
* referential equality (two references point to the same object)
|
||||
* structural equality (a check for {{equals()}}
|
||||
|
||||
h4. Referential equality
|
||||
|
||||
In [Kotlin], there's no built-in operator to check for referential equality, for we believe that it is rarely needed. Instead, there's an [inline function|Functions#Inline functions] {{identityEquals()}} that can be called in the following way:
|
||||
{jet}
|
||||
a.identityEquals(b)
|
||||
// or
|
||||
a identityEquals b // infix call
|
||||
{jet}
|
||||
And returns *true* if and only if {{a}} and {{b}} point to the same object.
|
||||
|
||||
h4. Structural equality
|
||||
|
||||
Structural equality is checked by the {{==}} operation (and its negated counterpart {{!=}}). By [convention|Operator overloading#Equals], an expression like {{a == b}} is translated to
|
||||
{jet}
|
||||
a?.equals(b) ?: b.identityEquals(null)
|
||||
{jet}
|
||||
I.e. if {{a}} is not *null*, it calls the {{equals(Any?)}} function, otherwise (i.e. {{a}} is *null*) it checks that {{b}} is referentially equal to *null*.
|
||||
|
||||
Note that there's no point in optimizing your code when comparing to *null* explicitly: {{a == null}} will be automatically translated to {{a.identityEquals(null)}}.
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Control structures]
|
||||
* [Function literals]
|
||||
* [Returns and jumps]
|
||||
* [Ranges]
|
||||
* [This expressions]
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
@@ -1,207 +0,0 @@
|
||||
{anchor:If}
|
||||
|
||||
h3. If expression
|
||||
|
||||
In [Kotlin], *if* is an _expression_, i.e. it returns a value. Therefore there is not _ternary operator_ ({{condition ? then : else}}), because ordinary *if* works fine in this role. Consider the following examples:
|
||||
|
||||
{jet}
|
||||
// Traditional usage
|
||||
var max = a
|
||||
if (a < b)
|
||||
max = b
|
||||
|
||||
// With else
|
||||
var max : Int
|
||||
if (a > b)
|
||||
max = a
|
||||
else
|
||||
max = b
|
||||
|
||||
// As expression
|
||||
val max = if (a > b) a else b
|
||||
{jet}
|
||||
|
||||
*If* branches can be blocks, and the last expression is the value of a block:
|
||||
{jet}
|
||||
val max = if (a > b) {
|
||||
print("Choose a")
|
||||
a
|
||||
}
|
||||
else {
|
||||
print("Choose b")
|
||||
b
|
||||
}
|
||||
{jet}
|
||||
|
||||
When *if* has only one branch, or one of its branches results in [{{Unit}}|Functions#Unit], it's type is [{{Unit}}|Functions#Unit].
|
||||
|
||||
See the grammar for *if* [here|Grammar#if].
|
||||
|
||||
{anchor:When}
|
||||
|
||||
h3. When expression
|
||||
|
||||
*When* replaces the *switch* operator of *C*\-like languages. In the simplest form it looks like this:
|
||||
{jet}
|
||||
when (x) {
|
||||
1 -> print("x == 1")
|
||||
2 -> print("x == 2")
|
||||
else -> { // Note the block
|
||||
print("x is neither 1 nor 2")
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
*When* matches its argument against all branches consequently until some branch condition is satisfied. *When* is an _expression_ and results in satisfied branch's right hand side. If some of its branches return result in a value of type [{{Unit}}|Functions#Unit], the whole expression has type [{{Unit}}|Functions#Unit].
|
||||
Note that the *else* branch is mandatory, unless the compiler can prove that all possible cases are covered with branch conditions.
|
||||
|
||||
If many cases should be handled in the same way, the branch conditions may be combined with a comma:
|
||||
{jet}
|
||||
when (x) {
|
||||
0, 1 -> print("x == 0 or x == 1")
|
||||
else -> print("otherwise")
|
||||
}
|
||||
{jet}
|
||||
|
||||
We can use arbitrary expressions (not only constants) as branch conditions:
|
||||
{jet}
|
||||
when (x) {
|
||||
parseInt(s) -> print("s encodes x")
|
||||
else -> print("s does not encode x")
|
||||
}
|
||||
{jet}
|
||||
|
||||
One can also check a value for being *in* or *\!in* a [range|Ranges]:
|
||||
{jet}
|
||||
when (x) {
|
||||
in 1..10 -> print("x is in the range")
|
||||
!in 10..20 -> print("x is outside the range")
|
||||
else -> print("none of the above")
|
||||
}
|
||||
{jet}
|
||||
|
||||
*When*\-expressions support [pattern matching|Pattern matching] through {{is}} and {{\!is}}:
|
||||
{jet}
|
||||
when (tuple) {
|
||||
is #(1, 2) -> ...
|
||||
is #(val a, 3) -> print(a) // binding a to the first element of the tuple
|
||||
!is #(*, 1100) -> ...
|
||||
else -> ...
|
||||
}
|
||||
{jet}
|
||||
We do not expand on the pattern matching here. For details, look at [this page|Pattern matching].
|
||||
|
||||
{anchor:bare-when}
|
||||
*When* can also be used as a replacement for an *if*\-*else*\-*if* chain. If no argument is supplied, the branch conditions are simply boolean expressions, and a branch is executed when its condition is true:
|
||||
{jet}
|
||||
when {
|
||||
x.isOdd() -> print("x is odd")
|
||||
x.isEven() -> print("x is even")
|
||||
else -> print("x is funny")
|
||||
}
|
||||
{jet}
|
||||
|
||||
{anchor:continue-when}
|
||||
h4. Continue inside {{when}}
|
||||
|
||||
Inside *when* expressions, *continue* jumps to the next branch condition, if any:
|
||||
{jet}
|
||||
when (x) {
|
||||
in 1..100 ->
|
||||
if (x.isOdd())
|
||||
continue // Jump to the next branch, i.e. '3, 101 -> ...'
|
||||
else
|
||||
print("Even between 1 and 100")
|
||||
3, 101 -> print("3 or 101")
|
||||
1000 -> <error desc="'continue' is not allowed in the last branch">continue</error> // Error: continue is not allowed in the last branch
|
||||
}
|
||||
{jet}
|
||||
|
||||
This mechanism replaces the concept of _guards_ available in other languages. I.e. in *Scala* one has _guard_ *{_}if{_}* _expressions_ in *match* (that corresponds to *when*):
|
||||
{code:Scala}
|
||||
// Scala
|
||||
term match {
|
||||
case Fun(x, Var(y)) if x == y -> print(x)
|
||||
case _ -> print("Nope!")
|
||||
}
|
||||
{code}
|
||||
This can be rewritten in [Kotlin] with as follows:
|
||||
{jet}
|
||||
when(term) {
|
||||
is Fun#(val x, Var#(val y)) -> { if (x != y) continue; print(x) }
|
||||
else -> print("Nope!")
|
||||
}
|
||||
{jet}
|
||||
See [Returns and jumps] for more information about *continue*.
|
||||
|
||||
See the grammar for *when* [here|Grammar#when].
|
||||
See also [Pattern matching].
|
||||
|
||||
{note:title=Continue in when is not implemented yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-771]{note}
|
||||
|
||||
{anchor:Loops}
|
||||
{anchor:For}
|
||||
h3. For loop
|
||||
|
||||
*For* loop iterates through anything that provides an _iterator_. The syntax is as follows:
|
||||
{jet}
|
||||
for (item in collection)
|
||||
print(item)
|
||||
{jet}
|
||||
|
||||
One can specify a type and *val* or *var* for the loop variable. The body can be a block.
|
||||
{jet}
|
||||
for (val item : Int in ints) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
As mentioned before, *for* iterates through anything that provides and *iterator*, i.e.
|
||||
# has an instance\- or extension-function {{iterator()}}, whose return type
|
||||
# has an instance\- or extension-function {{next()}}, and
|
||||
# either
|
||||
## a property {{hasNext}} of type {{Boolean}}, or
|
||||
## a function {{hasNext()}} that returns {{Boolean}}.
|
||||
|
||||
If you want to iterate through an [array|Basic types#Arrays] or list with an index, you can do it this way:
|
||||
{jet}
|
||||
for (i in array.indices)
|
||||
print(array[i])
|
||||
{jet}
|
||||
Note that this "iteration through a range" is compiled down to optimal implementation with no extra objects created.
|
||||
|
||||
See the grammar for *for* [here|Grammar#for].
|
||||
|
||||
{anchor:while}
|
||||
|
||||
h3. While and do..while loops
|
||||
|
||||
*While* and *do*..*while* work as usual:
|
||||
{jet}
|
||||
while(x > 0) {
|
||||
x--
|
||||
}
|
||||
|
||||
do {
|
||||
val y = retrieveData()
|
||||
} while(y != null) // y is visible here!
|
||||
{jet}
|
||||
|
||||
See the grammar for *while* [here|Grammar#while].
|
||||
|
||||
h3. Break and continue in loops
|
||||
|
||||
[Kotlin] supports traditional *break* and *continue* operators in loops. See more here [Returns and jumps].
|
||||
|
||||
h3. Try expression
|
||||
|
||||
See [Exceptions] for the details.
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Function literals]
|
||||
* [Returns and jumps]
|
||||
* [Ranges]
|
||||
* [This expressions]
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
@@ -1,109 +0,0 @@
|
||||
A _function literal_ as an "anonymous function", i.e. a function that is not declared, but passed immediately as an expression. Consider the following example:
|
||||
{jet}
|
||||
max(strings, {a, b -> a.length < b.length})
|
||||
{jet}
|
||||
Function {{max}} is a [higher-order function|Functions#Higher-order functions], i.e. is takes a function value as the second argument. This second argument is an expression that is itself a function, i.e. a _function literal_. As a function, it is equivalent to
|
||||
{jet}
|
||||
fun compare(a : String, b : String) : Boolean = a.length < b.length
|
||||
{jet}
|
||||
|
||||
h3. Function types
|
||||
|
||||
For a function to accept another function as a parameter, we have to specify a _function type_ for that parameter. For example the abovementioned function {{max}} is defined as follows:
|
||||
{jet:lineNumbers=true}
|
||||
fun max<T>(collection : Collection<out T>, less : (T, T) -> Boolean) : T? {
|
||||
var max : T? = null
|
||||
for (it in collection)
|
||||
if (max == null || less(max, it))
|
||||
max = it
|
||||
return max
|
||||
}
|
||||
{jet}
|
||||
The parameter {{less}} is of type {{(T, T) -> Boolean}}, i.e. a function that takes two parameters of type {{T}} and returns a {{Boolean}}: *true* if the first one is smaller than the second one.
|
||||
|
||||
In the body, line 4, {{less}} is used as a function: it is called by passing two arguments of type {{T}}.
|
||||
|
||||
A _function type_ is written as above, or may have named parameters, for documentation purposes and to enable calls with [named arguments|Functions#Named arguments].
|
||||
{jet}
|
||||
val compare : (x : T, y : T) -> Int = ...
|
||||
{jet}
|
||||
|
||||
{anchor:Syntax}
|
||||
|
||||
h3. Syntactic forms of function literals
|
||||
|
||||
The _full_ syntactic form of function literals, i.e. literals of function types, is as follows:
|
||||
{jet}
|
||||
val sum = {(x : Int, y : Int) : Int -> x + y}
|
||||
{jet}
|
||||
|
||||
* A function literal is always surrounded by curly braces,
|
||||
* parameter declarations in the full syntactic form go inside parentheses and have _optional_ type annotations,
|
||||
* the _optional_ return type annotation goes after the parameter list,
|
||||
* the body goes after an '{{->}}' sign.
|
||||
|
||||
If we leave all the optional annotations out, what's left looks like this:
|
||||
{jet}
|
||||
val sum : (Int, Int) -> Int = {(x, y) -> x + y}
|
||||
{jet}
|
||||
As this is the most common case, [Kotlin] allows us to leave the parentheses out as well, if no type annotations are present, and so we get the _short_ syntactic form for functional literals:
|
||||
{jet}
|
||||
val sum : (Int, Int) -> Int = {x, y -> x + y}
|
||||
{jet}
|
||||
|
||||
It very common that a function literal has _only one parameter_. If [Kotlin] can figure the signature out itself, it allows us not to declare the only parameter, and will implicitly declare it for us under the name *it*:
|
||||
{jet}
|
||||
ints.filter {it > 0} // this literal is of type '(it : Int) -> Boolean'
|
||||
{jet}
|
||||
Note that if a function takes another function as the last parameter, the function literal argument can be passed outside the parenthesized argument list. See [Higher-order functions|Functions#Higher-order functions] and the grammar for [callSuffix|Grammar#callSuffix].
|
||||
|
||||
See the grammar for function literals [here|Grammar#functionLiteral].
|
||||
|
||||
h3. Closures
|
||||
|
||||
A function literal (as well as a [local function|Functions#Local functions] and [object expressions|Object expressions and Declarations]) can access its _closure_, i.e. the variables declared in the outer scope. Unlike *Java* the closure variables can be modified:
|
||||
{jet}
|
||||
var sum = 0
|
||||
ints filter {it > 0} forEach {
|
||||
sum += it
|
||||
}
|
||||
print(sum)
|
||||
{jet}
|
||||
|
||||
{anchor:Extensions}
|
||||
|
||||
h3. Extension function literals
|
||||
|
||||
Besides ordinary functions, [Kotlin] supports [extension functions|Extension functions]. This kind of functions in so useful, that extension function literals are also supported. One of the most important examples of their usage is [Type-safe Groovy-style builders|Type-safe Groovy-style builders].
|
||||
|
||||
An extension function differs from an ordinary one in that it has a _receiver type_ specification. One can specify a receiver type in a function literal as well:
|
||||
{jet}
|
||||
val sum = {Int.(other : Int) : Int -> this + other}
|
||||
{jet}
|
||||
Receiver type may be specified only in the _full_ syntactic form of a function literal (remember that parameter types and return type annotations are optional in this form).
|
||||
|
||||
Such a literal has a function type with receiver:
|
||||
{jet}
|
||||
sum : Int.(other : Int) -> Int
|
||||
{jet}
|
||||
it can be called with a dot or in infix form (since it has only one parameter):
|
||||
{jet}
|
||||
1.sum(2)
|
||||
1 sum 2
|
||||
{jet}
|
||||
|
||||
h4. Disambiguation of {{this}} expressions
|
||||
|
||||
See [*This* expressions|This expressions#Qualified].
|
||||
|
||||
h3. What's next
|
||||
|
||||
*Expressions*
|
||||
* [Returns and jumps]
|
||||
* [Ranges]
|
||||
* [This expressions]
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
|
||||
*Functions*
|
||||
* [Type-safe Groovy-style builders]
|
||||
@@ -1,24 +0,0 @@
|
||||
Range expressions are formed with {{rangeTo}} functions that have the [operator form of {{..}}|Operator overloading#Binary operations] which are complemented by [*in* and *!in*|Operator overloading#in]:
|
||||
{jet}
|
||||
// Check range membership, i.e. contains
|
||||
// (optimized for Ints)
|
||||
if (a in 1..100) {
|
||||
print("in range")
|
||||
}
|
||||
|
||||
// Iterate through a range, i.e. iterator()
|
||||
// (optimized for Ints)
|
||||
for (x in 1..100) {
|
||||
print(x)
|
||||
}
|
||||
{jet}
|
||||
|
||||
A {{rangeTo()}} function may return whatever type one likes, but there's a common convention:
|
||||
* For enumerable types like {{Int}}, {{rangeTo()}} returns an {{IterableRange}} object that supports both checking membership with {{contains()}} (*in*) and iterating with {{iterator()}}.
|
||||
* For other ordered types (like {{String}} or {{Double}}), it returns a {{Range}} that only supports checking membership with {{contains()}}.
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [This expressions]
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
@@ -1,118 +0,0 @@
|
||||
There are three so-called _structural jump operators_ that are sort of like *goto* but much nicer: *return*, *break* and *continue*. By default, their behavior is as follows:
|
||||
* *return* returns from the _nearest enclosing_ _[function|Functions]_, and not a [function literal|Function literals]
|
||||
* *break* terminates the _nearest enclosing_ _[loop|Control structures#Loops]_
|
||||
* *continue* either proceeds to the next step of the _nearest enclosing_ _[loop|Control structures#Loops]_ or to the next branch in the _nearest enclosing_ _[*when* expression|Control structures#When]_
|
||||
|
||||
h3. Break and continue at labels
|
||||
|
||||
Any expression in [Kotlin] may be marked with a _label_. Labels have the from of the {{@}} sign followed by an optional identifier, for examples {{@}}, {{@abc}}, {{@fooBar}} are valid labels (see the [grammar|Grammar#label]). To label an expression, we just put a label in front of it:
|
||||
{jet}
|
||||
@loop for (i in 1..100) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
Now, we can qualify a *break* or *continue* with a label:
|
||||
{jet}
|
||||
@loop for (i in 1..100) {
|
||||
for (j in 1..100) {
|
||||
if (...)
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
A *break* qualified with a label jumps to the execution point right after the loop marked with that label. A *continue* proceeds to the next iteration of that loop.
|
||||
|
||||
h3. Return at labels
|
||||
|
||||
With [function literals|Function literals], [local functions|Functions#Local functions] and [object expression|Object expressions and Declarations], functions can be nested in [Kotlin]. _Qualified_ *{_}return{_}{*}_'s_ allow us to return from an _outer function_. The most important use case is returning from a function literal. Recall that when we write this:
|
||||
{jet}
|
||||
fun foo() {
|
||||
ints.forEach {
|
||||
if (it == 0) return
|
||||
print(it)
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
The *return* expression returns from the nearest enclosing _function_, i.e. {{foo}}. If we need to return from a _function literal_, we have to label it and qualify the *return*:
|
||||
{jet}
|
||||
fun foo() {
|
||||
ints.forEach @lit {
|
||||
if (it == 0) return@lit
|
||||
print(it)
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Now, it returns only from the function literal. Often times it is more convenient to use the shortest implicit label {{@}} for function literals:
|
||||
{jet}
|
||||
fun foo() {
|
||||
ints.forEach {
|
||||
if (it == 0) return@ // Works if there's one and only one function literal in lexical scope up to named entity (function or class)
|
||||
print(it)
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Note that such non-local returns are supported only for function literals passed to inline-functions.
|
||||
|
||||
When returning a value, the parser gives preference to the qualified return, i.e.
|
||||
{jet}
|
||||
return@a 1
|
||||
{jet}
|
||||
means "return 1 at label @a" and not "return a labeled expression (@a 1)".
|
||||
|
||||
Named functions automatically define labels:
|
||||
{jet}
|
||||
fun outer() {
|
||||
fun inner() {
|
||||
return@outer // the label @outer was defined automatically
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
{note:title=Non-local returns are not implemented yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1435].{note}
|
||||
|
||||
{anchor:custom}
|
||||
h4. Break and continue in custom control structures
|
||||
|
||||
[Inline functions|Functions#Inline functions] make writing performant "custom control structures" easy, for example, the {{forEach()}} function that executes a function literal for every element in a collection:
|
||||
{jet}
|
||||
inline fun <T> Collection<T>.forEach(body : (item : T) -> Unit) {
|
||||
for (item in this) {
|
||||
body(item)
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Note that this function is not exactly a redundant example easily substitutable by a normal *for* loop. Consider the following code:
|
||||
{jet}
|
||||
ints filter {it > 0} sortby {-it} forEach {print(it)}
|
||||
{jet}
|
||||
|
||||
Now, what happens when we write *break* (or *continue*) inside the body of {{forEach}}? We simply get a compile-time error, because, lexically, there's no loop to *break*:
|
||||
{jet}
|
||||
ints forEach {
|
||||
if (it < 0) <error desc="'break' is only allowed inside a loop">break</error> // Error: 'break' does not belong to a loop
|
||||
print(it)
|
||||
}
|
||||
{jet}
|
||||
But, actually, there _is_ a loop, hidden inside {{forEach}}, and it is _inlined_ there, so we should be able to tell the compiler to understand that. An we can, by annotating the loop inside {{forEach}} with the {{loop}} annotation. The function parameter should also be annotated with {{loopbody}} annotation:
|
||||
{jet}
|
||||
<class desc="jet softkeyword":>inline fun <T> Collection<T>.forEach(<class desc="jet softkeyword":>loopbody body : (item : T) -> Unit) {
|
||||
[<class desc="jet softkeyword":>loop] for (item in this) {
|
||||
body(item)
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Now, the compiler allows *break* and *continue* in the function literal argument passed to {{forEach}}, and these operators apply to the loop marked with {{@@}}.
|
||||
|
||||
{note:title=Break and continue for custom control structures are not implemented yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1436].{note}
|
||||
|
||||
h3. Qualified {{this}} expressions
|
||||
|
||||
See [*This* expressions|This expressions#Qualified].
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Ranges]
|
||||
* [This expressions]
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
@@ -1,41 +0,0 @@
|
||||
To denote the current _receiver_, we use *this* expressions:
|
||||
* In a member of a [class|Classes and Inheritance], *this* refers to the current object of that class
|
||||
** *this{*}{{<Supertype>}} is used to qualified calls to supertype's implementations of members, see [Classes and Inheritance#Overriding rules]
|
||||
* In an [extension function|Extension functions] or an [extension function literal|Function literals#Extensions], *this* denotes the _receiver_ parameter that is passed on the left-hand side of a dot.
|
||||
|
||||
If *this* has no qualifiers, it refers to the _innermost enclosing scope_. To refer to *this* in other scopes, _label qualifiers_ are used:
|
||||
|
||||
{anchor:qualified}
|
||||
|
||||
h3. Qualified {{this}}
|
||||
|
||||
To access *this* from an outer scope (a [class|Classes and Inheritance], or [extension function|Extension functions], or labeled [extension function literal|Function literals#Extensions]) one writes *this{*}{{@label}} where {{@label}} is a [label|Returns and jumps] on the scope {{this}} is meant to be from:
|
||||
{jet}
|
||||
class A { // implicit label @A
|
||||
class B { // implicit label @B
|
||||
fun Int.foo() { // implicit label @foo
|
||||
val a = this@A // A's this
|
||||
val b = this@B // B's this
|
||||
|
||||
val c = this // foo()'s receiver, an Int
|
||||
val c1 = this@foo // foo()'s receiver, an Int
|
||||
|
||||
val funLit = {String.() -> // implicit label @
|
||||
val d = this // funLit's receiver
|
||||
val d1 = this@ // funLit's receiver
|
||||
}
|
||||
|
||||
|
||||
val funLit2 = { (s:String) ->
|
||||
val d1 = this // foo()'s receiver, since enclosing function literal doesn't have any receiver
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
@@ -1,52 +0,0 @@
|
||||
Tuples (pairs, triples and so on) are useful when we need a lightweight mechanism of data together, for example, to return several values from a function.
|
||||
|
||||
h3. Tuple types and literals
|
||||
|
||||
There are 22 tuple classes named {{Tuple0}} through {{Tuple21}}. {{Tuple0}} (also called [Unit|Functions#Unit]) has zero type parameters, {{Tuple1}} has one parameter, and so on. The type parameters determine types of tuple components. For example, {{Tuple2}} is defined as follows:
|
||||
{jet}
|
||||
class Tuple2<out T1, out T2>(
|
||||
val _1 : T1,
|
||||
val _2 : T2
|
||||
)
|
||||
{jet}
|
||||
|
||||
We can use shorthand syntax for tuple types and values
|
||||
{jet}
|
||||
val intStrPair : #(Int, String) = #(1, "") // same as 'Tuple2<Int, String>(1, "")'
|
||||
{jet}
|
||||
|
||||
One can access tuples' components either by [pattern matching|Pattern matching#Tuple patterns]:
|
||||
{jet}
|
||||
when (x) {
|
||||
is #(null, *) => throw NullPointerException()
|
||||
is #(val a, val b) => print(a, b)
|
||||
}
|
||||
{jet}
|
||||
or by generic accessors {{\_1}}, {{\_2}} etc:
|
||||
{jet}
|
||||
print("left = ${pair._1}, right = ${pair._2}")
|
||||
{jet}
|
||||
|
||||
To make accessors more readable, one can use [labeled tuples|#Labeled tuples].
|
||||
|
||||
h3. Labeled tuples
|
||||
|
||||
One can define a tuple type with _labels_ for its components:
|
||||
{jet}
|
||||
val point : #(x : Int, y : Int)
|
||||
{jet}
|
||||
Such a tuple can be accessed by those labels:
|
||||
{jet}
|
||||
print("x = ${point.x}, y = ${point.y}")
|
||||
{jet}
|
||||
|
||||
We can even create tuples with named components, where order does not matter any more:
|
||||
{jet}
|
||||
val point : #(x : Int, y : Int) = #(y = 10, x = 5)
|
||||
{jet}
|
||||
|
||||
{note:title=Labeled tuples are not implemented yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1433].{note}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Type casts]
|
||||
@@ -1,45 +0,0 @@
|
||||
A type cast operator changes the static type of an expression after performing a run-time check.
|
||||
|
||||
h3. Smart casts
|
||||
|
||||
In many cases, one does not need to use explicit cast operators in [Kotlin], because the compiler tracks the [*is*\-checks for immutable values|Pattern matching] and inserts (safe) casts automatically when needed:
|
||||
{jet}
|
||||
fun demo(x : Any) {
|
||||
if (x is String) {
|
||||
print(x.length) // x is automatically cast to String
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
Automatic casts work for [*when* expressions|Control structures#When] and [*while*|Control structures#While] loops as well:
|
||||
{jet}
|
||||
when (x) {
|
||||
is Int -> print(x + 1)
|
||||
is String -> print(x.length + 1)
|
||||
is Array<Int> -> print(x.sum())
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. "Unsafe" cast operator
|
||||
|
||||
Usually, cast operator throws an exception if the cast is not possible. Thus, we call it _unsafe_. The unsafe cast in [Kotlin] is done by an infix operator *as* (see [operator precedence|Grammar#Precedence]):
|
||||
{jet}
|
||||
val x : String = y as String
|
||||
{jet}
|
||||
Note that *null* cannot be cast to {{String}} as this type is not [nullable|Null-safety], i.e. if {{y}} is *null*, the code above throws an exception.
|
||||
In order to match Java cast semantics we have to have nullable type at cast right hand side, like
|
||||
{jet}
|
||||
val x : String? = y as String?
|
||||
{jet}
|
||||
|
||||
h3. "Safe" (nullable) cast operator
|
||||
|
||||
To avoid an exception being thrown, one can use a "safe" cast operator *as?* that returns *null* on failure:
|
||||
{jet}
|
||||
val x : String? = y as? String
|
||||
{jet}
|
||||
Note that despite the fact that the right-hand side of *as?* is a non-null type {{String}} the result of the cast is nullable.
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Pattern matching]
|
||||
@@ -1,61 +0,0 @@
|
||||
h1. Motivation
|
||||
|
||||
In *Java*, we are used to classes named {{\*Utils}}: {{FileUtils}}, {{StringUtils}} an so on. The famous {{java.util.Collections}} belongs to the same breed. And the unpleasant part about these {{Utils}}\-classes is that the code that uses them looks like this:
|
||||
{code}
|
||||
// Java
|
||||
Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))
|
||||
{code}
|
||||
Those class names are always getting in the way. We can use static imports and get this:
|
||||
{code}
|
||||
// Java
|
||||
swap(list, binarySearch(list, max(otherList)), max(list))
|
||||
{code}
|
||||
This is a little better, but we have no or little help from the powerful code completion of the IDE. It would be so much better if we could say
|
||||
{code}
|
||||
// Java
|
||||
list.swap(list.binarySearch(otherList.max()), list.max())
|
||||
{code}
|
||||
But we don't want to implement all the possible methods inside the class {{List}}, right?
|
||||
|
||||
So, [Kotlin] (after *C#* and *Gosu*) introduces _extension functions_: a function declared outside the class {{List}} may be contributed to this type as an extension. This is denoted by prepending the _receiver_ type (the one being extended) to the function name:
|
||||
{jet}
|
||||
fun List<Int>.swap(x : Int, y : Int) {
|
||||
val tmp = this[x] // 'this' corresponds to the list
|
||||
this[x] = this[y]
|
||||
this[y] = tmp
|
||||
}
|
||||
{jet}
|
||||
The *this* keyword inside an extension function corresponds to the _receiver object_ (the one that is passed before the dot). Now, we can call such a function on any {{List<Int>}}:
|
||||
{jet}
|
||||
val l = list(1, 2, 3)
|
||||
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
|
||||
{jet}
|
||||
|
||||
Of course, this function makes sense for any {{List<T>}}, and we can make it generic:
|
||||
{jet}
|
||||
fun <T> List<T>.swap(x : Int, y : Int) {
|
||||
val tmp = this[x] // 'this' corresponds to the list
|
||||
this[x] = this[y]
|
||||
this[y] = tmp
|
||||
}
|
||||
{jet}
|
||||
We declare the generic type parameter _before_ the function name for it to be available in the _receiver_ type expression. See [Generic functions|Generics#Generic functions].
|
||||
|
||||
h2. Extension functions are resolved statically
|
||||
|
||||
To avoid confusion, we would like to emphasize that extension functions are resolved _statically_, i.e. they are not *virtual* by receiver type. On the other hand they can be member functions on some class and thus can be virtual in that class hierarchy.
|
||||
|
||||
h1. Similar features in other languages
|
||||
|
||||
*AspectJ* has [inter-type declarations|http://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-itds.html].
|
||||
|
||||
*Groovy* has [metaclasses|http://groovy.codehaus.org/JN3525-MetaClasses].
|
||||
|
||||
*Scala* makes heavy use of implicit conversions, i.e. wraps values into adapters at runtime.
|
||||
|
||||
*[C#|http://msdn.microsoft.com/en-us/library/bb383977.aspx]* and *[Gosu|http://gosu-lang.org/doc/wwhelp/wwhimpl/api.htm?&context=gosu&src=enhancements&topic=Using_Enhancements]* have extension functions implemented similarly to our approach.
|
||||
|
||||
h1. What's next
|
||||
|
||||
* [Function literals]
|
||||
* [Type-safe Groovy-style builders]
|
||||
@@ -1,123 +0,0 @@
|
||||
[Kotlin] allows us to provide implementations for a predefined set of operators on our types. These operators have fixed symbolic representation (like '{{+}}' or '{{*}}') and fixed [precedence|Grammar#Precedence]. To implement an operator, one provides a [member function|Functions#Member functions] or an [extension function|Extension functions] with a fixed name, for the corresponding type, i.e. left-hand side type for binary operations and argument type for unary ones.
|
||||
|
||||
h3. Conventions
|
||||
|
||||
Here we describe the conventions that regulate operator overloading for different operators.
|
||||
|
||||
h5. Unary operations
|
||||
|
||||
||Expression||Translated to||
|
||||
| {{+a}} | {{a.plus()}} |
|
||||
| {{-a}} | {{a.minus()}} |
|
||||
| {{!a}} | {{a.not()}} |
|
||||
|
||||
This table says that when the compiler processes, for example, an expression {{+a}}, it performs the following steps:
|
||||
# Determines the type of {{a}}, let it be {{T}}.
|
||||
# Looks up a function {{plus()}} with no parameters for the receiver {{T}}, i.e. a member function or an extension function.
|
||||
# If the function is absent or ambiguous, it is a compilation error.
|
||||
# If the function is present and its return type is {{R}}, the expression {{+a}} has type {{R}}.
|
||||
|
||||
*Note* that these operations, as well as all the others, are optimized for [Basic types] and do not introduce overhead of function calls for them.
|
||||
|
||||
||Expression||Translated to||
|
||||
| {{a++}} | {{a.inc()}} + see below |
|
||||
| {{a--}} | {{a.dec()}} + see below |
|
||||
|
||||
These operations are supposed to change their receiver and (optionally) return a value.
|
||||
{note:title=inc()/dec() shouldn't mutate the receiver object}
|
||||
By "changing the receiver" we mean the receiver-variable, not the receiver object.
|
||||
{note}
|
||||
The compiler performs the following steps for resolution of an operator in the *postfix* form, e.g. {{a++}}:
|
||||
# Determines the type of {{a}}, let it be {{T}}.
|
||||
# Looks up a function {{inc()}} with no parameters, applicable to the receiver of type {{T}}.
|
||||
# If the function returns a type {{R}}, then it must be a subtype of {{T}}.
|
||||
|
||||
The effect of computing the expression is:
|
||||
# Store the initial value of {{a}} to a temporary storage {{a0}},
|
||||
# Assign the result of {{a.inc()}} to {{a}},
|
||||
# Return {{a0}} as a result of the expression.
|
||||
|
||||
For {{a--}} the steps are completely analogous.
|
||||
|
||||
For the *prefix* forms {{++a}} and {{--a}} resolution works the same way, and the effect is:
|
||||
# Assign the result of {{a.inc()}} to {{a}},
|
||||
# Return the new value of {{a}} as a result of the expression.
|
||||
|
||||
h5. Binary operations
|
||||
|
||||
||Expression||Translated to||
|
||||
| {{a + b}} | {{a.plus(b)}} |
|
||||
| {{a - b}} | {{a.minus(b)}} |
|
||||
| {{a * b}} | {{a.times(b)}} |
|
||||
| {{a / b}} | {{a.div(b)}} |
|
||||
| {{a % b}} | {{a.mod(b)}} |
|
||||
| {{a..b}} | {{a.rangeTo(b)}} |
|
||||
|
||||
For the operations in this table, the compiler just resolves the expression in the *Translated to* column.
|
||||
|
||||
||Expression||Translated to||
|
||||
| {{a in b}} | {{b.contains(a)}} |
|
||||
| {{a !in b}} | {{!b.contains(a)}} |
|
||||
|
||||
{anchor:in}
|
||||
For *in* and *!in* the procedure is the same, but the order of arguments is reversed.
|
||||
|
||||
||Symbol||Translated to||
|
||||
| {{a\[i\]}} | {{a.get\(i\)}} |
|
||||
| {{a\[i, j\]}} | {{a.get\(i, j\)}} |
|
||||
| {{a\[i_1, ..., i_n\]}} | {{a.get\(i_1, ..., i_n\)}} |
|
||||
| {{a\[i\] = b}} | {{a.set(i, b)}} |
|
||||
| {{a\[i, j\] = b}} | {{a.set(i, j, b)}} |
|
||||
| {{a\[i_1, ..., i_n\] = b}} | {{a.set(i_1, ..., i_n, b)}} |
|
||||
|
||||
Square brackets are translated to calls to {{get}} and {{set}} with appropriate numbers of arguments.
|
||||
|
||||
{anchor:assignments}
|
||||
||Expression||Translated to||
|
||||
| {{a += b}} | {{a.plusAssign(b)}} |
|
||||
| {{a -= b}} | {{a.minusAssign(b)}} |
|
||||
| {{a *= b}} | {{a.timesAssign(b)}} |
|
||||
| {{a /= b}} | {{a.divAssign(b)}} |
|
||||
| {{a %= b}} | {{a.modAssign(b)}} |
|
||||
|
||||
For the assignment operations, e.g. {{a += b}}, the compiler performs the following steps:
|
||||
# If the function from the right column is available
|
||||
## If the corresponding binary function (i.e. {{plus()}} for {{plusAssign()}}) is available too, report error (ambiguity).
|
||||
## Make sure its return type is {{Unit}}, and report an error otherwise.
|
||||
## Generate code for {{a.plusAssign(b)}}
|
||||
# Otherwise, try to generate code for {{a = a + b}} (this includes a type check: the type of {{a + b}} must be a subtype of {{a}}).
|
||||
|
||||
*Note*: assignments are *NOT* expressions in [Kotlin].
|
||||
|
||||
{anchor:Equals}
|
||||
||Expression||Translated to||
|
||||
| {{a == b}} | {{a?.equals(b) ?: b.identityEquals(null)}} |
|
||||
| {{a \!= b}} | {{\!(a?.equals(b) ?: b.identityEquals(null))}} |
|
||||
|
||||
*Note*: {{identityEquals}} checks if two references point to the same object.
|
||||
|
||||
The {{==}} operation is special in two ways:
|
||||
# It is translated to a complex expression that screens for *null*'s, and {{null == null}} is *true*.
|
||||
# It looks up a function with a specific _signature_, not just a specific _name_. The function must be declared as
|
||||
{code}
|
||||
fun equals(other : Any?) : Boolean
|
||||
{code}
|
||||
Or an extension function with the same parameter list and return type.
|
||||
|
||||
||Symbol||Translated to||
|
||||
| {{a > b}} | {{a.compareTo(b) > 0}} |
|
||||
| {{a < b}} | {{a.compareTo(b) < 0}} |
|
||||
| {{a >= b}} | {{a.compareTo(b) >= 0}} |
|
||||
| {{a <= b}} | {{a.compareTo(b) <= 0}} |
|
||||
|
||||
All comparisons are translated into calls to {{compareTo}}, that is required to return {{Int}}.
|
||||
|
||||
h4. Infix calls for named functions
|
||||
|
||||
One can simulate custom infix operations by using [infix function calls|Functions#Infix calls].
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Extension functions]
|
||||
* [Function literals]
|
||||
* [Type-safe Groovy-style builders]
|
||||
-263
@@ -1,263 +0,0 @@
|
||||
The concept of [builders|http://groovy.codehaus.org/Builders] is rather popular in the *Groovy* community. Builders allow for defining data in a semi-declarative way. Builders are good for [generating XML|http://groovy.codehaus.org/GroovyMarkup], [laying out UI components|http://groovy.codehaus.org/GroovySWT], [describing 3D scenes|http://www.artima.com/weblogs/viewpost.jsp?thread=296081] and more...
|
||||
|
||||
For many use cases, [Kotlin] allows to *type-check* builders, which makes them even more attractive than the dynamically-typed implementation made in *Groovy* itself.
|
||||
|
||||
For the rest of the cases, [Kotlin] supports [dynamic|Dynamic types] builders.
|
||||
|
||||
h3. A type-safe builder example
|
||||
|
||||
Consider the following code that is taken from [here|http://groovy.codehaus.org/Builders] and slightly adapted:
|
||||
{jet}
|
||||
import <ref="html_ns":>html.*
|
||||
|
||||
fun result(args : Array<String>) =
|
||||
<ref="html":>html {
|
||||
<ref="head":>head {
|
||||
<ref="title":>title {<ref="plus":>+"XML encoding with Kotlin"}
|
||||
}
|
||||
<ref="body":>body {
|
||||
<ref="h1":>h1 {<ref="plus":>+"XML encoding with Kotlin"}
|
||||
<ref="p":>p {<ref="plus":>+"this format can be used as an alternative markup to XML"}
|
||||
|
||||
// an element with attributes and text content
|
||||
<ref="a":>a(href = "http://jetbrains.com/kotlin") {<ref="plus":>+"Kotlin"}
|
||||
|
||||
// mixed content
|
||||
<ref="p":>p {
|
||||
<ref="plus":>+"This is some"
|
||||
<ref="b":>b {<ref="plus":>+"mixed"}
|
||||
<ref="plus":>+"text. For more see the"
|
||||
<ref="a":>a(href = "http://jetbrains.com/kotlin") {<ref="plus":>+"Kotlin"}
|
||||
<ref="plus":>+"project"
|
||||
}
|
||||
<ref="p":>p {<ref="plus":>+"some text"}
|
||||
|
||||
// content generated by
|
||||
<ref="p":>p {
|
||||
for (arg in args)
|
||||
<ref="plus":>+arg
|
||||
}
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
This is a completely legitimate [Kotlin] code. Click on names to navigate to definitions of function used in this example (they appear below in this page).
|
||||
|
||||
h3. How it works
|
||||
|
||||
Let's walk through the mechanisms of implementing type safe builders in [Kotlin]. First of all we need to define the model we want to build, in this case we need to model HTML tags. It is easily done with a bunch of classes. For example, {{HTML}} is a class that describes the {{<html>}} tag, i.e. it defines children like {{<head>}} and {{<body>}}.
|
||||
(See its declaration [below|#declarations].)
|
||||
|
||||
Now, let's recall why we can say something like this in the code:
|
||||
{jet}
|
||||
html {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
This is actually a function call that takes a [function literal|Function literals] as an argument (see [this page|Functions#Higher-order functions] for details). Actually, this function is defined as follows:
|
||||
{jet}
|
||||
fun html(init : HTML.() -> Unit) : HTML {
|
||||
val html = HTML()
|
||||
html.init()
|
||||
return html
|
||||
}
|
||||
{jet}
|
||||
This function takes one parameter named {{init}}, which is itself a function. Actually, it is an [extension function|Extension functions] that has a receiver of type {{HTML}} (and returns nothing interesting, i.e. [Unit|Functions#Unit]). So, when we pass a function literal to as an argument to {{html}}, it is typed as an extension function literal, and there's *this* reference available:
|
||||
{jet}
|
||||
html {
|
||||
this.head { /* ... */ }
|
||||
this.body { /* ... */ }
|
||||
}
|
||||
{jet}
|
||||
({{head}} and {{body}} are member functions of {{HTML}}.)
|
||||
Now, *this* can be omitted, as usual, and we get something that looks very much like a builder already:
|
||||
{jet}
|
||||
html {
|
||||
head { /* ... */ }
|
||||
body { /* ... */ }
|
||||
}
|
||||
{jet}
|
||||
So, what does this call do? Let's look at the body of {{html}} function as defined above. It creates a new instance of {{HTML}}, then it initializes it by calling the function that is passed as an argument (in our example this boils down to calling {{body}} on the {{HTML}} instance), and then it returns this instance. This is exactly what a builder should do.
|
||||
|
||||
The {{head}} and {{body}} functions in the {{HTML}} class is defined similarly to {{html}}. The only difference is that they add the built instanced to the {{children}} collection of the enclosing {{HTML}} instance:
|
||||
{jet}
|
||||
fun head(init : Head.() -> Unit) {
|
||||
val head = Head()
|
||||
head.init()
|
||||
<ref="children":>children.add(head)
|
||||
return head
|
||||
}
|
||||
|
||||
fun body(init : Body.() -> Unit) {
|
||||
val body = Body()
|
||||
body.init()
|
||||
<ref="children":>children.add(body)
|
||||
return body
|
||||
}
|
||||
{jet}
|
||||
Actually these two functions do just the same thing, so we can have a generic version, {{initTag}}:
|
||||
{jet}
|
||||
protected fun initTag<T : Element>(init : T.() -> Unit) : T
|
||||
where class object T : Factory<T> {
|
||||
val tag = T.create()
|
||||
tag.init()
|
||||
<ref="children":>children.add(tag)
|
||||
return tag
|
||||
}
|
||||
{jet}
|
||||
This function uses [class objects|Classes and Inheritance#Class objects] to instantiate classes. It depends on the {{Factory}} class defined as follows:
|
||||
{jet}
|
||||
abstract class Factory<T> {
|
||||
fun create() : T
|
||||
}
|
||||
{jet}
|
||||
|
||||
Now, the classes {{Head}} and {{Body}} declare class objects that extend {{Factory}}, for example:
|
||||
{jet}
|
||||
class Head() : TagWithText("head") {
|
||||
class object : Factory<Head> {
|
||||
override fun create() = Head()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
So, now our functions are very simple:
|
||||
{jet}
|
||||
fun head(init : Head.() -> Unit) = initTag(init)
|
||||
|
||||
fun body(init : Body.() -> Unit) = initTag(init)
|
||||
{jet}
|
||||
|
||||
And we can use them to build {{<head>}} and {{<body>}} tags.
|
||||
|
||||
One other thing to be discussed here is how we add text to tag bodies. In the example above we say something like
|
||||
{jet}
|
||||
<ref="html":>html {
|
||||
<ref="head":>head {
|
||||
<ref="title":>title {<ref="plus":>+"XML encoding with Kotlin"}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
So basically, we just put a string inside a tag body, but there is this little "+" in front of it, do it is a function call that invokes a prefix "plus" operation. That operation is actually defined by an extension function {{plus}} that is a member of the {{TagWithText}} abstract class (a parent of {{Title}}):
|
||||
{jet}
|
||||
fun String.plus() {
|
||||
<ref="children":>children.add(TextElement(this))
|
||||
}
|
||||
{jet}
|
||||
So, what the prefix "+" does here is it wraps a string into an instance of {{TextElement}} and adds it to the {{children}} collection, so that it becomes a proper part of the tag tree.
|
||||
|
||||
All this is defined in a namespace {{html}} that is imported at the top of the builder example above. In the next section you can read through the full definition of this namespace.
|
||||
|
||||
h3. Full definition of the {{html}} namespace
|
||||
|
||||
This is how the namespace {{html}} is defined (only the elements used in the example above). It builds an HTML tree. It makes heavy use of [Extension functions] and [Extension function literals|Function literals#Extensions].
|
||||
{anchor:declarations}{jet}
|
||||
<label="html_ns":>namespace html {
|
||||
|
||||
<label="Factory":>abstract class Factory<T> {
|
||||
fun create() : T
|
||||
}
|
||||
|
||||
<label="Element":>abstract class Element
|
||||
|
||||
<label="TextElement":>class TextElement(val text : String) : Element
|
||||
|
||||
<label="Tag":>abstract class Tag(val name : String) : Element {
|
||||
<label="children":>val children = ArrayList<Element>()
|
||||
<label="attributes":>val attributes = HashMap<String, String>()
|
||||
|
||||
protected fun initTag<T : Element>(init : T.() -> Unit) : T
|
||||
where class object T : Factory<T> {
|
||||
val tag = T.create()
|
||||
tag.init()
|
||||
<ref="children":>children.add(tag)
|
||||
return tag
|
||||
}
|
||||
}
|
||||
|
||||
<label="TagWithText":>abstract class TagWithText(name : String) : Tag(name) {
|
||||
<label="plus"/>fun String.plus() {
|
||||
children.add(TextElement(this))
|
||||
}
|
||||
}
|
||||
|
||||
<label="HTML":>class HTML() : TagWithText("html") {
|
||||
class object : Factory<HTML> {
|
||||
override fun create() = HTML()
|
||||
}
|
||||
|
||||
<label="head"/>fun head(init : Head.() -> Unit) = initTag(init)
|
||||
|
||||
<label="body"/>fun body(init : Body.() -> Unit) = initTag(init)
|
||||
}
|
||||
|
||||
<label="Head":>class Head() : TagWithText("head") {
|
||||
class object : Factory<Head> {
|
||||
override fun create() = Head()
|
||||
}
|
||||
|
||||
<label="title"/>fun title(init : Title.() -> Unit) = initTag(init)
|
||||
}
|
||||
|
||||
<label="Title":>class Title() : TagWithText("title")
|
||||
|
||||
<label="BodyTag":>abstract class BodyTag(name : String) : TagWithText(name) {
|
||||
}
|
||||
|
||||
<label="Body":>class Body() : BodyTag("body") {
|
||||
class object : Factory<Body> {
|
||||
override fun create() = Body()
|
||||
}
|
||||
|
||||
<label="b"/>fun b(init : B.() -> Unit) = initTag(init)
|
||||
<label="p"/>fun p(init : P.() -> Unit) = initTag(init)
|
||||
<label="h1"/>fun h1(init : H1.() -> Unit) = initTag(init)
|
||||
<label="a"/>fun a(href : String, init : A.() -> Unit) {
|
||||
val a = initTag(init)
|
||||
a.href = href
|
||||
}
|
||||
}
|
||||
|
||||
class B() : BodyTag("b")
|
||||
class P() : BodyTag("p")
|
||||
class H1() : BodyTag("h1")
|
||||
class A() : BodyTag("a") {
|
||||
var href : String
|
||||
get() = <ref="attributes":>attributes["href"]
|
||||
set(value) { <ref="attributes":>attributes["href"] = value }
|
||||
}
|
||||
|
||||
<label="html"/>fun html(init : HTML.() -> Unit) : HTML {
|
||||
val html = HTML()
|
||||
html.init()
|
||||
return html
|
||||
}
|
||||
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. Appendix. Making Java classes nicer
|
||||
|
||||
In the code above there's something that looks very nice:
|
||||
{jet}
|
||||
class A() : BodyTag("a") {
|
||||
var href : String
|
||||
get() = <ref="attributes":>attributes["href"]
|
||||
set(value) { <ref="attributes":>attributes["href"] = value }
|
||||
}
|
||||
{jet}
|
||||
We access the {{attributes}} map as if it were an "associative array": just with the {{\[\]}} operation. By [convention|Operator overloading] this compiles to a call to {{get(K)}} or {{set(K, V)}}, all right. But we said that {{attributes}} was a *Java* {{Map}}, i.e. it does NOT have a {{set(K, V)}}. This problem is easily fixable in [Kotlin]:
|
||||
{jet}
|
||||
fun <K, V> Map<K, V>.set(key : K, value : V) = this.put(key, value)
|
||||
{jet}
|
||||
So, we simply define an [extension function|Extension functions] {{set(K, V)}} that delegates to vanilla {{put}} and make a [Kotlin] operator available for a *Java* class.
|
||||
|
||||
h3. What's next
|
||||
|
||||
*Examples*
|
||||
* [Comparison to Java]
|
||||
|
||||
*Functions*
|
||||
* [Properties And Fields]
|
||||
-178
@@ -1,178 +0,0 @@
|
||||
h2. Modules/Namespaces rethought
|
||||
|
||||
In the initial design we had modules and namespaces.
|
||||
*Module* is a unit of compilation, specifies dependencies and provides a scope for *internal* visibility.
|
||||
*Namespaces* are just intended for name disambiguation, they have a syntactic for (two, actually): each file may have a namespace declaration in the header, and all the contents are placed under that namespace. Additionally, there may be namespace blocks. Each namespace occurrence has a separate block of imports.
|
||||
|
||||
_All this looks a little bit brittle, so we rethought the design, and propose a unified concept of *packages* that replaces modules and namespaces:_
|
||||
|
||||
|
||||
h3. Packages
|
||||
|
||||
(Our packages are similar to Java's ones, but there are some important differences, so, please, read carefully.)
|
||||
|
||||
A *package* is a group of source files along with dependencies, default imports and other compiler settings.
|
||||
* Any *unit of compilation* is a package, although some packages are not units of compilation.
|
||||
* Every source file declares the package it belongs to in a *package* directive (like in Java). This is needed only for self-documentation of the code.
|
||||
** If there's no *package* directive in a file, it is a script (whatever it means)
|
||||
* Packages are not tied up to file system, one can have as many directories for the code in a single packages as they please. One can store a dozen packages in a single directory as well.
|
||||
* One file immediately belongs to exactly one package, though.
|
||||
* Every package has a unique name and encloses its contents so that there may be two entities with the same name in different packages.
|
||||
|
||||
Example of a kotlin file:
|
||||
{jet}
|
||||
package my.example
|
||||
|
||||
import other.*
|
||||
|
||||
fun foo() {} // package-level function
|
||||
class A {} // FQN is my.example.A
|
||||
class B {} // many classes in a file
|
||||
{jet}
|
||||
|
||||
Packages may *contain* other packages. By default, child packages inherit all the compiler settings from their parents.
|
||||
* Every package defines a *visibility* scope. It may contain *internal* members, including child packages. Internal members are visible to all the members of the package and their members as well.
|
||||
* Only members of the same package are visible by default (without importing). Members of child and enclosing packages are accessible but require importing.
|
||||
|
||||
Example:
|
||||
{jet}
|
||||
package my.example.other // sits inside my.example
|
||||
|
||||
val a : <unresolved:>A = ... // class my.example.A is not visible without importing
|
||||
fun foo() {} // default visibility is internal: visible to child packages and other members of this package
|
||||
|
||||
public class Foo {} // visible to everybody who sees this package
|
||||
{jet}
|
||||
|
||||
To specify package *settings* such as visibility, dependencies etc, one may define a package configuration script in the spirit of former module scripts.
|
||||
* At least the root package in the project must have such a script, a single script may describe several packages.
|
||||
* If a package has no script, then it's visibility is *internal* and all the other settings are inherited from its parent.
|
||||
|
||||
h3. Summary. Diff from Java
|
||||
|
||||
How Kotlin packages are better that Java ones:
|
||||
* In Kotlin package is a *unit* of compilation (optimization for *internal* things)
|
||||
* Kotlin packages specify their dependencies, default imports and other compiler settings
|
||||
* Packages truly nest in Kotlin (hence *internal* visibility is useful)
|
||||
* Kotlin packages are not folders, i.e. not tied up to the file system
|
||||
* You name it
|
||||
|
||||
*Your objections/corrections/proposals are very welcome in the comments.*
|
||||
|
||||
----
|
||||
|
||||
Here goes the old descriptions of modules:
|
||||
|
||||
h2. Overall structure
|
||||
|
||||
A *module* is a unit of compilation, i.e. we do not compile classes or source file, we compile _modules_.
|
||||
A module descriptor contains information about source files that reside in the module, how they are divided into production code and test code, dependencies, compiler options and so on.
|
||||
|
||||
h3. Module scripts
|
||||
|
||||
Physically, modules are represented as *scripts* written in Kotlin. The compiler (or IDE, or other tool) runs a script that builds a module object in memory, and uses the information from that object to resolve dependencies and compile the sources.
|
||||
|
||||
A script creates objects that describe the modules and adds them to a *project* object that is passed to the script by the caller (typically, the compiler or the IDE).
|
||||
|
||||
h3. Class path issues & configuration
|
||||
|
||||
There're two kinds of class paths:
|
||||
* Compiler class path: classes that Kotlin compiler uses at runtime
|
||||
** module scripts are compiled against this class path
|
||||
** this class path is configured in a {{.kotlinrc}} file: there's a global one, one in home dir, and one in local dir
|
||||
* Module class path: classes the module is compiled against (does not necessarily contain all classes in the compiler class path)
|
||||
** Specified in a module script
|
||||
|
||||
Example:
|
||||
Compiler class path would contain things like {{maven4kotlin.jar}}, {{my_compiler_extension_1.0.jar}} and such.
|
||||
Module class path would contain things like {{my_nosqldb_driver.jar}}, {{my_actor_library.jar}}, {{janes_module.jar}} and such.
|
||||
|
||||
h2. Information that constitutes a module descriptor
|
||||
* Basic metadata
|
||||
** Root namespace/module name
|
||||
* Sources
|
||||
** Kotlin source files
|
||||
** Java source files
|
||||
* Compiler options
|
||||
** Kotlin compiler options
|
||||
*** Extensions -- what compiler extensions to use to compile this module
|
||||
*** Default imports -- what's imported by default into every source file
|
||||
** Javac options
|
||||
* Dependencies (each may be exported or private, and embedded, jarjar'ed or not embedded)
|
||||
** JDK
|
||||
** Java-style class path
|
||||
** Kotlin modules
|
||||
** Maven modules
|
||||
** ...
|
||||
* User data
|
||||
** Key-value pairs
|
||||
|
||||
NOTE: currently there's no built-in versioning for modules planned. We intend to reuse Maven for that.
|
||||
|
||||
Files are treated according to their types. E.g. *.java files are Java sources, *.kt files are Kotlin sources etc. One can register custom file types in a module script.
|
||||
|
||||
h2. What a module script looks like
|
||||
|
||||
Syntactically, a script is not a normal Kotlin source file: it contains import directives followed immediately by code. And this code has an implicit receiver of type {{Project}} that has member functions for building module objects:
|
||||
{jet}
|
||||
import kotlin.modules.dependencies.maven.*
|
||||
|
||||
fun ModuleBuilder.defineModules() {
|
||||
jdk = defaultJDK("1.6")
|
||||
|
||||
// Standard extensions are registered, adding custom ones
|
||||
source mask "*.jav" language java // Non-standard extension for Java
|
||||
source mask "*.kt" language kotlin
|
||||
resource mask "*.bundle"
|
||||
|
||||
module ("org.example.mymodule") {
|
||||
source files "kotlin/src/*.kt"
|
||||
source root "kotlin_src"
|
||||
source root "java_src"
|
||||
|
||||
kotlin extension MyCoolExtension
|
||||
kotlin import "kotlin.*"
|
||||
kotlin import "java.lang.*"
|
||||
kotlin import "java.util.*"
|
||||
|
||||
javac options "-g:lines -Afoo=bar"
|
||||
|
||||
classpath entries "lib/*.jar"
|
||||
classpath entry "bin/classes"
|
||||
|
||||
require module "org.jetbrains.extras"
|
||||
require maven "junit" version "3.8.1"
|
||||
|
||||
resource root "resources"
|
||||
|
||||
data["key"] = "value"
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
Actually, the {{module()}} is called on the *this* reference that represents current project.
|
||||
|
||||
One other difference from normal Kotlin is that a script can define *public val*'s. A public *val* may be used by another script that "requires" this one:
|
||||
|
||||
E.g., {{Compiler.kts}}:
|
||||
{jet}
|
||||
public val frontend = module("kotlin.frontend") {
|
||||
...
|
||||
}
|
||||
public val frontend_java = module("kotlin.frontend.java") {
|
||||
...
|
||||
}
|
||||
public val backend = module("kotlin.backend") {
|
||||
...
|
||||
}
|
||||
{jet}
|
||||
|
||||
{{IDE.kts}}:
|
||||
{jet}
|
||||
val compiler = requireScript<Compiler>
|
||||
|
||||
module ("ide") {
|
||||
...
|
||||
require module compiler.frontend
|
||||
}
|
||||
{jet}
|
||||
@@ -1,53 +0,0 @@
|
||||
{jet}
|
||||
namespace addressbook
|
||||
|
||||
class Contact(
|
||||
val name : String,
|
||||
val emails : List<EmailAddress>,
|
||||
val addresses : List<PostalAddress>,
|
||||
val phonenums : List<PhoneNumber>
|
||||
)
|
||||
|
||||
class EmailAddress(
|
||||
val user : String,
|
||||
val host : String
|
||||
)
|
||||
|
||||
class PostalAddress(
|
||||
val streetAddress : String,
|
||||
val city : String,
|
||||
val zip : String,
|
||||
val state : USState?,
|
||||
val country : Country
|
||||
) {
|
||||
assert {(state == null) xor (country == Countries["US"]) }
|
||||
}
|
||||
|
||||
class PhoneNumber(
|
||||
val country : Country,
|
||||
val areaCode : Int,
|
||||
val number : Long
|
||||
)
|
||||
|
||||
object Countries {
|
||||
fun get(id : CountryID) : Country = countryTable[id]
|
||||
|
||||
private var table : Map<String, Country>? = null
|
||||
private val countryTable : Map<String, Country>
|
||||
get() {
|
||||
if (table == null) {
|
||||
table = HashMap()
|
||||
for (line in TextFile("countries.txt").lines(stripWhiteSpace = true)) {
|
||||
table[line] = Country(line)
|
||||
}
|
||||
}
|
||||
return table
|
||||
}
|
||||
}
|
||||
|
||||
class Country(val name : String)
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [HTML builder example|Type-safe Groovy-style builders]
|
||||
@@ -1,249 +0,0 @@
|
||||
h4. Define a package
|
||||
|
||||
{jet}
|
||||
package my.demo // One per file
|
||||
|
||||
import std.io.*
|
||||
|
||||
// ...
|
||||
{jet}
|
||||
|
||||
See [Packages].
|
||||
|
||||
h4. Define a function
|
||||
|
||||
{jet}
|
||||
// Return type mandatory
|
||||
fun sum(a : Int, b : Int) : Int {
|
||||
return a + b
|
||||
}
|
||||
{jet}
|
||||
|
||||
or
|
||||
|
||||
{jet}
|
||||
// Return type may be inferred
|
||||
fun sum(a : Int, b : Int) = a + b
|
||||
{jet}
|
||||
|
||||
When no meaningful value returned:
|
||||
{jet}
|
||||
fun printSum(a : Int, b : Int) : Unit {
|
||||
print(a + b)
|
||||
}
|
||||
{jet}
|
||||
|
||||
or
|
||||
|
||||
{jet}
|
||||
// Return type is optional when Unit is intended
|
||||
fun printSum(a : Int, b : Int) {
|
||||
print(a + b)
|
||||
}
|
||||
{jet}
|
||||
|
||||
See [Functions].
|
||||
See [Hello, world!].
|
||||
|
||||
h4. Define a local variable
|
||||
|
||||
Assign-once (read-only) local variable:
|
||||
{jet}
|
||||
val a : Int = 1
|
||||
val b = 1 // Type is inferred
|
||||
val c : Int // Type required when no initializer provided
|
||||
c = 1 // definite assignment
|
||||
{jet}
|
||||
|
||||
Note that [semicolons are optional|Grammar#Semicolons].
|
||||
|
||||
Mutable variable:
|
||||
{jet}
|
||||
var x = 5 // Type inferred
|
||||
x += 1
|
||||
{jet}
|
||||
|
||||
See also [Properties And Fields].
|
||||
|
||||
h4. Use a string template
|
||||
|
||||
{jet}
|
||||
fun main(args : Array<String>) {
|
||||
if (args.size == 0) return
|
||||
|
||||
print("First argument: ${args[0]}")
|
||||
}
|
||||
{jet}
|
||||
|
||||
See [String templates|Strings#Templates].
|
||||
See [Arrays|Basic types#Arrays].
|
||||
|
||||
h4. Use a conditional expression
|
||||
|
||||
{jet}
|
||||
fun max(a : Int, b : Int) : Int {
|
||||
if (a > b)
|
||||
return a
|
||||
else
|
||||
return b
|
||||
}
|
||||
{jet}
|
||||
|
||||
or
|
||||
{jet}
|
||||
// 'if' is an expression
|
||||
fun max(a : Int, b : Int) = if (a > b) a else b
|
||||
{jet}
|
||||
|
||||
See [{{if}} expressions|Control structures#If].
|
||||
|
||||
h5. Null-checks
|
||||
|
||||
A reference must be explicitly marked as _nullable_ to be able hold a {{null}}:
|
||||
{jet}
|
||||
package multiplier
|
||||
|
||||
// Return null if str does not hold a number
|
||||
fun parseInt(str : String) : Int? {
|
||||
// ...
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
if (args.size < 2) {
|
||||
print("No number supplied");
|
||||
}
|
||||
val x = parseInt(args[0])
|
||||
val y = parseInt(args[1])
|
||||
|
||||
// We cannot say 'x * y' now because they may hold nulls
|
||||
|
||||
if (x != null && y != null) {
|
||||
print(x * y) // Now we can
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
or
|
||||
|
||||
{jet}
|
||||
// ...
|
||||
if (x == null) {
|
||||
print("Wrong number format in '${args[0]}'")
|
||||
return
|
||||
}
|
||||
if (y == null) {
|
||||
print("Wrong number format in '${args[1]}'")
|
||||
return
|
||||
}
|
||||
print(x * y) // Now we know that x and y are not nulls
|
||||
{jet}
|
||||
|
||||
See [Null-safety].
|
||||
|
||||
h5. {{is}}-checks and automatic casts
|
||||
|
||||
The *is* operator checks if an expression is an instance of a type (and [more|Pattern matching]). If we *is*-checked an immutable local variable or property, there's no need to cast it explicitly to the *is*-checked type:
|
||||
{jet}
|
||||
fun getStringLength(obj : Any) : Int? {
|
||||
if (obj is String)
|
||||
return obj.length // no cast to String is needed
|
||||
return null
|
||||
}
|
||||
{jet}
|
||||
|
||||
or
|
||||
|
||||
{jet}
|
||||
fun getStringLength(obj : Any) : Int? {
|
||||
if (obj !is String)
|
||||
return null
|
||||
return obj.length // no cast to String is needed
|
||||
}
|
||||
{jet}
|
||||
|
||||
See [Classes and Inheritance].
|
||||
See [Type casts].
|
||||
|
||||
h4. Use a {{for}}-loop
|
||||
|
||||
{jet}
|
||||
fun main(args : Array<String>) {
|
||||
for (arg in args)
|
||||
print(arg)
|
||||
|
||||
// or
|
||||
|
||||
for (i in args.indices)
|
||||
print(args[i])
|
||||
}
|
||||
{jet}
|
||||
|
||||
See [{{for}}-loops|Control structures#For].
|
||||
|
||||
h4. Use a {{while}}-loop
|
||||
|
||||
{jet}
|
||||
fun main(args : Array<String>) {
|
||||
var i = 0
|
||||
while (i < args.size)
|
||||
print(args[i++])
|
||||
}
|
||||
{jet}
|
||||
|
||||
See [{{while}}-loop|Control structures#While].
|
||||
|
||||
h4. Use pattern-matching
|
||||
|
||||
{jet}
|
||||
fun cases(obj : Any) {
|
||||
when (obj) {
|
||||
1 -> print("One")
|
||||
"Hello" -> print("Greeting")
|
||||
is Long -> print("Long")
|
||||
!is String -> print("Not a string"
|
||||
else -> print("Unknown")
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
See [Pattern matching].
|
||||
|
||||
h4. Use ranges and {{in}}
|
||||
|
||||
Check if a number lies within a range:
|
||||
{jet}
|
||||
if (x in 1..y-1)
|
||||
print("OK")
|
||||
{jet}
|
||||
|
||||
Check if a number is out of range:
|
||||
{jet}
|
||||
if (x !in 0..array.lastIndex)
|
||||
print("Out")
|
||||
{jet}
|
||||
|
||||
Check if a collection contains an object:
|
||||
{jet}
|
||||
if (obj in collection) // collection.contains(obj) is called
|
||||
print("Yes")
|
||||
{jet}
|
||||
|
||||
Iterate over a range:
|
||||
{jet}
|
||||
for (x in 1..5)
|
||||
print(x)
|
||||
{jet}
|
||||
|
||||
See [Ranges].
|
||||
|
||||
h4. Use function literals to filter and map collections
|
||||
|
||||
{jet}
|
||||
names filter {it.startsWith("A")} sortby {it} map {it.toUpperCase()} foreach {print(it)}
|
||||
{jet}
|
||||
|
||||
See [Higher-order functions|Functions#Higher-order functions] and [Function literals].
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Address book example|Address book]
|
||||
@@ -1,104 +0,0 @@
|
||||
This page gives some very basic examples of [Kotlin] syntax.
|
||||
|
||||
h3. Simplest version
|
||||
|
||||
{jet:linenumbers=true}
|
||||
package demo
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
println("Hello, world!")
|
||||
}
|
||||
{jet}
|
||||
|
||||
Line 1 is the optional [package header|Packages#Header package declaration].
|
||||
Then we declare a [package-level|Packages] function {{main}} which [returns {{Unit}}|Functions#Unit] and takes an [Array|Basic types#Arrays] of strings as a parameter.
|
||||
|
||||
Note that [semicolons are optional|Grammar#Semicolons].
|
||||
|
||||
h3. Reading a name from the command line
|
||||
|
||||
{jet:linenumbers=true}
|
||||
fun main(args : Array<String>) {
|
||||
if (args.size == 0) {
|
||||
println("Please provide a name as a command-line argument")
|
||||
return
|
||||
}
|
||||
println("Hello, ${args[0]}!")
|
||||
}
|
||||
{jet}
|
||||
|
||||
Line 6 demonstrates [string templates|Strings#Templates] and [array access|Basic types#Arrays].
|
||||
|
||||
h3. Reading many names from the command line
|
||||
|
||||
{jet:linenumbers=true}
|
||||
fun main(args : Array<String>) {
|
||||
for (name in args)
|
||||
println("Hello, $name!")
|
||||
}
|
||||
{jet}
|
||||
|
||||
Line 2 demonstrates the [*for*\-loop|Control structures#For loop], that would have been called "enhanced" if there were any other *for*\-loop in [Kotlin] :-)
|
||||
|
||||
h3. An "object-oriented" Hello
|
||||
|
||||
{jet:linenumbers=true}
|
||||
class Greeter(val name : String) {
|
||||
fun greet() {
|
||||
println("Hello, ${name}");
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
Greeter(args[0]).greet()
|
||||
}
|
||||
{jet}
|
||||
|
||||
Here we have a [class|Classes and Inheritance] with a _primary constructor_ and a member function.
|
||||
Note that there's no *new* keyword used to create an object.
|
||||
|
||||
h3. A multi-language Hello
|
||||
|
||||
{jet:linenumbers=true}
|
||||
fun main(args : Array<String>) {
|
||||
val language = if (args.size == 0) "EN" else args[0]
|
||||
println(when (language) {
|
||||
"EN" -> "Hello!"
|
||||
"ES" -> "¡Hola!"
|
||||
"RU" -> "Привет!"
|
||||
else -> "Sorry, I can't greet you in $language yet"
|
||||
})
|
||||
}
|
||||
{jet}
|
||||
|
||||
In this example, *val* denotes a declaration of a read-only local variable, that is assigned an [*if*\-expression|Control structures#If expression]. Then we use very basic [pattern matching|Pattern matching] expression.
|
||||
|
||||
h3. Extension function {{hello()}}
|
||||
|
||||
{jet:linenumbers=true}
|
||||
fun String.hello() {
|
||||
println("Hello, $this!")
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
"world".hello() // prints 'Hello, world!'
|
||||
}
|
||||
{jet}
|
||||
|
||||
In this snippet, we define an [extension function|Extension functions] {{hello()}} for the type {{String}} that uses *this* in a [string template|Strings#Templates]. And then we call this function on a string {{"world"}}, i.e. we pass this string as the receiver-argument (*this*\-argument) to {{hello()}}.
|
||||
|
||||
h3. LINQ-like Hello
|
||||
|
||||
{jet:linenumbers=true}
|
||||
fun main(args : Array<String>) {
|
||||
args filter {it.length() > 0} forEach {print("Hello, $it!")}
|
||||
}
|
||||
{jet}
|
||||
|
||||
Here we first called the {{filter()}} [higher-order function|Functions#Higher-order functions] to select only those string from the {{args}} array that have non-zero length. To do this, we passed a [function literal|Function literals] that checks the length of its parameter. the name {{it}} is the default name of a parameter for a function literal.
|
||||
|
||||
Filter created a collection for us, and we called {{foreach()}} on that collection, passing in a function literal to be executed for each element. And that function literal just prints a greeting with the passed string.
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Basic syntax walk-through|Basic syntax walk-through]
|
||||
@@ -1,56 +0,0 @@
|
||||
In Kotlin, one can attach metadata to declarations in the form of _annotations_. To declare an annotation, put the *annotation* annotation (no pun intended :)) in front of a normal class:
|
||||
{jet}
|
||||
annotation class fancy {}
|
||||
{jet}
|
||||
(Note that, by convention, annotation classes are named with the lowercase fitst letter; the reason will be clear from the examples below.)
|
||||
Now we can annotate a declaration or an expression with the new {{fancy}} annotation. In general, one puts square brackets around the annotation name:
|
||||
{jet}
|
||||
[fancy] class Foo {
|
||||
[fancy] fun baz([fancy] foo : Int) : Int {
|
||||
return [fancy] 1
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
{note:title=Annotations are under development}{note}
|
||||
|
||||
When annotating a declaration (e.g. a function or a class), the square brackets may be omitted:
|
||||
{jet}
|
||||
fancy class Foo() {
|
||||
fancy fun baz(fancy foo: Int) {
|
||||
return [fancy] 1
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Note that square brackets are required for expressions.
|
||||
|
||||
Annotation classes may have constructors that take parameters. For example:
|
||||
{jet}
|
||||
annotation class special(val why : String)
|
||||
|
||||
special("example") class Foo {}
|
||||
{jet}
|
||||
As you can see, to pass arguments to an annotation one simply calls its constructor.
|
||||
|
||||
On the JVM one can re-use Java annotations:
|
||||
{jet}
|
||||
import org.junit.Test
|
||||
import org.junit.Assert.*
|
||||
|
||||
class Tests {
|
||||
Test fun simple() {
|
||||
assertEquals(42, getTheAnswer())
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
If you want your Java annotations to look like modifiers, you can rename them on import:
|
||||
|
||||
{jet}
|
||||
import org.junit.Test as test
|
||||
|
||||
class Tests {
|
||||
test fun simple() {
|
||||
...
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
@@ -1,181 +0,0 @@
|
||||
In [Kotlin], everything is an object in the sense that one can call member functions and properties on any variable. Some types are built-in, because their implementation is optimized, but for the used they look like ordinary classes. In this section we describe most of these types: [numbers|#Numbers], [characters|#Characters], [booleans|#Booleans] and [arrays|#Arrays].
|
||||
|
||||
h3. Numbers
|
||||
|
||||
[Kotlin] handles numbers in a way close to *Java*, but not exactly the same. For example, there are no _implicit widening conversions_ or numbers, and literals are slightly different in some cases.
|
||||
|
||||
[Kotlin] provides the following built-in types representing numbers (this is close to *Java*):
|
||||
|| Type || Bitwidth ||
|
||||
| Double | 64 |
|
||||
| Float | 32 |
|
||||
| Long | 64 |
|
||||
| Int | 32 |
|
||||
| Short | 16 |
|
||||
| Byte | 8 |
|
||||
|
||||
Note that [characters|#Characters] are not numbers in [Kotlin].
|
||||
|
||||
h4. Representation
|
||||
|
||||
On the *Java* platform, numbers are physically stored as JVM primitive types, unless we need a [nullable|Null-safety] number reference (e.g. {{Int?}}) or generics are involved. In the latter cases numbers are _boxed_.
|
||||
|
||||
*Note* that boxing of numbers does not preserve [identity|Basic operations]:
|
||||
{jet}
|
||||
val a : Int = 10000
|
||||
print(a identityEquals a) // Prints 'true'
|
||||
val boxedA : Int? = a
|
||||
val anotherBoxedA : Int? = a
|
||||
print(boxedA identityEquals anotherBoxedA) // !!!Prints 'false'!!!
|
||||
{jet}
|
||||
On the other hand, it preserves [equality|Expressions#Equality checks]:
|
||||
{jet}
|
||||
val a : Int = 10000
|
||||
print(a == a) // Prints 'true'
|
||||
val boxedA : Int? = a
|
||||
val anotherBoxedA : Int? = a
|
||||
print(boxedA == anotherBoxedA) // Prints 'true'
|
||||
{jet}
|
||||
|
||||
h4. Explicit conversions
|
||||
|
||||
Due to different representations, smaller types are not _subtypes_ of bigger ones.
|
||||
If they were, we would have troubles of the following sort:
|
||||
{jet}
|
||||
// Hypothetical code, does not actually compile:
|
||||
val a : Int? = 1 // A boxed Int (java.lang.Integer)
|
||||
val b : Long? = a // implicit conversion yields a boxed Long (java.lang.Long)
|
||||
print(a == b) // Surprise! This prints "false" as Long's equals() check for other part to be Long as well
|
||||
{jet}
|
||||
So not only identity, but even equality would have been lost silently all over the place.
|
||||
|
||||
As a consequence, smaller types are *NOT* implicitly converted to bigger types. This means that one cannot assign a value of type {{Byte}} to an {{Integer}} variable without an explicit conversion:
|
||||
{jet}
|
||||
val b : Byte = 1 // OK, literals are checked statically
|
||||
val i : Int = <error desc="Incompatible types: Byte cannot be assigned to a variable of type Int. Use the explicit conversion '.int'">b</error> // ERROR
|
||||
{jet}
|
||||
One can use *explicit conversions* to widen numbers:
|
||||
{jet}
|
||||
val i : Int = b.int // OK: explicitly widened
|
||||
{jet}
|
||||
|
||||
Every number type supports the following conversions:
|
||||
* {{toLong() : Byte}}
|
||||
* {{toShort() : Short}}
|
||||
* {{toInt() : Int}}
|
||||
* {{toLong() : Long}}
|
||||
* {{toFloat() : Float}}
|
||||
* {{toDouble() : Double}}
|
||||
* {{toChar() : Char}}
|
||||
|
||||
Absence of implicit conversions is rarely noticeable because one can use literals almost freely cause the type is inferred from the context, and arithmetical operations are _overloaded_ for appropriate conversions, for example
|
||||
{jet}
|
||||
val l = 1.toLong() + 3 // Long + Int => Long
|
||||
{jet}
|
||||
|
||||
h4. Literals
|
||||
|
||||
All the integer literals are written in the same way:
|
||||
* Decimals: {{123}}, {{123.5}}, {{123.5e10}}
|
||||
* Hexadecimals: {{0x0F}}
|
||||
* Binaries: {{0b00001011}}
|
||||
|
||||
*NOTE*: Octal literals are not supported.
|
||||
|
||||
There're no "L"-tagged or otherwise tagged literals. In case of ambiguity, one should use explicit conversions to specify a type for a literal:
|
||||
{jet}
|
||||
val list = list(1.toLong(), 100000000000, 2.toLong())
|
||||
{jet}
|
||||
|
||||
h4. Operations
|
||||
|
||||
[Kotlin] supports the standard set of arithmetical operations over numbers, which are declared as members of appropriate classes (but the compiler optimizes the calls down to the corresponding instructions). See [Operator overloading|Functions#Operator overloading].
|
||||
|
||||
As of _bitwise_ operations, there're no special characters for them, but just named functions that can be called in [infix form|Functions#Infix calls], for example:
|
||||
{jet}
|
||||
val x = (1 shl 2) and 0x000FF000
|
||||
{jet}
|
||||
Here is the complete list of bitwise operations (available for {{Int}} and {{Long}} only):
|
||||
* {{shl(bits)}} -- signed shift left (*Java*'s {{<<}})
|
||||
* {{shr(bits)}} -- signed shift right (*Java*'s {{>>}})
|
||||
* {{ushr(bits)}} -- unsigned shift right (*Java*'s {{>>>}})
|
||||
* {{and(bits)}} -- bitwise {{and}}
|
||||
* {{or(bits)}} -- bitwise {{or}}
|
||||
* {{xor(bits)}} -- bitwise {{xor}}
|
||||
* {{inv()}} -- bitwise inversion
|
||||
|
||||
h2. Characters
|
||||
|
||||
Characters are represented by the type {{Char}}. They are can not be treated directly as numbers:
|
||||
{jet}
|
||||
fun check(c : Char) {
|
||||
if (c <error desc="A value of type Char cannot be equal to a value of type Int">==</error> 1) { // ERROR: incompatible types
|
||||
// ...
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Character literals go in single quotes: {{'1'}}, {{'\n'}}, {{'\uFF00'}}.
|
||||
One can explicitly _convert_ a character to an {{Int}} number:
|
||||
{jet}
|
||||
fun decimalDigitValue(c : Char) : Int {
|
||||
if (c !in '0'..'9')
|
||||
throw IllegalArgumentException("Out of range")
|
||||
return c.toInt() - '0'.toInt() // Explicit conversions to numbers
|
||||
}
|
||||
{jet}
|
||||
|
||||
Like numbers, characters are *boxed* when a nullable reference is needed. Identity is not preserved by the boxing operation.
|
||||
|
||||
h2. Booleans
|
||||
|
||||
The type {{Boolean}} represents booleans, and has two values: {{true}} and {{false}}.
|
||||
|
||||
Booleans are boxed if a nullable reference is needed.
|
||||
|
||||
Built-in operations on booleans include
|
||||
* {{\|\|}} -- lazy disjunction
|
||||
* {{&&}} -- lazy conjunction
|
||||
|
||||
h3. Arrays
|
||||
|
||||
Arrays in [Kotlin] are represented by the {{Array}} class, that has {{get}} and {{set}} functions (that turn into {{\[\]}} by [operator overloading conventions|Operator overloading]), and {{size}}, along with a few other useful member functions:
|
||||
{jet}
|
||||
class Array<T>(val size : Int, init : (Int) -> T) {
|
||||
fun get(index : Int) : T
|
||||
fun set(index : Int, value : T) : Unit
|
||||
|
||||
fun iterator() : Iterator<T>
|
||||
|
||||
val indices : IntRange
|
||||
}
|
||||
{jet}
|
||||
|
||||
To create an array one can call its [constructor|Classes and Inheritance#Classes and Primary constructors] providing the array size and a [function|Function literals] that knows how to initialize elements of the array:
|
||||
{jet}
|
||||
val asc = Array<Int>(5, {i -> i * i}) // Creates an array [0, 1, 2, 3, 4]
|
||||
{jet}
|
||||
Or, alternatively, one can use a library function {{array()}} and pass the item values to it, so that {{array(1, 2, 3)}} creates an array {{\[1, 2, 3\]}}.
|
||||
|
||||
As we said above, the {{\[\]}} operation stands for calls to member functions {{get()}} and {{set()}}. When compiling to JVM byte codes, the compiler optimizes access to arrays so that there's no overhead introduced, and all operations work exactly like in *Java*:
|
||||
{jet}
|
||||
val array = array(1, 2, 3, 4)
|
||||
array[x] = array[x] * 2 // no actual calls to get() and set() generated
|
||||
for (x in array) // no iterator created
|
||||
print(x)
|
||||
{jet}
|
||||
Even when we navigate with an index, it does not introduce any overhead:
|
||||
{jet}
|
||||
for (i in array.indices) // no iterator created
|
||||
array[i] += 2
|
||||
{jet}
|
||||
Finally, *in*\-checks have no overhead either
|
||||
{jet}
|
||||
if (i in array.indices) { // same as (i >= 0 && i < array.size)
|
||||
print(array[i])
|
||||
}
|
||||
{jet}
|
||||
|
||||
*Note*: arrays are [invariant|Java interoperability#Arrays]. For the best performance on the JVM use [specialized array classes|Java interoperability#Arrays].
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Strings]
|
||||
@@ -1,291 +0,0 @@
|
||||
h1. Classes and Primary constructors
|
||||
|
||||
Here is an example of a class declaration in [Kotlin]:
|
||||
{jet}
|
||||
class Example(param : Int) {
|
||||
val property = param
|
||||
}
|
||||
{jet}
|
||||
Let's start with the header that says
|
||||
{jet}
|
||||
class Example(param : Int) {
|
||||
{jet}
|
||||
This is a declaration of a class {{Example}} that has a constructor that takes one parameter of type {{Int}}. Such constructors, declared immediately in the class header, are called _primary constructors_.
|
||||
|
||||
To create a new instance of the class {{Example}}, one simply calls its constructor, as if it were a regular function:
|
||||
{jet}
|
||||
val e = Example(10)
|
||||
{jet}
|
||||
(Note that one does not need the *new* keyword.)
|
||||
|
||||
If a class does not have any constructors declared, one cannot instantiate it:
|
||||
{jet}
|
||||
class Some {}
|
||||
|
||||
val s = <error desc="Can't find a function 'Some'. Note that the class Some has no constructor">Some()</error> // Error: no constructor for Some
|
||||
{jet}
|
||||
*Note* that a class with no constructors must not declare any state (properties with backing fields), or inherit from classes that have constructors.
|
||||
|
||||
What does the primary constructor do? It executes the initializers of properties, in the order of declaration. These initializers can use the constructor's parameters. In the example above, the only thing the constructor does is initialization of {{property}}.
|
||||
|
||||
Additionally, one can place "anonymous initializers" in the body of a class, just surrounding pieces of code with curly braces:
|
||||
{jet}
|
||||
class ExampleWithAnonymousInitializer(param : Int) {
|
||||
val property = HashSet<Int>()
|
||||
{
|
||||
property.add(param)
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Here, the primary constructor first creates a new {{HashSet}}, assigns it to {{property}} and then adds the value of {{param}} to this set.
|
||||
|
||||
{anchor:bean-class}
|
||||
Parameters of primary constructors can be prefixed with *val* or *var* keywords to declare corresponding [properties|Properties And Fields] in-place:
|
||||
{jet}
|
||||
class Bean(val prop1 : Int, val prop2 : String)
|
||||
{jet}
|
||||
Class body is optional, and the example above is a complete declaration of a class that has two properties *prop1* and *prop2* and a primary constructor with two parameters, that initializes these properties in an obvious way.
|
||||
|
||||
So, it does not take you much code to declare a bean-style data class in [Kotlin], at least it is a lot less code than in Java.
|
||||
|
||||
h1. Class members
|
||||
|
||||
Classes have the following kinds of members:
|
||||
* [Functions]
|
||||
* [Properties|Properties And Fields]
|
||||
* [Other classes|Nested classes]
|
||||
* [Object declarations|Object expressions and Declarations]
|
||||
|
||||
h1. Inheritance
|
||||
|
||||
All classes in [Kotlin] have a common superclass {{Any}}, that is a default super for a class with no supertypes declared:
|
||||
{jet}
|
||||
class Example // Implicitly inherits from Any
|
||||
{jet}
|
||||
|
||||
{{Any}} is not {{java.lang.Object}}; in particular, it does not have any members, not even {{equals()}}, {{hashCode}} or {{toString()}}. This does not mean that you can not call, say, {{toString()}} on any object: you can, but it will be an [extension function|Extension functions]. See [Java interoperability#Object methods] for more details.
|
||||
|
||||
To declare an explicit supertype, one puts it after a colon in the class header:
|
||||
{jet}
|
||||
open class Base(p : Int)
|
||||
|
||||
class Derived(p : Int) : Base(p)
|
||||
{jet}
|
||||
As you can see, the base type can (and must) be initialized right there, using the parameters of the primary constructor.
|
||||
|
||||
The *open* annotation on a class is the opposite of *Java*'s *final*: it allows others to inherit from this class. By default, all classes in [Kotlin] are *final*, which corresponds to Item 17 of _[Effective Java|http://java.sun.com/docs/books/effective]_: *Design and document for inheritance or else prohibit it*.
|
||||
|
||||
A class may have _many supertypes_. See [*this post*|http://blog.jetbrains.com/kotlin/2011/08/multiple-inheritance-part-2-possible-directions/] for more details.
|
||||
|
||||
h2. Overriding members
|
||||
|
||||
As we mentioned before, we stick to making things explicit in [Kotlin]. And unlike *Java*, [Kotlin] requires explicit annotations for overridable members that we call *open* and for *overrides*:
|
||||
{jet}
|
||||
open class Base {
|
||||
open fun v() {}
|
||||
fun nv() {}
|
||||
}
|
||||
class Derived() : Base {
|
||||
override fun v() {}
|
||||
}
|
||||
{jet}
|
||||
The *override* annotation is required for {{Derived.v()}}. If it were missing, the compiler would complain. If there is no *open* annotation on a function, like {{Base.nv()}}, declaring a method with the same signature in a subclass is illegal, either with *override* or without it. In a *final* class (e.g. a class with no *open* annotation), *open* members are prohibited.
|
||||
|
||||
A member marked *override* is itself _open_, i.e. it may be overridden in subclasses. If you want to prohibit re-overriding, use *final*:
|
||||
{jet}
|
||||
open class AnotherDerived() : Base {
|
||||
final override fun v() {}
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. (!) Wait\! How will I hack my libraries now?\!
|
||||
|
||||
One issue with our approach to overriding (classes and members *final* by default) is that it would be difficult to subclass something inside the libraries you use to override some method that was not intended for overriding by the library designer, and introduce some nasty hack there.
|
||||
|
||||
We think that this is not a disadvantage, for the following reasons:
|
||||
# Best practices say that you should not allow these hacks anyway
|
||||
# People successfully use other languages (C++, C#) that have similar approach
|
||||
# If people really want to hack, there still are ways: in some cases it will be possible to write your hack in Java, and Aspect frameworks always work for these purposes...
|
||||
|
||||
h2. Traits
|
||||
|
||||
_Traits_ are essentially interfaces with (optional) method bodies. See [*this post*|http://blog.jetbrains.com/kotlin/2011/08/multiple-inheritance-part-2-possible-directions/] for more details.
|
||||
|
||||
h2. Overriding rules
|
||||
|
||||
In [Kotlin], implementation inheritance is regulated by the following rule: if a class inherits many _implementations_ of the same member from its immediate superclasses, it must override this member and provide its own implementation (perhaps, using one of the inherited ones). To denote the supertype from which the inherited implementation is taken, we use *this* qualified by the supertype name in angle brackets, e.g. *this{*}{{<Base>}}:
|
||||
{jet}
|
||||
open class A {
|
||||
open fun f() { print("A") }
|
||||
fun a() { print("a") }
|
||||
}
|
||||
|
||||
trait B {
|
||||
open fun f() { print("B") }
|
||||
open fun b() { print("b") }
|
||||
}
|
||||
|
||||
class C() : A(), B {
|
||||
// The compiler requires f() to be overridden:
|
||||
override fun f() {
|
||||
super<A>.f() // call to A.f()
|
||||
super<B>.f() // call to B.f()
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
It's fine to inherit from both {{A}} and {{B}}, and we have no problems with {{a()}} and {{b()}} since {{C}} inherits only _one implementation_ of each of these functions. But for {{f()}} we have _two_ implementations inherited by {{C}}, and this we _have to_ override {{f()}} in {{C}} and provide our own implementation that eliminates the ambiguity.
|
||||
|
||||
h2. Abstract classes
|
||||
|
||||
As in *Java*, a class and some of its members may be declared *abstract*. An *abstract* member does not have an implementation in its class. Thus, when some descendant inherits an abstract member, it does not count as an implementation:
|
||||
{jet}
|
||||
abstract class A {
|
||||
abstract fun f()
|
||||
}
|
||||
|
||||
trait B {
|
||||
open fun f() { print("B") }
|
||||
}
|
||||
|
||||
class C() : A(), B {
|
||||
// We are not required to override f()
|
||||
}
|
||||
{jet}
|
||||
Note that we do not need to annotate an *abstract* class *open* -- it goes without saying. Neither need we annotate an *abstract* function *open*.
|
||||
|
||||
One can *override* a non-abstract *open* member with an *abstract* one:
|
||||
{jet}
|
||||
open class Base {
|
||||
open fun f() {}
|
||||
}
|
||||
|
||||
abstract class Derived : Base {
|
||||
override abstract fun f()
|
||||
}
|
||||
{jet}
|
||||
|
||||
h2. Overridable properties and accessors
|
||||
|
||||
A property may be declared *open* as well as a function. This actually means that _accessors_ of this property can be overridden:
|
||||
{jet}
|
||||
open class Base {
|
||||
open val p : Int
|
||||
get() = 1
|
||||
}
|
||||
class Derived : Base {
|
||||
override val p : Int
|
||||
get() = 2
|
||||
}
|
||||
{jet}
|
||||
|
||||
One can make individual accessors *open* and *override* them one-by-one:
|
||||
{jet}
|
||||
open class Base {
|
||||
var p : Int
|
||||
get() = 1
|
||||
open set(value) { /* do nothing */ }
|
||||
}
|
||||
class Derived : Base {
|
||||
var p : Int
|
||||
/* get is inherited as it was */
|
||||
override set(value) { print(value) }
|
||||
}
|
||||
{jet}
|
||||
|
||||
h1. Delegation
|
||||
|
||||
The [Delegation pattern|http://en.wikipedia.org/wiki/Delegation_pattern] has proven to be a good alternative to implementation inheritance, and [Kotlin] supports it natively requiring zero boilerplate code. A class {{Derived}} can inherit from a trait {{Base}} and delegate all of its public methods to a specified object:
|
||||
{jet}
|
||||
trait Base {
|
||||
fun print()
|
||||
}
|
||||
|
||||
class BaseImpl(val x : Int) : Base {
|
||||
override fun print() { print(x) }
|
||||
}
|
||||
|
||||
class Derived(b : Base) : Base by b
|
||||
|
||||
fun main() {
|
||||
val b = BaseImpl(10)
|
||||
Derived(b).print() // prints 10
|
||||
}
|
||||
{jet}
|
||||
The *by*\-clause in the supertype list for {{Derived}} indicates that {{b}} will be stored internally in objects of {{Derived}} and the compiler will generate all the methods of {{Base}} that forward to {{b}}.
|
||||
|
||||
h1. Generic classes
|
||||
|
||||
See [Generics]
|
||||
|
||||
h1. Class objects
|
||||
|
||||
In [Kotlin], unlike *Java*, classes do not have *static* methods. In most cases, [namespace-level functions|Packages] form a good substitute for them, but there are a few cases when they don't. These cases involve access to class' internals (private members).
|
||||
|
||||
For example, to replace a constructor with a [Factory method|http://en.wikipedia.org/wiki/Factory_method_pattern], one makes the constructor *private* and provides a function that calls the constructor. But if this function in located outside the class in question, it would not have any access to the constructor.
|
||||
|
||||
To address this issue (and to provide some other interesting features), [Kotlin] introduces a concept of a *class object* (the closest analog in other languages would be [Companion objects in *Scala*|http://programming-scala.labs.oreilly.com/ch06.html#CompanionObjects]). Roughly speaking, a *class object* for class {{C}} is an object (in the sense of [Object declaration|Object expressions and Declarations]) that is associated to {{C}}. There may be not more than one class object for each class. A *class object* is declared inside its associated class, and thus it can access its *private* members. A *class object* for {{C}} itself is (usually) not and instance of {{C}}. For example:
|
||||
{jet}
|
||||
class C() {
|
||||
class object {
|
||||
fun create() = C()
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val c = C.create() // C denotes the class object here
|
||||
}
|
||||
{jet}
|
||||
|
||||
At first you may think that this is just a way of grouping static members of a class together instead of mixing them with instance members: in *Java* we access static members of {{C}} by calling {{C.foo()}}, and the same happens with *class object*'s members in [Kotlin]. But in fact there is an important difference: a *class object* can have _supertypes_, and {{C}}, as an expression denotes this object as a value, so one can pass it around, say, as an argument for a function. Let's modify our example to demonstrate this:
|
||||
{jet}
|
||||
abstract class Factory<out T> {
|
||||
fun create() : T
|
||||
}
|
||||
|
||||
open class C() {
|
||||
class object : Factory<C> {
|
||||
override fun create() : C = C()
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val factory = C // C denotes the class object
|
||||
val c = factory.create()
|
||||
}
|
||||
{jet}
|
||||
|
||||
{note:title=Class object bounds are not supported yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1437].{note}
|
||||
|
||||
*Note* that class objects are never inherited:
|
||||
{jet}
|
||||
class D : C()
|
||||
|
||||
val d = <error desc="Class D has no class object">D</error>.create() // Error: no class object for D
|
||||
{jet}
|
||||
|
||||
A description of some more interesting features related to *class objects* can be found in the [Generic constaints|Generics#Class objects] section.
|
||||
|
||||
*Note*: if you think that *class objects* are a great way of implementing singletons in [Kotlin], please see [Object expressions and Declarations].
|
||||
|
||||
h1. Best practices related to this feature
|
||||
|
||||
[Effective Java Second Edition by Joshua Bloch|http://java.sun.com/docs/books/effective/]
|
||||
*Item 16*: Favor composition over inheritance
|
||||
*Item 17*: Design and document for inheritance or else prohibit it
|
||||
*Item 18*: Prefer interfaces to abstract classes
|
||||
|
||||
h1. Similar features in other languages
|
||||
|
||||
IDEs automatically [generate delegating methods|http://www.jetbrains.com/idea/features/code_generation.html#link1].
|
||||
|
||||
[Project Lombok|http://projectlombok.org/features/Delegate.html] implements delegation in *Java* with annotations.
|
||||
|
||||
*Scala* has traits.
|
||||
|
||||
*Groovy* has [Categories and Mixins|http://groovy.codehaus.org/Category+and+Mixin+transformations].
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Enum classes]
|
||||
* [Nested classes]
|
||||
* [Object expressions and Declarations]
|
||||
@@ -1,25 +0,0 @@
|
||||
h1. Kotlin Coding Style
|
||||
|
||||
This page contains the current coding style for the Kotlin language.
|
||||
|
||||
* if in doubt default to the [Java Coding Conventions|http://www.oracle.com/technetwork/java/codeconv-138413.html] such as:
|
||||
** use of camelCase for names (and avoid underscore in names)
|
||||
** types start with upper case
|
||||
** methods and properties start with lower case
|
||||
** use 4 space indentation
|
||||
* public functions should have documentation such that it appears in [Kotlin Doc]
|
||||
* Kotlin does not have fields as a primary concept in the language - it only has properties. Avoid the use of prefixes on properties, such as _ or m\_ or other kinds of notation; If you need access to a backing field of a property, use the $ prefix: $foo to refer to a field behind property foo; never create a private property and call it \_foo
|
||||
|
||||
h3. Colon
|
||||
|
||||
There is a space before colon where colon separates type and supertype and there's no color where color separates instance and type:
|
||||
|
||||
{code}
|
||||
trait Foo : Bar {
|
||||
fun foo(a: Int): String
|
||||
}
|
||||
{code}
|
||||
|
||||
h4. See also
|
||||
|
||||
[Kotlin Doc]
|
||||
@@ -1,49 +0,0 @@
|
||||
This document provides a quick comparison of [Kotlin] to *Java*.
|
||||
|
||||
h3. Fixes
|
||||
|
||||
Safety problems in *Java* that are fixed in [Kotlin]:
|
||||
* Null references are controlled by the type system, i.e. [Kotlin] has [no {{NPE}}'s|Null-safety]
|
||||
* Full type information is [retained at runtime|Generics#Reified generics], i.e. better reflection/safer instanceof-checks
|
||||
* [No raw types|Java interoperability#Java generics in Up]
|
||||
* Arrays in [Kotlin] are [invariant|Basic types#Arrays]
|
||||
|
||||
Usability problems in *Java* that are fixed in [Kotlin]:
|
||||
* [Kotlin] has [higher-order functions|Functions#Higher-order functions], aka closures
|
||||
** And with [inlining|Functions#Inline functions] they are cheap
|
||||
* [Use-site variance without wildcards|Generics#Type projections]
|
||||
* [Declaration-site variance|Generics#Declaration-site variance]
|
||||
* [Kotlin] has [no checked exceptions|Exceptions]
|
||||
|
||||
h3. What Java has and [Kotlin] has not
|
||||
|
||||
* [Checked exceptions|Exceptions]
|
||||
* [Primitive types|Basic types] that are not objects
|
||||
* [Static members|Classes and Inheritance#Class objects]
|
||||
* [Non-private fields|Properties And Fields]
|
||||
* [Type erasure|Java interoperability#Java generics in Up]
|
||||
* [Wildcard-types|Generics#Variance]
|
||||
|
||||
h3. What [Kotlin] has and Java has not
|
||||
|
||||
* [Function literals] + [Inline functions|Functions#Inline functions] = performant custom control structures
|
||||
* [Null-safety]
|
||||
* [Smart casts|Type casts]
|
||||
* [String templates|Strings#Templates]
|
||||
* [Properties|Properties And Fields]
|
||||
* [Primary constructors|Classes and Inheritance#Primary constructors]
|
||||
* [Mixins and First-class delegation|Classes and Inheritance#Inheritance]
|
||||
* [Extension functions]
|
||||
* [Type inference for variable and property types|Basic syntax walk-through#Define a local variable]
|
||||
* [Singletons|Object expressions and Declarations]
|
||||
* [Declaration-site variance & Type projections|Generics#Variance]
|
||||
* [Modules|Modules and Compilation]
|
||||
* [Range expressions|Ranges]
|
||||
* [Pattern matching]
|
||||
* [Generic types retained at runtime|Generics#Reified generics]
|
||||
* [Operator overloading]
|
||||
* [Class objects|Generics#Class objects]
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Comparison to Scala]
|
||||
@@ -1,47 +0,0 @@
|
||||
Two of the [main design goals|Welcome#Design goals] for [Kotlin] are
|
||||
* make *compilation* at least as fast as *Java* and,
|
||||
* keeping the useful level of expressiveness (see above), make it as simple as possible.
|
||||
|
||||
{info:title:Note}
|
||||
If you are happy with *Scala*, you probably don't need [Kotlin].
|
||||
{info}
|
||||
|
||||
h3. What Scala has that [Kotlin] has not
|
||||
|
||||
* Implicit conversions, parameters, etc
|
||||
** In *Scala*, sometimes it's very hard to tell what's happening in your code without using a debugger, because too many implicits get into the picture
|
||||
** To enrich your types with functions in [Kotlin] use [Extension functions].
|
||||
* Overridable type members
|
||||
* Path-dependent types
|
||||
* Existential types
|
||||
** [Type projections|Generics#Type projections] are a very special case
|
||||
* Complicated logic for initialization of traits
|
||||
** See [Classes and Inheritance]
|
||||
* Custom symbolic operations
|
||||
** See [Operator overloading]
|
||||
* Built-in XML
|
||||
** See [Type-safe Groovy-style builders]
|
||||
|
||||
Things that may be added to [Kotlin] later:
|
||||
* Higher kinds
|
||||
* Structural types
|
||||
* Yield operator
|
||||
* Actors
|
||||
* Parallel collections
|
||||
* .NET target
|
||||
|
||||
h3. What [Kotlin] has that Scala has not
|
||||
* [Zero-overhead null-safety|Null-safety]
|
||||
** *Scala* has {{Option}}, which is a syntactic and run-time wrapper
|
||||
* [Smart casts|Type casts]
|
||||
* Static [extension functions|Extension functions]
|
||||
** Instead of wrapping at runtime (with Scala 2.10, implicit value classes will fix the runtime overhead problem)
|
||||
* [Kotlin]'s [Inline functions|Functions#Inline functions] facilitate [Nonlocal jumps|Returns and jumps#custom]
|
||||
* [String templates|Strings#Templates].
|
||||
** This feature will be supported in Scala 2.10
|
||||
* [First-class delegation|Classes and Inheritance#Delegation]. Also implemented via 3rd party plugin: [Autoproxy|https://github.com/kevinwright/Autoproxy-Lite]
|
||||
* [Modules|Modules and Compilation]
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Modules and Compilation]
|
||||
@@ -1,86 +0,0 @@
|
||||
h1. Welcome to [Kotlin] documentation page\!
|
||||
|
||||
*Disclaimer*: this is not a language specification. Neither is it a complete reference manual. These documents are written to give you an impression of what kind of language [Kotlin] is. Some of the examples are somewhat speculative as the implementation of the compiler and library is currently in progress. Most of the details presented here are subject to change. *Your feedback and suggestions are very welcome.* You can write comments or file an issue in the [issue tracker|http://youtrack.jetbrains.net/issues/KT].
|
||||
|
||||
h3. Introductory Video
|
||||
|
||||
For an introduction, check out the presentation [*slides* and *video* from StrangeLoop 2011|http://www.infoq.com/presentations/The-Kotlin-Programming-Language].
|
||||
More presentations are available on the [Talks and Publications] page.
|
||||
|
||||
h3. What is [Kotlin]?
|
||||
|
||||
"Project [Kotlin]" is the codename for a *statically-typed JVM-targeted programming language* developed by [*JetBrains*|http://jetbrains.com] and intended *for industrial use*.
|
||||
|
||||
h3. Why a new language?
|
||||
|
||||
At [JetBrains|http://jetbrains.com], we’ve been developing for the *Java* platform for a long time, and we know how good it is. On the other hand, we know that the *Java* programming language has certain limitations and problems that are either impossible or very hard to fix due to backward-compatibility issues. We know that *Java* is going to stand long, but we believe that the community can benefit from a new statically typed JVM-targeted language free of the legacy trouble and having the features so desperately wanted by the developers.
|
||||
|
||||
{anchor:Design goals}
|
||||
The main *design goals* behind this project are
|
||||
* to create a [*Java-compatible* language|Java interoperability],
|
||||
* that *compiles* at least *as fast as Java*,
|
||||
* make it *safer* than Java, i.e. statically check for common pitfalls such as [null pointer dereference|Null-safety],
|
||||
* make it *more concise* than *Java* by supporting [variable type inference|Basic syntax walk-through#Define a local variable], [higher-order functions|Functions#Higher-order functions] (closures), [extension functions|Extension functions], [code in interfaces and first-class delegation|Classes and Inheritance], etc;
|
||||
* and, keeping the useful level of expressiveness (see above), make it as *simple* as possible.
|
||||
|
||||
See more [here|http://blog.jetbrains.com/kotlin/2011/08/02/why-jetbrains-needs-kotlin/].
|
||||
|
||||
h3. What does it look like?
|
||||
|
||||
{jet}
|
||||
fun main(args : Array<String>) {
|
||||
println("Hello, world!")
|
||||
}
|
||||
{jet}
|
||||
See more [here|Hello, world!] and below.
|
||||
|
||||
h3. Development status
|
||||
|
||||
The compiler is being developed alongside with an [IntelliJ IDEA|http://www.jetbrains.com/idea/] integration.
|
||||
[Kotlin] is an [Open Source project|http://github.com/jetbrains/kotlin]. Distributed under Apache 2 License.
|
||||
|
||||
{note:title=Kotlin is Under Development}Please report bugs to our [Issue Tracker|http://youtrack.jetbrains.com/issues/KT]{note}
|
||||
|
||||
If you're interested in keeping track of the project status, you're welcome to subscribe to the [Kotlin blog|http://blog.jetbrains.com/kotlin] or to [follow us on Twitter|http://twitter.com/project_kotlin].
|
||||
|
||||
h3. Read more
|
||||
|
||||
*FAQ*. See [this page|FAQ] for the answers to the most common questions.
|
||||
|
||||
API Documentation for the *Standard Library* can be found [here|http://jetbrains.github.com/kotlin/apidoc/stdlib/].
|
||||
API Documentation for the *Runtime* can be found [here|http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/].
|
||||
|
||||
Check out some *[Examples]* to get an idea of what [Kotlin] is:
|
||||
* [Hello, world!]
|
||||
* [Basic syntax walk-through|Basic syntax walk-through]
|
||||
* [Address book] --- collections and higher-order functions
|
||||
* [HTML builder|Type-safe Groovy-style builders] --- declarative structures
|
||||
* [More...|Examples] --- extensions, pattern matching, IO, operator overloading, etc.
|
||||
|
||||
If you are a *Java* developer, look here:
|
||||
* [Comparison to Java], and
|
||||
* [Java interoperability]
|
||||
|
||||
If you got interested, take the *Feature tour*:
|
||||
* [Modules and Compilation]
|
||||
* [Packages]
|
||||
* [Functions]
|
||||
** [Operator overloading]
|
||||
** [Extension functions]
|
||||
** [Function literals]
|
||||
** [Type-safe Groovy-style builders|Type-safe Groovy-style builders]
|
||||
* [Properties And Fields]
|
||||
* [Basic types]
|
||||
** [Strings]
|
||||
* [Expressions]
|
||||
{children:page=Expressions|depth=5}
|
||||
* [Pattern matching]
|
||||
* [Classes and Inheritance]
|
||||
{children:page=Classes and inheritance|depth=5}
|
||||
* [Generics]
|
||||
** [Runtime Type Information]
|
||||
* [Null-safety|Null-safety]
|
||||
* [Exceptions]
|
||||
* [Java interoperability]
|
||||
|
||||
Check out the *[Grammar]* for a formal syntax description.
|
||||
@@ -1 +0,0 @@
|
||||
{children}
|
||||
@@ -1,71 +0,0 @@
|
||||
Exceptions in [Kotlin] are not very different from any other language. the main difference from *Java* is that there're no checked exceptions in [Kotlin], you can find out the motivation for this [below|#why].
|
||||
|
||||
h3. Exception classes
|
||||
|
||||
All exception classes in [Kotlin] are descendants of the class {{Exception}}. Every exception has a message, stack trace and an optional cause.
|
||||
|
||||
To *throw* an exception object, one uses the *throw* expression:
|
||||
{jet}
|
||||
throw MyException("Hi there!")
|
||||
{jet}
|
||||
|
||||
To catch an exception, one uses the *try* expression:
|
||||
{jet}
|
||||
try {
|
||||
// some code
|
||||
}
|
||||
catch (e : SomeException) {
|
||||
// handler
|
||||
}
|
||||
finally {
|
||||
// optional finally block
|
||||
}
|
||||
{jet}
|
||||
As usual, there may be zero or more *catch* blocks, and *finally* may be omitted, but at least one *catch* or *finally* must be present.
|
||||
|
||||
Note that *try* is an _expression_, i.e. it may have a value:
|
||||
{jet}
|
||||
val a : Int? = try { parseInt(input) } catch (e : NumberFormatException) { null }
|
||||
{jet}
|
||||
The "returned" value of *try* expression with no *finally* is either the last expression in the *try* block or the last expression in the *catch* block (or blocks).
|
||||
|
||||
If *finally* block is present, its last expression is the value of *try* expression.
|
||||
|
||||
{anchor:why}
|
||||
h3. Why [Kotlin] has no checked exceptions
|
||||
|
||||
People with *Java* background may wonder why [Kotlin] does not have checked exceptions. There's so much said on this topic, that we just provide a few citations and one example here.
|
||||
|
||||
Our example is {{java.lang.Appendable}} -- an interface from {{JDK}}, implemented by {{StringBuilder}}, that has, among others, the following method declaration:
|
||||
{jet}
|
||||
Appendable append(CharSequence csq) throws IOException;
|
||||
{jet}
|
||||
What does this signature say? It says that _every time_ I append a string to something (a {{StringBuilder}}, some kind of a log, a console, etc) I _have to_ catch those {{IOExceptions}}. Why? Because it _might be_ performing IO ({{Writer}} also implements {{Appendable}})... So it results into this kind of code all over the place:
|
||||
{jet}
|
||||
try {
|
||||
log.append(message);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Must be safe
|
||||
}
|
||||
{jet}
|
||||
And this is no good, see [Effective Java|http://java.sun.com/docs/books/effective] Item 65: *Don't ignore exceptions*.
|
||||
|
||||
h4. Some citations from prior art:
|
||||
|
||||
Bruce Eckel says in [Does Java need Checked Exceptions? |http://www.mindview.net/Etc/Discussions/CheckedExceptions]:
|
||||
{quote}
|
||||
Examination of small programs leads to the conclusion that requiring exception specifications could both enhance developer productivity and enhance code quality, but experience with large software projects suggests a different result -- decreased productivity and little or no increase in code quality.
|
||||
{quote}
|
||||
|
||||
Other citations of this sort:
|
||||
# [Java's checked exceptions were a mistake|http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html] (Rod Waldhoff)
|
||||
# [The Trouble with Checked Exceptions|http://www.artima.com/intv/handcuffs.html] (Anders Hejlsberg]
|
||||
|
||||
h3. Java interoperability
|
||||
|
||||
Some details on *Java* interoperability are available [here|Java interoperability#Checked exceptions].
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Java interoperability]
|
||||
@@ -1,35 +0,0 @@
|
||||
This is a quick overview of expressions in [Kotlin].
|
||||
|
||||
h3. Atomic expressions
|
||||
|
||||
Atomic expressions are
|
||||
* Literal constants (see [Basic types], [Strings])
|
||||
* [Tuple literals|Tuples]
|
||||
* [Variable names or field references|Properties And Fields]
|
||||
* [Object expressions|Object expressions and Declarations]
|
||||
* Parenthesized expression
|
||||
* [Control structures (if, when, try)|Control structures]
|
||||
* [Function literals]
|
||||
* [*this* expressions|This expressions]
|
||||
* [*break*, *continue* or *return*|Returns and jumps]
|
||||
** note that these are _expressions_ that are typed with the type [{{Nothing}}|Returns and jumps#Nothing]
|
||||
|
||||
See the [grammar for atomic expressions|Grammar#atmoicExpression].
|
||||
|
||||
h3. Operators
|
||||
|
||||
The [grammar|Grammar#Expressions] defines a number of operators denoted by symbols. The precedence table is available [here|Grammar#Precedence]. Many of the operators can be [overloaded|Operator overloading], other are described below:
|
||||
* {{.}} -- for member access
|
||||
* {{?.}} and {{?:}} -- for [Null-safety]
|
||||
* {{&&}} and {{||}} -- for incomplete boolean evaluation
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Basic operations]
|
||||
* [Control structures]
|
||||
* [Function literals]
|
||||
* [Returns and jumps]
|
||||
* [Ranges]
|
||||
* [This expressions]
|
||||
* [Tuples]
|
||||
* [Type casts]
|
||||
@@ -1,75 +0,0 @@
|
||||
h3. What is [Kotlin]?
|
||||
|
||||
"Project [Kotlin]" is the codename of a statically-typed JVM-targeted programming language developed by [JetBrains|http://jetbrains.com] intended for industrial use.
|
||||
|
||||
h4. Why a new language?
|
||||
At [JetBrains|http://jetbrains.com], we’ve been developing for the *Java* platform for a long time, and we know how good it is. On the other hand, we know that the *Java* programming language has certain limitations and problems that are either impossible or very hard to fix due to backward-compatibility issues. We know that *Java* is going to stand long, but we believe that the community can benefit from a new statically typed JVM-targeted language free of the legacy trouble and having the features so desperately wanted by the developers.
|
||||
|
||||
{anchor:Design goals}
|
||||
The main design goals behind this project are
|
||||
* to create a *Java-compatible* language,
|
||||
* that *compiles* at least *as fast as Java*,
|
||||
* make it *safer* than Java, i.e. statically check for common pitfalls such as [null pointer dereference|Null-safety],
|
||||
* make it *more concise* than *Java* by supporting [variable type inference|Basic syntax walk-through#Define a local variable], [higher-order functions|Functions#Higher-order functions] (closures), [extension functions|Extension functions], [mixins and first-class delegation|Classes and Inheritance], etc;
|
||||
* and, keeping the useful level of expressiveness (see above), make it way *simpler* than the most mature competitor -- *Scala*.
|
||||
|
||||
See [Comparison to Java] and [Comparison to Scala].
|
||||
|
||||
h4. Is this an open source project? What's the license?
|
||||
|
||||
Both the compiler and the IntelliJ IDEA plugin are open source under the Apache 2 license. We're happy to accept [contributions|Kontributions].
|
||||
|
||||
h4. Is it Java-compatible?
|
||||
|
||||
Yes. The compiler emits *Java* byte-code. [Kotlin] can call *Java*, and *Java* can call [Kotlin]. See [Java interoperability].
|
||||
|
||||
h4. Other platforms than Java?
|
||||
|
||||
We have started a JavaScript back-end recently. There are external Kontributors willing to work on an LLVM back-end.
|
||||
|
||||
{anchor:Eclipse}
|
||||
h4. Eclipse-based IDE?
|
||||
|
||||
We plan to provide two things:
|
||||
1) An open source Eclipse plugin that will be initially contributed by JetBrains, and later we will gradually move it's support onto the community.
|
||||
2) API exposed by the compiler, to make it easy to retrieve semantic information from within the plugin.
|
||||
|
||||
In any case, Eclipse support will be released later that IntelliJ support.
|
||||
|
||||
h4. Is this a functional language? Is this an object-oriented language?
|
||||
|
||||
This is an object-oriented language. It supports [higher-order functions|Functions#Higher-order functions] and [function literals|Function literals], but that does not make it a functional language. It targets OO-developers.
|
||||
|
||||
h4. What about generics?
|
||||
[Kotlin] has [generics|Generics]. They are [retained at runtime|Generics#Reified generics], support [declaration-site variance|Generics#Declarations-site variance] and [usage-site variance|Generics#Type projections], and [Kotlin] does not have any wildcard types.
|
||||
|
||||
h4. Does it have type inference? Is it a good idea?
|
||||
[Kotlin] infers type arguments when generic functions are called, as well as types of variables from their initializers. This makes the code more concise.
|
||||
|
||||
h4. Does it have semicolons, curly braces, etc?
|
||||
|
||||
Semicolons are [optional|Grammar#Semicolons]. Curly braces are there. Types of [variables|Basic syntax walk-through] and [functions|Functions] are written on the right after a colon (like *Scala*, and unlike *C*-style languages).
|
||||
|
||||
h4. Why types on the right?
|
||||
|
||||
We believe that it makes the code more readable. Besides, it enables some nice syntactic features, for example, it's easy to leave type annotations out, and *Scala* has proven pretty well that this is not really a problem.
|
||||
|
||||
h4. Is this language extensible?
|
||||
|
||||
We are planning to make it extensible in a few ways: from [inline functions|Functions#Inline functions] to annotations, type loaders and language-quotations.
|
||||
|
||||
h4. Can I embed my DSL into this language?
|
||||
|
||||
Yes, [Kotlin] provides a few features that help here: [Operator overloading], [Custom control structures via inline functions|Functions#Inline functions], [Infix function calls|Functions#infix function calls], [Extension functions], annotations, language-quotations.
|
||||
|
||||
h4. Does it have IDE support?
|
||||
|
||||
Yes. The compiler is developed as an [IntelliJ IDEA|http://jetbrains.com/idea] plugin, and user-facing IDE features are there from the very beginning (we make good use of them while debugging and testing).
|
||||
|
||||
h4. Where to ask more questions?
|
||||
|
||||
Join our [*Forum*|http://devnet.jetbrains.net/community/kotlin].
|
||||
|
||||
h3. What to read next
|
||||
|
||||
* [Hello, world!]
|
||||
@@ -1,350 +0,0 @@
|
||||
Functions in [Kotlin] are declared with the *fun* keyword:
|
||||
{jet}
|
||||
fun double(x : Int) : Int {
|
||||
return x * 2
|
||||
}
|
||||
{jet}
|
||||
|
||||
A function call goes in the traditional way:
|
||||
{jet}
|
||||
val two = demo(1)
|
||||
{jet}
|
||||
|
||||
See also [Infix calls|#Infix calls] and [Operator overloading].
|
||||
|
||||
h3. Single-expression functions
|
||||
|
||||
If a function just returns a value of a single expression, one can specify its body after '{{=}}' and with no *return* statement:
|
||||
{jet}
|
||||
fun double(x : Int) : Int = x * 2
|
||||
{jet}
|
||||
|
||||
In this case, it is allowed to omit the return type annotation, and the type will be inferred from the expression on the right-hand side:
|
||||
{jet}
|
||||
fun double(x : Int) = x * 2
|
||||
{jet}
|
||||
|
||||
{anchor:Unit}
|
||||
|
||||
h3. {{Unit}}\-returning functions
|
||||
|
||||
If a function does not return any useful value, its return type is {{Unit}}. {{Unit}} is a type of [tuples|Tuples] of zero components, its an alias for {{Tuple0}}. It has only one value -- a tuple of zero components, that is written {{()}}. This value does not have to be returned explicitly:
|
||||
{jet}
|
||||
fun printHello(name : String?) : Unit {
|
||||
if (name != null)
|
||||
print("Hello, $name!")
|
||||
else
|
||||
print("Hi there!")
|
||||
// We don't need to write 'return ()' or 'return', although we could
|
||||
}
|
||||
{jet}
|
||||
|
||||
Neither has the {{Unit}} return type to be specified explicitly:
|
||||
If a function has a block body (in curly braces, not after '{{=}}') and returns {{Unit}}, one can omit the return type annotation:
|
||||
{jet}
|
||||
fun printHello(name : String?) {
|
||||
//...
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. Local functions
|
||||
|
||||
[Kotlin] supports _local functions_, i.e. one can define a function inside a function:
|
||||
{jet}
|
||||
fun dfs(graph : Graph){
|
||||
fun dfs(current : Vertex, visited : Set<Vertex>) {
|
||||
if (!visited.add(current)) return
|
||||
for (v in current.neighbors)
|
||||
dfs(v, visited)
|
||||
}
|
||||
|
||||
dfs(graph.vertices[0], HashSet())
|
||||
}
|
||||
{jet}
|
||||
|
||||
Local functions can "see" local variables of outer functions (i.e. the closure), so we can have our {{visited}} set as a local variable, not a parameter to always pass around:
|
||||
{jet}
|
||||
fun dfs(graph : Graph){
|
||||
val visited = HashSet<Vertex>()
|
||||
fun dfs(current : Vertex) {
|
||||
if (!visited.add(current)) return
|
||||
for (v in current.neighbors)
|
||||
dfs(v)
|
||||
}
|
||||
|
||||
dfs(graph.vertices[0])
|
||||
}
|
||||
{jet}
|
||||
|
||||
Local functions can even *return* from outer functions using [qualified *return* expressions|Returns and jumps]:
|
||||
{jet}
|
||||
fun reachable(from : Vertex, to : Vertex) : Boolean {
|
||||
val visited = HashSet<Vertex>()
|
||||
fun dfs(current : Vertex) {
|
||||
// here we return from the outer function:
|
||||
if (current == to) return@reachable true
|
||||
// And here -- from local function:
|
||||
if (!visited.add(current)) return
|
||||
for (v in current.neighbors)
|
||||
dfs(v)
|
||||
}
|
||||
|
||||
dfs(from)
|
||||
return false // if dfs() did not return true already
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. Member functions
|
||||
|
||||
A _member function_ is a function defined inside a class:
|
||||
{jet}
|
||||
class Sample() {
|
||||
fun foo() { print("foo") }
|
||||
}
|
||||
{jet}
|
||||
|
||||
Member functions are called with a dot:
|
||||
{jet}
|
||||
Sample().foo() // creates a new object of Sample and calls foo() on it
|
||||
{jet}
|
||||
See [Classes and Inheritance].
|
||||
|
||||
h3. Generic functions
|
||||
|
||||
Functions may have generic parameters which can be specified in angle brackets after the function name and before the value parameters:
|
||||
{jet}
|
||||
fun singletonArray<T>(item : T) : Array<T> {
|
||||
val result = Array<T>(1)
|
||||
result[0] = item
|
||||
return result
|
||||
}
|
||||
{jet}
|
||||
More on generic functions can be found on the page dedicated to [generics|Generics#Generic functions].
|
||||
|
||||
h3. Varargs
|
||||
|
||||
The last argument of a function may be marked with *vararg* annotation:
|
||||
{jet}
|
||||
fun asList<T>(<style desc="font-weight:bold; display:inline":>vararg ts : T) : List<T> {
|
||||
val result = ArrayList<T>
|
||||
for (t in ts) // ts is an Array
|
||||
result.add(t)
|
||||
return result
|
||||
}
|
||||
{jet}
|
||||
|
||||
By default, *vararg* creates an array, but this behavior can be customized by providing arguments to the annotation:
|
||||
{jet}
|
||||
fun asList<T>(<style desc="font-weight:bold; display:inline":>vararg<ArrayList<T>> ts : T) : List<T> = ts // ts is a List now!
|
||||
{jet}
|
||||
The type argument to the *vararg* annotation denotes a _builder_ type. A call to this function is compiled like this:
|
||||
{jet}
|
||||
asList(0, 1, 2)
|
||||
// Compiles to
|
||||
val list = ArrayList<Int>(3) // 3 is the size of the structure
|
||||
list.add(0)
|
||||
list.add(1)
|
||||
list.add(2)
|
||||
asList(list.build()) // For ArrayList, build() just returns the list itself
|
||||
{jet}
|
||||
So, the *vararg* builder must be a type that has
|
||||
* A constructor that takes one {{Int}} parameter
|
||||
* An {{add()}} function
|
||||
* A {{build()}} function
|
||||
The type of the *vararg* parameter if the returned type of {{build()}}.
|
||||
|
||||
h3. Default arguments
|
||||
|
||||
Function parameters may have _default values_, which are used when a corresponding argument is omitted. This allows to reduce the number of overloads, compared to *Java*:
|
||||
{jet}
|
||||
// In java.io.InputStream this function has two versions:
|
||||
fun read(b : Array<Byte>, off : Int = 0, len : Int = -1) {
|
||||
val actualLength = if (len == -1) b.length else len
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
This function may be called in three forms:
|
||||
{jet}
|
||||
read(b, off, len)
|
||||
read(b, off) // len = -1, effectively, b.length
|
||||
read(b) // off = 0, len = -1
|
||||
{jet}
|
||||
|
||||
h3. Named arguments
|
||||
|
||||
When a function has many parameters (and many of them have defaults), it is very convenient to see parameter names at the call site. Consider the following function in:
|
||||
{jet}
|
||||
fun reformat(
|
||||
str : String,
|
||||
normalizeCase : Boolean = true,
|
||||
uppercaseFirstLetter : Boolean = true,
|
||||
divideByCamelHumps : Boolean = false,
|
||||
wordSeparator : Character = ' '
|
||||
) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
The best-case call site is fine:
|
||||
{jet}
|
||||
reformat(str)
|
||||
{jet}
|
||||
But what if we want to change the word separator without changing the flags?
|
||||
{jet}
|
||||
reformat(str, true, true, false, '_')
|
||||
{jet}
|
||||
Without named arguments, a call site is hard to read. To document it, we can provide parameter names for each argument:
|
||||
{jet}
|
||||
reformat(str,
|
||||
normalizeCase = true,
|
||||
uppercaseFirstLetter = true,
|
||||
divideByCamelHumps = false,
|
||||
wordSeparator = '_'
|
||||
)
|
||||
{jet}
|
||||
It is better already, but we can improve it: there's no need to specify all the arguments if some of the default values are fine for us:
|
||||
{jet}
|
||||
reformat(str, wordSeparator = '_')
|
||||
{jet}
|
||||
|
||||
h3. Infix calls
|
||||
|
||||
If a member function (or an [extension function|Extension functions]) takes one parameter, it may be called in _infix form_, i.e. without a dot after receiver and parentheses around the arguments:
|
||||
{jet}
|
||||
1 shl 2
|
||||
// is the same as
|
||||
1.shl(2)
|
||||
{jet}
|
||||
An infix call _must_ have two parameters. One is not allowed to say, e.g. {{print 1}}, because there's nothing on the left of {{print}}.
|
||||
|
||||
Infix calls associate to the left, i.e. {{1 foo 2 bar 3}} means {{(1 foo 2) bar 3}}.
|
||||
|
||||
For precedence, see [the grammar|Grammar#Precedence].
|
||||
|
||||
h3. Extension functions
|
||||
|
||||
[Extension functions] allow us to define a function having some type as a receiver:
|
||||
{jet}
|
||||
fun Int.abs() : Boolean = if (this >= 0) this else -this
|
||||
{jet}
|
||||
This function can be called on any {{Int}} with a dot, as if it were a member function:
|
||||
{jet}
|
||||
print(-1.abs())
|
||||
{jet}
|
||||
|
||||
For more details, see [Extension functions].
|
||||
|
||||
h3. Higher-order functions
|
||||
|
||||
A _higher-order function_ is a function that takes functions as parameters, or returns a function. A good example of such a function is {{lock()}} that takes a lock object and a function, acquires the lock, runs the functions and releases the lock:
|
||||
{anchor:lock}
|
||||
{jet}
|
||||
fun lock<T>(lock : Lock, body : () -> T) : T {
|
||||
lock.lock()
|
||||
try {
|
||||
return body()
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
Let's examine the code above: {{body}} has a [_function type_|Function literals#Function types]: {{() -> T}}, so it's supposed to be a function that takes no parameters and returns a value of type {{T}}. It is invoked inside the *try* block, while protected by the lock, and its result is returned by the {{lock()}} function.
|
||||
|
||||
If we want to call {{lock()}}, we can pass a [_function literal_|Function literals] to it as an argument:
|
||||
{jet}
|
||||
val result = lock(lock, { sharedResource.operation() })
|
||||
{jet}
|
||||
Function literals are described in details [on this page|Function literals]. Here we only give a superficial description:
|
||||
* a function literal is always surrounded by curly braces,
|
||||
* its parameters (if any) are declared before {{->}} (parameter types may be omitted),
|
||||
* the body goes after {{->}}.
|
||||
In our case, there are no parameters, and the expression in the curly braces is the function literal body.
|
||||
|
||||
There is a convention in [Kotlin] that makes our example look nicer:
|
||||
* if the _last_ parameter of a function is itself a function, the corresponding _function literal_ may be passed outside the parentheses:
|
||||
{jet}
|
||||
lock (lock) {
|
||||
sharedResource.operation()
|
||||
}
|
||||
{jet}
|
||||
This makes our code look more like a 'control structure'.
|
||||
|
||||
Another example of a higher order function would be {{map()}} (of Map/Reduce):
|
||||
{jet}
|
||||
fun <T, R> List<T>.map(transform : (T) -> R) : List<R> {
|
||||
val result = ArrayList<R>()
|
||||
for (item in this)
|
||||
result.add(transform(item))
|
||||
return result
|
||||
}
|
||||
{jet}
|
||||
This function can be called as follows:
|
||||
{jet}
|
||||
val doubled = ints.map {it -> it * 2}
|
||||
{jet}
|
||||
One other convention helps us here:
|
||||
* if a function literal has only one parameter, its declaration may be omitted (along with the {{->}}) and its name will be {{it}}:
|
||||
{jet}
|
||||
ints map {it * 2} // Infix call + Implicit 'it'
|
||||
{jet}
|
||||
|
||||
These conventions allow us to write [LINQ|http://msdn.microsoft.com/en-us/library/bb308959.aspx]\-like expressions:
|
||||
{jet}
|
||||
strings filter {it.length == 5} sortby {it} map {it.toUpperCase()}
|
||||
{jet}
|
||||
|
||||
h4. Extension function literals
|
||||
|
||||
Like named extension functions, function literals may declare _receiver parameters_. This allows us to write things like [Groovy-style builders|http://groovy.codehaus.org/Builders] in a type-safe way.
|
||||
|
||||
Learn more [here|Function literals#Extensions] and [here|Type-safe Groovy-style builders].
|
||||
|
||||
h3. Inline functions
|
||||
|
||||
Using higher-order functions imposes certain runtime penalties: each function is an object, and it captures a _closure_, i.e. those variables that are accessed in the body of the function. Memory allocations (both for function objects and classes) and virtual calls introduce runtime overhead.
|
||||
|
||||
But it appears that in many cases this kind of overhead can be eliminated by _inlining_ the function literals. The functions shown above are good examples of this situation. I.e., the [{{lock()}}|#lock] function could be easily inlined at call-sites. Consider the following case:
|
||||
{jet}
|
||||
lock(l) {foo()}
|
||||
{jet}
|
||||
Instead of creating a function object for the parameter and generating a call, the compiler could emit the following code:
|
||||
{jet}
|
||||
lock.lock()
|
||||
try {
|
||||
foo()
|
||||
}
|
||||
finally {
|
||||
lock.unlock()
|
||||
}
|
||||
{jet}
|
||||
Isn't it what we wanted from the very beginning?
|
||||
|
||||
To make the compiler do this, one needs to annotate the {{lock()}} function with the *inline* annotation:
|
||||
{jet}
|
||||
inline fun lock<T>(lock : Lock, body : () -> T) : T {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
Inlining may cause the generated code to grow, but if we do it in a reasonable way (do not inline big functions) it will pay off in performance, especially at "megamorphic" call-sites inside loops.
|
||||
|
||||
{note:title=Inline functions are not implemented yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1434].{note}
|
||||
|
||||
h3. Returning many things from a function
|
||||
|
||||
Sometimes we need to return several things from a function. Some languages support this through [*out*\-parameters|http://msdn.microsoft.com/en-us/library/aa645764(v=vs.71).aspx], and some -- through _tuples_. We follow the latter way.
|
||||
|
||||
Tuples are described in detail on [this page|Tuples]. Here we just give an example:
|
||||
{jet}
|
||||
fun splitEmail(email : String) : #(username : String, host : String) {
|
||||
return #(email.substringUntil("@"), email.substringAfter("@"))
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Operator overloading]
|
||||
* [Extension functions]
|
||||
* [Function literals]
|
||||
* [Type-safe Groovy-style builders]
|
||||
@@ -1,281 +0,0 @@
|
||||
h1. Generic classes
|
||||
|
||||
As in *Java*, classes in [Kotlin] may have _type parameters_:
|
||||
{jet}
|
||||
class Box<T>(t : T) {
|
||||
var value = t
|
||||
}
|
||||
{jet}
|
||||
In general, to create an instance of such a class, one needs to provide the type parameters:
|
||||
{jet}
|
||||
val box : Box<Int> = Box<Int>(1)
|
||||
{jet}
|
||||
But if the parameters may be inferred, e.g. from the constructor arguments or by some other means, one is allowed to omit the type parameters:
|
||||
{jet}
|
||||
val box = Box(1) // 1 has type Int, so the compiler figures out that we are talking about Box<Int>
|
||||
{jet}
|
||||
|
||||
{anchor:Reified generics}
|
||||
h2. Generic types are retained at runtime
|
||||
|
||||
Unlike *Java*, the information about actual type arguments of [Kotlin] classes is retained at runtime. This allows for checking complete types of objects at runtime:
|
||||
{jet}
|
||||
if (b is Box<Int>) { // 'is' replaces Java's 'instanceof'
|
||||
// b is guaranteed to be Box<Int>, not just Box
|
||||
}
|
||||
{jet}
|
||||
We can even use type variables in *is*\-checks:
|
||||
{jet}
|
||||
if (foo is T) { // this is a non-trivial check
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
Also, we can create generic arrays:
|
||||
{jet}
|
||||
class ArrayDemo<T> {
|
||||
val array = Array<T>() // Array is just a class
|
||||
}
|
||||
{jet}
|
||||
|
||||
And no, [Kotlin] does NOT have _raw types_, and _type erasure_ does not play that much of a role. For example, there can not be a values of type {{Box}}, without type arguments, if {{Box}} is a generic class. This corresponds to [Effective Java|http://java.sun.com/docs/books/effective/] Item 23: *Don't use raw types in new code* and Item 24: *Eliminate unchecked warnings*.
|
||||
|
||||
{note:title=Run-time generics are not implemented yet}{note}
|
||||
|
||||
h2. Variance
|
||||
|
||||
One of the most tricky parts of *Java*'s type system is _wildcard types_ (see [Java Generics FAQ|http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html]). And [Kotlin] doesn't have any. Instead, it has two other things: declaration-site variance and type projections.
|
||||
|
||||
First, let's think about why *Java* needs those mysterious wildcards. The problem is explained in [Effective Java|http://java.sun.com/docs/books/effective/], [Item 28: *Use bounded wildcards to increase API flexibility*|http://java.sun.com/docs/books/effective/generics.pdf]. First, generic types in *Java* are _invariant_, meaning that {{List<String>}} is _not_ a subtype of {{List<Object>}}. Why so? If {{List}} was not _invariant_, it would have been no better than *Java*'s arrays, cause the following code would have compiled and cause an exception at runtime:
|
||||
{code}
|
||||
// Java
|
||||
List<String> strs = new ArrayList<String>();
|
||||
List<Object> objs = strs; // !!! The cause of the upcoming problem sits here. Java prohibits this!
|
||||
objs.add(1); // Here we put an Integer into a list of Strings
|
||||
String s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String
|
||||
{code}
|
||||
So, *Java* prohibits such things in order to guarantee run-time safety. But this has some implications. For example, consider the {{addAll()}} method from {{Collection}} interface. What's the signature of this method? Intuitively, we'd put it this way:
|
||||
{code}
|
||||
// Java
|
||||
interface Collection<E> ... {
|
||||
void addAll(Collection<E> items);
|
||||
}
|
||||
{code}
|
||||
But then, we would not be able to do the following simple thing (which is perfectly safe):
|
||||
{code}
|
||||
// Java
|
||||
void copyAll(Collection<Object> to, Collection<String> from) {
|
||||
to.addAll(from); // !!! Would not compile with the naive declaration of addAll:
|
||||
// Collection<String> is not a subtype of Collection<Object>
|
||||
}
|
||||
{code}
|
||||
(In *Java*, we learned this lesson the hard way, see [Effective Java|http://java.sun.com/docs/books/effective/]'s [Item 25: *Prefer lists to arrays*|http://java.sun.com/docs/books/effective/generics.pdf].)
|
||||
|
||||
That's why the actual signature of {{addAll()}} is the following:
|
||||
{code}
|
||||
// Java
|
||||
interface Collection<E> ... {
|
||||
void addAll(Collection<? extends E> items);
|
||||
}
|
||||
{code}
|
||||
The _wildcard type argument_ {{? extends T}} indicates that this method accepts a collection of objects of _some subtype of_ {{{_}T{_}}}, not {{T}} itself. This means that we can safely _read_ {{T}}'s from {{items}} (elements of this collection are instances of a subclass of T), but _cannot write_ to it since we do not know what objects comply to that unknown subtype of {{T}}. In return for this limitation, we have the desired behaviour: {{Collection<String>}} _is_ a subtype of {{Collection<? extends Object>}}. In "clever words", the wildcard with an *extends*\-bound (_upper_ bound) makes the type _covariant_.
|
||||
|
||||
The key to understanding why this trick works is rather simple: if you can only _take_ items from a collection, then a collection of {{String}}'s and reading {{Object}}'s from it is fine. Conversely, if you can only _put_ items into the collection, it's OK to take a collection of {{Object}}'s and put {{String}}'s into it: in *Java* we have {{List<? super String>}} a _supertype_ of {{List<Object>}}. The latter is called _contravariance_, and you can only call methods that take {{String}} as an argument on {{List<? super String>}} (e.g., you can call {{add(String)}} or {{set(int, String)}}), while if you call something that returns {{T}} in {{List<T>}}, you don't get a {{String}}, but an {{Object}}.
|
||||
|
||||
Joshua Bloch calls those objects you only _read_ from *producers*, and those you only _write_ to -- *consumers*. He recommends: "*For maximum flexibility, use wildcard types on input parameters that represent producers or consumers*", and proposes the following mnemonic:
|
||||
|
||||
*PECS stands for producer-extends, consumer-super.*
|
||||
|
||||
*NOTE*: if you use a producer-object, say, {{List<? extends Foo>}}, you are not allowed to call {{add()}} or {{set()}} on this object, but this does not mean that this object is _immutable_: for example, nothing prevents you to call {{clear()}} to remove all items from the list, since {{clear()}} does not take any parameters at all. The only thing guaranteed by wildcards (or other types of variance) is _type safety_. Immutability is a completely different story.
|
||||
|
||||
h3. Declaration-site variance
|
||||
|
||||
Suppose we have a generic interface {{Source<T>}} that does not have any methods that take {{T}} as a parameter, only methods that return T:
|
||||
{code}
|
||||
// Java
|
||||
interface Source<T> {
|
||||
T nextT();
|
||||
}
|
||||
{code}
|
||||
Then, it would be perfectly safe to store a reference to an instance of {{Source<String>}} in a variable of type {{Source<Object>}} -- there're no consumer-methods to call. But Java does not know this, and still prohibits:
|
||||
{code}
|
||||
// Java
|
||||
void demo(Source<String> strs) {
|
||||
Source<Object> objects = strs; // !!! Not allowed in Java
|
||||
// ...
|
||||
}
|
||||
{code}
|
||||
To fix this, we have to declare {{objects}} of type {{Source<? extends Object>}} that is sort of meaningless, because we can call all the same methods on such a variable, as before, so there's no value added by the more complex type. But the compiler does not know that.
|
||||
|
||||
In [Kotlin], there is a way to explain this sort of thing to the compiler. This is called _declaration-site variance_: we can annotate the _type parameter_ {{T}} of {{Source}} to make sure that it is only _returned_ (produced) from members of {{Source<T>}}, and never consumed. To do this we provide the *out* modifier:
|
||||
{jet}
|
||||
abstract class Source<out T> {
|
||||
fun nextT() : T
|
||||
}
|
||||
|
||||
fun demo(strs : Source<String>) {
|
||||
val objects : Source<Any> = strs // This is OK, since T is an out-parameter
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
The general rule is: when a type parameter {{T}} of a class {{C}} is declared *out*, it may occur only in *out*\-position in the members of {{C}}, but in return {{C<Base>}} can safely be a supertype of {{C<Derived>}}.
|
||||
|
||||
In "clever words" they say that the class {{C}} is _covariant_ in the parameter {{T}}, or that {{T}} is a _covariant_ type parameter. You can think of {{C}} as being a _producer_ of {{T}}'s, and NOT a _consumer_ of {{T}}'s.
|
||||
|
||||
The *out* modifier is called a _variance annotation_, and since it is provided at the type parameter declaration site, we talk about _declaration-site variance_. This is in contrast with *Java*'s _use-site variance_ where wildcards in the type usages make the types covariant.
|
||||
|
||||
In addition to *out*, [Kotlin] provides a complementary variance annotation: *in*. It makes a type parameter _contravariant_: it can only be consumed and never produced. A good example of a contravariant class is {{Comparable}}:
|
||||
{jet}
|
||||
abstract class Comparable<in T> {
|
||||
fun compareTo(other : T) : Int
|
||||
}
|
||||
|
||||
fun demo(x : Comparable<Number>) {
|
||||
x.compareTo(1.0) // 1.0 has type Double, which is a subtype of Number
|
||||
// Thus, we can assign x to a variable of type Comparable<Double>
|
||||
val y : Comparable<Double> = x // OK!
|
||||
}
|
||||
{jet}
|
||||
|
||||
We believe that the word *in* and *out* are self-explainig (as they were successfully used in C# for quite some time already), thus the mnemonic mentioned above is not really needed, and one can rephrase it for a higher purpose:
|
||||
|
||||
*The* *[Existential|http://en.wikipedia.org/wiki/Existentialism]* *Transformation: Consumer in, Producer out\!* :-)
|
||||
|
||||
{anchor:Type projections}
|
||||
|
||||
h3. Use-site variance: Type projections
|
||||
|
||||
It is very convenient to declare a type parameter {{T}} as *out* and have no trouble with subtyping on the use site. Yes, it is, when the class in question _can_ actually be restricted to only return {{T}}'s, but what if it can't? A good example of this is {{Array}}:
|
||||
{jet}
|
||||
class Array<T>(val length : Int) {
|
||||
fun get(index : Int) : T { /* ... */ }
|
||||
fun set(index : Int, value : T) { /* ... */ }
|
||||
}
|
||||
{jet}
|
||||
This class cannot be either co\- or contravariant in {{T}}. And this imposes certain inflexibilities. Consider the following function:
|
||||
{jet}
|
||||
fun copy(from : Array<Any>, to : Array<Any>) {
|
||||
assert {from.length == to.length}
|
||||
for (i in from.indices)
|
||||
to[i] = from[i]
|
||||
}
|
||||
{jet}
|
||||
This function is supposed to copy item from one array to another. Let's try to apply it in practice:
|
||||
{jet}
|
||||
val ints : Array<Int> = array(1, 2, 3)
|
||||
val any = Array<Any>(3)
|
||||
copy<error desc="The arguments (Array<int>, Array<Any>) do not match the signature 'copy(Array<Any>, Array<Any>)'">(ints, any)</error> // Error: expects (Array<Any>, Array<Any>)
|
||||
{jet}
|
||||
Here we run into the same familiar problem: {{Array<T>}} is _invariant_ in {{T}}, thus neither of {{Array<Int>}} and {{Array<Any>}} is a subtype of the other. Why? Again, because {{copy}} _might_ be doing bad things, i.e. it might attempt to _write_, say, a {{String}} to {{from}}, and if we actually passed an array of {{Int}} there, a {{ClassCastException}} would have been thrown sometime later...
|
||||
Then, the only thing we want to ensure is that {{copy()}} does not do any bad things. We want to prohibit it to _write_ to {{from}}, and we can:
|
||||
{jet}
|
||||
fun copy(from : Array<out Any>, to : Array<Any>) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
What has happened here is called _type projection_: we said that {{from}} is not simply an array, but a restricted (_projected_) one: we can only call those methods that return the type parameter {{T}}, in this case it means that we can only call {{get()}}. This is our approach to _use-site variance_, and corresponds to *Java*'s {{Array<? extends Object>}}, but in a little simpler way.
|
||||
|
||||
You can project a type with *in* as well:
|
||||
{jet}
|
||||
fun fill(dest : Array<in String>, value : String) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
{{Array<in String>}} corresponds to Java's {{Array<? super String>}}, i.e. you can pass an array of {{CharSequence}} or an array of {{Object}} to the {{fill()}} function.
|
||||
|
||||
h4. Star-projections
|
||||
|
||||
Sometimes you want to say that you know nothing about the type argument, but still want to use it in a safe way. The safe way here is to say that we are dealing with an *out*\-projection (the object does not consume any values of unknown types), and that this projection is with the upper-bound of the corresponding parameter, i.e. *out* {{Any?}} for most cases. [Kotlin] provides a shortahnd syntax for this, that we call a _star-projection_: {{Foo<*>}} means {{Foo<out Bar>}} where {{Bar}} is the upperbound for {{Foo}}'s type parameter.
|
||||
|
||||
*Note*: star-projections are very much like *Java*'s raw types, but safe.
|
||||
|
||||
h1. Generic functions
|
||||
|
||||
Not only classes can have type parameters. Functions can, too. Usually, one places the type parameters in angle brackets _after_ the name of the function:
|
||||
{jet}
|
||||
fun singletonList<T>(item : T) : List<T> {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
But for [Extension functions] it may be necessary to declare type parameters before specifying the receiver type, so [Kotlin] allows the alternative syntax:
|
||||
{jet}
|
||||
fun <T> T.basicToString() : String {
|
||||
return typeinfo.typeinfo(this) + "@" + System.identityHashCode(this)
|
||||
}
|
||||
{jet}
|
||||
|
||||
If type parameters are passed explicitly at the call site, they can be only specified _after_ the name of the function:
|
||||
{jet}
|
||||
val l = singletonList<Int>(1)
|
||||
{jet}
|
||||
|
||||
h1. Generic constraints
|
||||
|
||||
The set of all possible types that can be substituted for a given type parameter may be restricted by _generic constraints_.
|
||||
|
||||
h2. Upper bounds
|
||||
|
||||
The most common type a constraint is an _upper bound_ that corresponds to *Java*'s *extends* keyword:
|
||||
{jet}
|
||||
fun sort<T : Comparable<T>>(list : List<T>) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
The type specified after a colon is the _upper bound_: only subtype of {{Comparable<T>}} may be substituted for {{T}}. For example
|
||||
{jet}
|
||||
sort(list(1, 2, 3)) // OK. Int is a subtype of Comparable<Int>
|
||||
sort<error desc="Argument type mismatch">(list(HashMap<Int, String>()))</error> // Error: HashMap<Int, String> is not a subtype of Comparable<HashMap<Int, String>>
|
||||
{jet}
|
||||
|
||||
The default upper bound (if none specified) is {{Any?}}. There can be not more than one upper bound specified directly inside the angle brackets. If same type parameter needs more than one upper bound, we need a separate *where*\-clause:
|
||||
{jet}
|
||||
fun cloneWhenGreater<T : Comparable<T>>(list : List<T>, threshold : T) : List<T>
|
||||
where T : Cloneable {
|
||||
return list when {it > threshold} map {it.clone()}
|
||||
}
|
||||
{jet}
|
||||
|
||||
h2. Class objects
|
||||
|
||||
Another type of generic constraints are *class object* constraints. They restrict the properties of a [class object|Classes and Inheritance#Class objects] of the root class of a type being substituted for {{T}}.
|
||||
|
||||
Consider the following example. Suppose, we have a class {{Default}} that has a property {{default}} that holds a _default_ value to be used for this type:
|
||||
{jet}
|
||||
abstract class Default<T> {
|
||||
val default : T
|
||||
}
|
||||
{jet}
|
||||
For example, the class {{Int}} could extend {{Default}} in the following way:
|
||||
{jet}
|
||||
class Int {
|
||||
class object : Default<Int> {
|
||||
override val default = 0
|
||||
}
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
Now, let's consider a function that takes a list of [nullable|Null-safety] {{T}}'s, i.e. {{T?}}, and replaces all the {{null}}'s with the default values:
|
||||
{jet}
|
||||
fun replaceNullsWithDefaults<T : Any>(list : List<T?>) : List<T> {
|
||||
return list map {
|
||||
if (it == null)
|
||||
<error desc="The type T does not have a class object">T</error>.default // For now, we don't know if T's class object has such a property
|
||||
else it
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
For this function to compile, we need to specify a type constraint that requires a *class object* of {{T}} to be of a subtype of {{Default<T>}}:
|
||||
{jet}
|
||||
fun replaceNullsWithDefaults<T : Any>(list : List<T?>) : List<T>
|
||||
where class object T : Default<T> {
|
||||
// ...
|
||||
{jet}
|
||||
Now the compiler knows that {{T}} (as a *class object* reference) has the *default* property, and we can access it. This is possible because the generic types in [Kotlin] are [retained at runtime|#Reified generics].
|
||||
|
||||
{note:title=Class object bounds are not supported yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-1437].{note}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Runtime Type Information]
|
||||
@@ -1,68 +0,0 @@
|
||||
h2. Setting up IntelliJ IDEA
|
||||
|
||||
First, you need to install IntelliJ IDEA 11.1 or higher (the free Community Edition can be downloaded from [here|http://www.jetbrains.com/idea/]).
|
||||
Once you've installed that, you'll need the Kotlin IDEA Plugin.
|
||||
|
||||
h3. Milestone versions
|
||||
|
||||
A stable milestone version of Kotlin can be obtained from JetBrains' [Plugin Repository|http://www.jetbrains.com/idea/plugins/index.html].
|
||||
|
||||
In IDEA navigate to: Settings \-> Plugins \-> Browse Repositories
|
||||
|
||||
Select the Kotlin plugin and then Download and Install.
|
||||
|
||||
h3. Using the Kotlin integration builds repository
|
||||
|
||||
In IDEA navigate to: Preferences \-> Plugins \-> Browse Repositories. Enter
|
||||
|
||||
* [http://www.jetbrains.com/kotlin/eap-plugin-repository/updatePlugins.xml]
|
||||
|
||||
Then you should be able to select the Kotlin plugin and Download and Install. The repository above contains reasonable stable builds published approximately every week.
|
||||
|
||||
{note:title=If you want to retrieve nightly builds through a plugin repository, use}[https://teamcity.jetbrains.com/guestAuth/repository/download/bt345/.lastSuccessful/updatePlugins.xml]{note}
|
||||
|
||||
h3. Download the Kotlin plugin manually
|
||||
|
||||
Alternatively, you can download the nightly builds of the IDEA Plugin from [our build server|https://teamcity.jetbrains.com/viewType.html?tab=buildTypeStatusDiv&buildTypeId=bt345&guest=1], look under "Artifacts".
|
||||
|
||||
Then navigate to Preferences \-> Plugins \-> Install plugin from disk...
|
||||
|
||||
h2. Creating a project
|
||||
|
||||
* Now in IDEA you can select File \-> New Project.
|
||||
* Create a new project as usual with a src directory.
|
||||
* Right click on src and select New \-> Kotlin file
|
||||
* Enter some name, say 'Foo'
|
||||
* The IDE will prompt you at the top right of your editor to select the Kotlin Runtime
|
||||
* You'll need to point the IDE to some download of the Kotlin runtime (see below)
|
||||
* Enter some code like this
|
||||
|
||||
{jet}
|
||||
fun main(args: Array<String>): Unit {
|
||||
println("Hello world!")
|
||||
}
|
||||
{jet}
|
||||
|
||||
* Now thats done you should be able to right click on the Foo class and select Run
|
||||
* Enjoy\!
|
||||
|
||||
h2. Working with the Kotlin project at github
|
||||
|
||||
Please note that the [root project at github|https://github.com/JetBrains/kotlin] is a Java based project for creating the compiler and IDEA plugin. It *should not* be opened in IDEA with the Kotlin plugin installed\!
|
||||
|
||||
However the [kotlin libraries project|https://github.com/JetBrains/kotlin/tree/master/libraries] is all Kotlin code and used to create the standard library, tests and associated tools. That project opens fine in IDEA with Kotlin plugin installed. You just may have to specify which KotlinRuntime to choose.
|
||||
|
||||
h2. Downloading the Kotlin Runtime
|
||||
|
||||
The IDEA plugin already includes a Kotlin runtime. If you want to use Kotlin yourself from the command line or Ant you may need this too (unless you use other build tools like the [Kotlin Maven Plugin|Kotlin Build Tools#Maven]).
|
||||
|
||||
Download it from the [build server|https://teamcity.jetbrains.com/viewType.html?tab=buildTypeStatusDiv&buildTypeId=bt345&guest=1], look under "Artifacts".
|
||||
|
||||
h2. Common Issues
|
||||
|
||||
Sometimes you open a Kotlin file and things go all red. This may mean that the IDEA plugin cannot find your Kotlin Runtime.
|
||||
|
||||
* Go to File \-> Project Structure...
|
||||
* Select Libraries tab
|
||||
* Do you see KotlinRuntime? Is it pointing to a valid kotlin-runtime.jar?
|
||||
* If not remove it and add a new one
|
||||
@@ -1,927 +0,0 @@
|
||||
h1. Contents
|
||||
{toc:style=disc|indent=20px}
|
||||
h1. Notation
|
||||
|
||||
This section informally explains the grammar notation used below.
|
||||
|
||||
h2. Symbols and naming
|
||||
|
||||
_Terminal symbol_ names start with an uppercase letter, e.g. *SimpleName*
|
||||
_Nonterminal symbol_ names start with lowercase letter, e.g. *kotlinFile*
|
||||
Each _production_ starts with a colon (*:*)
|
||||
_Symbol definitions_ may have many productions and are terminated by a semicolon (*;*)
|
||||
Symbol definitions may be prepended with _attributes_, e.g. {{start}} attribute denotes a start symbol
|
||||
|
||||
h2. EBNF expressions
|
||||
|
||||
Operator {color:blue}*|*{color} denotes _alternative_
|
||||
Operator {color:blue}*\**{color} denotes _iteration_ (zero or more)
|
||||
Operator {color:blue}*+*{color} denotes _iteration_ (one or more)
|
||||
Operator {color:blue}*?*{color} denotes _option_ (zero or one)
|
||||
alpha{color:blue}*{*{color}beta{color:blue}*}*{color} denotes a nonempty _beta_-separated list of _alpha_'s
|
||||
|
||||
h1. Semicolons
|
||||
|
||||
[Kotlin] provides "semicolon inference": syntactically, subsentences (e.g., statements, declarations etc) are separated by
|
||||
the pseudo-token [SEMI|#SEMI], which stands for "semicolon or newline". In most cases, there's no need for semicolons in
|
||||
[Kotlin] code.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
h1. Syntax
|
||||
|
||||
*Relevant pages:* [Namespaces]
|
||||
|
||||
|
||||
|
||||
{{start}}
|
||||
{anchor:kotlinFile}*kotlinFile*
|
||||
{color:blue}*:*{color} [#preamble] [#toplevelObject]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{{start}}
|
||||
{anchor:script}*script*
|
||||
{color:blue}*:*{color} [#preamble] [#expression]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:preamble}\[{color:grey}Used by [#script], [#kotlinFile]{color}\]
|
||||
*preamble*
|
||||
{color:blue}*:*{color} [#packageHeader]{color:blue}*?*{color} [#import]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:packageHeader}\[{color:grey}Used by [#preamble]{color}\]
|
||||
*packageHeader*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"package"}}*{color} [#SimpleName]{color:blue}*\{*{color}{color:green}*{{"."}}*{color}{color:blue}*\}*{color} [#SEMI]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:import}\[{color:grey}Used by [#preamble], [#package]{color}\]
|
||||
*import*
|
||||
{color:blue}*:*{color} {color:green}*{{"import"}}*{color} {color:blue}*\(*{color}{color:green}*{{"package"}}*{color} {color:green}*{{"."}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#SimpleName]{color:blue}*\{*{color}{color:green}*{{"."}}*{color}{color:blue}*\}*{color} {color:blue}*\(*{color}{color:green}*{{"."}}*{color} {color:green}*{{"\*"}}*{color} {color:blue}*|*{color} {color:green}*{{"as"}}*{color} [#SimpleName]{color:blue}*\)*{color}{color:blue}*?*{color} [#SEMI]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
|
||||
bq. See [Imports|Namespaces#Imports]
|
||||
|
||||
|
||||
{anchor:toplevelObject}\[{color:grey}Used by [#package], [#kotlinFile]{color}\]
|
||||
*toplevelObject*
|
||||
{color:blue}*:*{color} [#package]
|
||||
{color:blue}*:*{color} [#class]
|
||||
{color:blue}*:*{color} [#object]
|
||||
{color:blue}*:*{color} [#function]
|
||||
{color:blue}*:*{color} [#property]
|
||||
{color:blue}*:*{color} [#typedef]
|
||||
;
|
||||
|
||||
{anchor:package}\[{color:grey}Used by [#toplevelObject]{color}\]
|
||||
*package*
|
||||
{color:blue}*:*{color} {color:green}*{{"package"}}*{color} [#SimpleName]{color:blue}*\{*{color}{color:green}*{{"."}}*{color}{color:blue}*\}*{color} {color:green}*{{"\{"}}*{color}
|
||||
[#import]{color:blue}*\**{color}
|
||||
[#toplevelObject]{color:blue}*\**{color}
|
||||
{color:green}*{{"}"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
bq. See [Namespaces]
|
||||
|
||||
|
||||
{{undocumented}}
|
||||
{anchor:typedef}\[{color:grey}Used by [#memberDeclaration], [#declaration], [#toplevelObject]{color}\]
|
||||
*typedef*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"type"}}*{color} [#SimpleName] {color:blue}*\(*{color}[#typeParameters] [#typeConstraints]{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{"="}}*{color} [#type]
|
||||
;
|
||||
|
||||
|
||||
h2. Classes
|
||||
|
||||
bq. See [Classes and Inheritance]
|
||||
|
||||
|
||||
|
||||
|
||||
{anchor:class}\[{color:grey}Used by [#memberDeclaration], [#declaration], [#toplevelObject]{color}\]
|
||||
*class*
|
||||
{color:blue}*:*{color} [#modifiers] {color:blue}*\(*{color}{color:green}*{{"class"}}*{color} {color:blue}*|*{color} {color:green}*{{"trait"}}*{color}{color:blue}*\)*{color} [#SimpleName]
|
||||
[#typeParameters]{color:blue}*?*{color}
|
||||
[#modifiers] {color:blue}*\(*{color}{color:green}*{{"("}}*{color} [#functionParameter]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{")"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
{color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#annotations] [#delegationSpecifier]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
[#typeConstraints]
|
||||
{color:blue}*\(*{color}[#classBody]{color:blue}*?*{color} {color:blue}*|*{color} [#enumClassBody]{color:blue}*\)*{color}
|
||||
;
|
||||
|
||||
|
||||
{anchor:classBody}\[{color:grey}Used by [#objectLiteral], [#enumEntry], [#class], [#object]{color}\]
|
||||
*classBody*
|
||||
{color:blue}*:*{color} {color:blue}*\(*{color}{color:green}*{{"\{"}}*{color} [#memberDeclaration] {color:green}*{{"}"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:delegationSpecifier}\[{color:grey}Used by [#objectLiteral], [#class], [#object]{color}\]
|
||||
*delegationSpecifier*
|
||||
{color:blue}*:*{color} [#constructorInvocation]
|
||||
{color:blue}*:*{color} [#explicitDelegation]
|
||||
;
|
||||
|
||||
{anchor:explicitDelegation}\[{color:grey}Used by [#delegationSpecifier]{color}\]
|
||||
*explicitDelegation*
|
||||
{color:blue}*:*{color} [#userType] {color:green}*{{"by"}}*{color} [#expression]
|
||||
;
|
||||
|
||||
{anchor:typeParameters}\[{color:grey}Used by [#enumEntry], [#class], [#property], [#typedef], [#function]{color}\]
|
||||
*typeParameters*
|
||||
{color:blue}*:*{color} {color:green}*{{"<"}}*{color} [#typeParameter]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{">"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:typeParameter}\[{color:grey}Used by [#typeParameters]{color}\]
|
||||
*typeParameter*
|
||||
{color:blue}*:*{color} [#modifiers] [#SimpleName] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#userType]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
|
||||
bq. See [Generic classes|Generics#Generic classes]
|
||||
|
||||
|
||||
{anchor:typeConstraints}\[{color:grey}Used by [#enumEntry], [#class], [#property], [#typedef], [#function]{color}\]
|
||||
*typeConstraints*
|
||||
{color:blue}*:*{color} {color:blue}*\(*{color}{color:green}*{{"where"}}*{color} [#typeConstraint]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:typeConstraint}\[{color:grey}Used by [#typeConstraints]{color}\]
|
||||
*typeConstraint*
|
||||
{color:blue}*:*{color} [#annotations] [#SimpleName] {color:green}*{{":"}}*{color} [#type]
|
||||
{color:blue}*:*{color} [#annotations] {color:green}*{{"class"}}*{color} {color:green}*{{"object"}}*{color} [#SimpleName] {color:green}*{{":"}}*{color} [#type]
|
||||
;
|
||||
|
||||
bq. See [Generic constraints|Generics#Generic constraints]
|
||||
|
||||
|
||||
|
||||
h3. Class members
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{anchor:memberDeclaration}\[{color:grey}Used by [#classBody]{color}\]
|
||||
*memberDeclaration*
|
||||
{color:blue}*:*{color} [#classObject]
|
||||
{color:blue}*:*{color} [#object]
|
||||
{color:blue}*:*{color} [#constructor]
|
||||
{color:blue}*:*{color} [#function]
|
||||
{color:blue}*:*{color} [#property]
|
||||
{color:blue}*:*{color} [#class]
|
||||
{color:blue}*:*{color} [#typedef]
|
||||
{color:blue}*:*{color} [#anonymousInitializer]
|
||||
;
|
||||
|
||||
{anchor:anonymousInitializer}\[{color:grey}Used by [#memberDeclaration]{color}\]
|
||||
*anonymousInitializer*
|
||||
{color:blue}*:*{color} [#block]
|
||||
;
|
||||
|
||||
{anchor:classObject}\[{color:grey}Used by [#memberDeclaration]{color}\]
|
||||
*classObject*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"class"}}*{color} [#object]
|
||||
;
|
||||
|
||||
bq. See [Class objects|Classes and Inheritance#Class objects]
|
||||
|
||||
|
||||
{{undocumented}}
|
||||
{anchor:constructor}\[{color:grey}Used by [#memberDeclaration]{color}\]
|
||||
*constructor*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"this"}}*{color} [#valueParameters] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#initializer]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color} [#block]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:valueParameters}\[{color:grey}Used by [#enumEntry], [#function], [#constructor]{color}\]
|
||||
*valueParameters*
|
||||
{color:blue}*:*{color} {color:green}*{{"("}}*{color} [#functionParameter]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*?*{color} {color:green}*{{")"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:functionParameter}\[{color:grey}Used by [#valueParameters], [#class]{color}\]
|
||||
*functionParameter*
|
||||
{color:blue}*:*{color} [#modifiers] {color:blue}*\(*{color}{color:green}*{{"val"}}*{color} {color:blue}*|*{color} {color:green}*{{"var"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#parameter] {color:blue}*\(*{color}{color:green}*{{"="}}*{color} [#expression]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:initializer}\[{color:grey}Used by [#enumEntry], [#constructor]{color}\]
|
||||
*initializer*
|
||||
{color:blue}*:*{color} [#annotations] {color:green}*{{"this"}}*{color} [#valueArguments]
|
||||
{color:blue}*:*{color} [#annotations] [#constructorInvocation]
|
||||
;
|
||||
|
||||
{anchor:block}\[{color:grey}Used by [#catchBlock], [#anonymousInitializer], [#functionBody], [#try], [#finallyBlock], [#constructor]{color}\]
|
||||
*block*
|
||||
{color:blue}*:*{color} {color:green}*{{"\{"}}*{color} [#statements] {color:green}*{{"}"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:function}\[{color:grey}Used by [#memberDeclaration], [#declaration], [#toplevelObject]{color}\]
|
||||
*function*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"fun"}}*{color} [#typeParameters]{color:blue}*?*{color}
|
||||
{color:blue}*\(*{color}[#type] {color:green}*{{"."}}*{color} {color:blue}*|*{color} [#annotations]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
[#SimpleName]
|
||||
[#typeParameters]{color:blue}*?*{color} [#valueParameters] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#type]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
[#typeConstraints]
|
||||
[#functionBody]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:functionBody}\[{color:grey}Used by [#getter], [#setter], [#function]{color}\]
|
||||
*functionBody*
|
||||
{color:blue}*:*{color} [#block]
|
||||
{color:blue}*:*{color} {color:green}*{{"="}}*{color} [#expression]
|
||||
;
|
||||
|
||||
{anchor:property}\[{color:grey}Used by [#memberDeclaration], [#declaration], [#toplevelObject]{color}\]
|
||||
*property*
|
||||
{color:blue}*:*{color} [#modifiers] {color:blue}*\(*{color}{color:green}*{{"val"}}*{color} {color:blue}*|*{color} {color:green}*{{"var"}}*{color}{color:blue}*\)*{color}
|
||||
[#typeParameters]{color:blue}*?*{color} {color:blue}*\(*{color}[#type] {color:green}*{{"."}}*{color} {color:blue}*|*{color} [#annotations]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
[#SimpleName] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#type]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
[#typeConstraints]
|
||||
{color:blue}*\(*{color}{color:green}*{{"="}}*{color} [#expression] [#SEMI]{color:blue}*?*{color}{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
{color:blue}*\(*{color}[#getter]{color:blue}*?*{color} [#setter]{color:blue}*?*{color} {color:blue}*|*{color} [#setter]{color:blue}*?*{color} [#getter]{color:blue}*?*{color}{color:blue}*\)*{color} [#SEMI]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
bq. See [Properties and Fields]
|
||||
|
||||
|
||||
{anchor:getter}\[{color:grey}Used by [#property]{color}\]
|
||||
*getter*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"get"}}*{color}
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"get"}}*{color} {color:green}*{{"("}}*{color} {color:green}*{{")"}}*{color} {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#type]{color:blue}*\)*{color}{color:blue}*?*{color} [#functionBody]
|
||||
;
|
||||
|
||||
{anchor:setter}\[{color:grey}Used by [#property]{color}\]
|
||||
*setter*
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"set"}}*{color}
|
||||
{color:blue}*:*{color} [#modifiers] {color:green}*{{"set"}}*{color} {color:green}*{{"("}}*{color} [#modifiers] {color:blue}*\(*{color}[#SimpleName] {color:blue}*|*{color} [#parameter]{color:blue}*\)*{color} {color:green}*{{")"}}*{color} [#functionBody]
|
||||
;
|
||||
|
||||
{anchor:parameter}\[{color:grey}Used by [#functionType], [#tupleType], [#setter], [#functionParameter]{color}\]
|
||||
*parameter*
|
||||
{color:blue}*:*{color} [#SimpleName] {color:green}*{{":"}}*{color} [#type]
|
||||
;
|
||||
|
||||
{anchor:object}\[{color:grey}Used by [#memberDeclaration], [#declaration], [#toplevelObject], [#classObject]{color}\]
|
||||
*object*
|
||||
{color:blue}*:*{color} {color:green}*{{"object"}}*{color} [#SimpleName] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#delegationSpecifier]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#classBody]{color:blue}*?*{color}
|
||||
|
||||
bq. See [Object expressions and Declarations]
|
||||
|
||||
|
||||
|
||||
|
||||
h3. Enum classes
|
||||
|
||||
bq. See [Enum classes]
|
||||
|
||||
|
||||
{anchor:enumClassBody}\[{color:grey}Used by [#class]{color}\]
|
||||
*enumClassBody*
|
||||
{color:blue}*:*{color} {color:green}*{{"\{"}}*{color} [#enumEntry]{color:blue}*\**{color} {color:green}*{{"}"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:enumEntry}\[{color:grey}Used by [#enumClassBody]{color}\]
|
||||
*enumEntry*
|
||||
{color:blue}*:*{color} [#modifiers] [#SimpleName] [#typeParameters]{color:blue}*?*{color} [#valueParameters]{color:blue}*?*{color} {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#initializer]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#typeConstraints] [#classBody]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
|
||||
|
||||
h2. Types
|
||||
|
||||
bq. See [Types]
|
||||
|
||||
|
||||
|
||||
|
||||
{anchor:type}\[{color:grey}Used by [#simpleUserType], [#decomposerPattern], [#getter], [#tupleType], [#for], [#atomicExpression], [#property], [#typeArguments], [#typedef], [#function], [#functionLiteral], [#parameter], [#pattern], [#functionType], [#binding], [#typeConstraint]{color}\]
|
||||
*type*
|
||||
{color:blue}*:*{color} [#annotations] [#typeDescriptor]
|
||||
|
||||
|
||||
{anchor:typeDescriptor}\[{color:grey}Used by [#nullableType], [#typeDescriptor], [#type]{color}\]
|
||||
*typeDescriptor*
|
||||
{color:blue}*:*{color} {color:green}*{{"("}}*{color} [#typeDescriptor] {color:green}*{{")"}}*{color}
|
||||
{color:blue}*:*{color} [#selfType]
|
||||
{color:blue}*:*{color} [#functionType]
|
||||
{color:blue}*:*{color} [#userType]
|
||||
{color:blue}*:*{color} [#tupleType]
|
||||
{color:blue}*:*{color} [#nullableType]
|
||||
;
|
||||
|
||||
{anchor:nullableType}\[{color:grey}Used by [#typeDescriptor]{color}\]
|
||||
*nullableType*
|
||||
{color:blue}*:*{color} [#typeDescriptor] {color:green}*{{"?"}}*{color}
|
||||
|
||||
{anchor:selfType}\[{color:grey}Used by [#typeDescriptor]{color}\]
|
||||
*selfType*
|
||||
{color:blue}*:*{color} {color:green}*{{"This"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:userType}\[{color:grey}Used by [#typeParameter], [#catchBlock], [#typeDescriptor], [#constructorInvocation], [#explicitDelegation]{color}\]
|
||||
*userType*
|
||||
{color:blue}*:*{color} {color:blue}*\(*{color}{color:green}*{{"namespace"}}*{color} {color:green}*{{"."}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#simpleUserType]{color:blue}*\{*{color}{color:green}*{{"."}}*{color}{color:blue}*\}*{color}
|
||||
;
|
||||
|
||||
{anchor:simpleUserType}\[{color:grey}Used by [#userType]{color}\]
|
||||
*simpleUserType*
|
||||
{color:blue}*:*{color} [#SimpleName] {color:blue}*\(*{color}{color:green}*{{"<"}}*{color} {color:blue}*\(*{color}[#optionalProjection] [#type] {color:blue}*|*{color} {color:green}*{{"\*"}}*{color}{color:blue}*\)*{color}{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{">"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:optionalProjection}\[{color:grey}Used by [#simpleUserType]{color}\]
|
||||
*optionalProjection*
|
||||
{color:blue}*:*{color} [#varianceAnnotation]
|
||||
;
|
||||
|
||||
{anchor:functionType}\[{color:grey}Used by [#typeDescriptor]{color}\]
|
||||
*functionType*
|
||||
{color:blue}*:*{color} {color:blue}*\(*{color}[#type] {color:green}*{{"."}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{"("}}*{color} {color:blue}*\(*{color}[#parameter] {color:blue}*|*{color} [#modifiers] [#type]{color:blue}*\)*{color}{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{")"}}*{color} {color:green}*{{"->"}}*{color} [#type]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:tupleType}\[{color:grey}Used by [#typeDescriptor]{color}\]
|
||||
*tupleType*
|
||||
{color:blue}*:*{color} {color:green}*{{"#"}}*{color} {color:green}*{{"("}}*{color} [#type]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*?*{color} {color:green}*{{")"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"#"}}*{color} {color:green}*{{"("}}*{color} [#parameter]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{")"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
h2. Control structures
|
||||
|
||||
bq. See [Control structures]
|
||||
|
||||
|
||||
{anchor:if}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*if*
|
||||
{color:blue}*:*{color} {color:green}*{{"if"}}*{color} {color:green}*{{"("}}*{color} [#expression] {color:green}*{{")"}}*{color} [#expression] [#SEMI]{color:blue}*?*{color} {color:blue}*\(*{color}{color:green}*{{"else"}}*{color} [#expression]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:try}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*try*
|
||||
{color:blue}*:*{color} {color:green}*{{"try"}}*{color} [#block] [#catchBlock]{color:blue}*\**{color} [#finallyBlock]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:catchBlock}\[{color:grey}Used by [#try]{color}\]
|
||||
*catchBlock*
|
||||
{color:blue}*:*{color} {color:green}*{{"catch"}}*{color} {color:green}*{{"("}}*{color} [#annotations] [#SimpleName] {color:green}*{{":"}}*{color} [#userType] {color:green}*{{")"}}*{color} [#block]
|
||||
;
|
||||
|
||||
{anchor:finallyBlock}\[{color:grey}Used by [#try]{color}\]
|
||||
*finallyBlock*
|
||||
{color:blue}*:*{color} {color:green}*{{"finally"}}*{color} [#block]
|
||||
;
|
||||
|
||||
{anchor:loop}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*loop*
|
||||
{color:blue}*:*{color} [#for]
|
||||
{color:blue}*:*{color} [#while]
|
||||
{color:blue}*:*{color} [#doWhile]
|
||||
;
|
||||
|
||||
{anchor:for}\[{color:grey}Used by [#loop]{color}\]
|
||||
*for*
|
||||
{color:blue}*:*{color} {color:green}*{{"for"}}*{color} {color:green}*{{"("}}*{color} [#annotations] {color:blue}*\(*{color}{color:green}*{{"val"}}*{color} {color:blue}*|*{color} {color:green}*{{"var"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#SimpleName] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#type]{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{"in"}}*{color} [#expression] {color:green}*{{")"}}*{color} [#expression]
|
||||
;
|
||||
|
||||
{anchor:while}\[{color:grey}Used by [#loop]{color}\]
|
||||
*while*
|
||||
{color:blue}*:*{color} {color:green}*{{"while"}}*{color} {color:green}*{{"("}}*{color} [#expression] {color:green}*{{")"}}*{color} [#expression]
|
||||
;
|
||||
|
||||
{anchor:doWhile}\[{color:grey}Used by [#loop]{color}\]
|
||||
*doWhile*
|
||||
{color:blue}*:*{color} {color:green}*{{"do"}}*{color} [#expression] {color:green}*{{"while"}}*{color} {color:green}*{{"("}}*{color} [#expression] {color:green}*{{")"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
|
||||
h2. Expressions
|
||||
|
||||
bq. See [Expressions]
|
||||
|
||||
h3. Precedence
|
||||
|
||||
||*Precedence*||Title||Symbols||
|
||||
|Highest|Postfix|{{\+\+}}, {{\-\-}}, {{.}}, {{?.}}, {{?}}|
|
||||
| |Prefix|{{-}}, {{\+}}, {{\+\+}}, {{\-\-}}, {{!}}, [{{@label}}|#LabelName], {{@}}, {{@@}} |
|
||||
| |Type RHS|{{:}}, {{as}}, {{as?}} |
|
||||
| |Multiplicative|{{*}}, {{/}}, {{%}} |
|
||||
| |Additive|{{\+}}, {{-}} |
|
||||
| |Range|{{..}} |
|
||||
| |Infix function|[{{SimpleName}}|#SimpleName] |
|
||||
| |Elvis|{{?:}} |
|
||||
| |Named checks|{{in}}, {{\!in}}, {{is}}, {{\!is}} |
|
||||
| |Comparison|{{<}}, {{>}}, {{<=}}, {{>=}} |
|
||||
| |Equality|{{==}}, {{\!==}}|
|
||||
| |Conjunction|{{&&}}|
|
||||
| |Disjunction|{{\|\|}}|
|
||||
|Lowest|Assignment|{{=}}, {{+=}}, {{-=}}, {{*=}}, {{/=}}, {{%=}}|
|
||||
|
||||
h3. Rules
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{anchor:expression}\[{color:grey}Used by [#tupleLiteral], [#for], [#atomicExpression], [#longTemplate], [#whenCondition], [#functionBody], [#doWhile], [#property], [#script], [#explicitDelegation], [#jump], [#while], [#whenEntry], [#arrayAccess], [#statement], [#if], [#when], [#binding], [#valueArguments], [#functionParameter]{color}\]
|
||||
*expression*
|
||||
{color:blue}*:*{color} [#disjunction] {color:blue}*\(*{color}[#assignmentOperator] [#disjunction]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:disjunction}\[{color:grey}Used by [#expression]{color}\]
|
||||
*disjunction*
|
||||
{color:blue}*:*{color} [#conjunction] {color:blue}*\(*{color}{color:green}*{{"||"}}*{color} [#conjunction]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:conjunction}\[{color:grey}Used by [#disjunction]{color}\]
|
||||
*conjunction*
|
||||
{color:blue}*:*{color} [#equalityComparison] {color:blue}*\(*{color}{color:green}*{{"&&"}}*{color} [#equalityComparison]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:equalityComparison}\[{color:grey}Used by [#conjunction]{color}\]
|
||||
*equalityComparison*
|
||||
{color:blue}*:*{color} [#comparison] {color:blue}*\(*{color}[#equalityOperation] [#comparison]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:comparison}\[{color:grey}Used by [#equalityComparison]{color}\]
|
||||
*comparison*
|
||||
{color:blue}*:*{color} [#namedInfix] {color:blue}*\(*{color}[#comparisonOperation] [#namedInfix]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:namedInfix}\[{color:grey}Used by [#comparison]{color}\]
|
||||
*namedInfix*
|
||||
{color:blue}*:*{color} [#elvisExpression] {color:blue}*\(*{color}[#inOperation] [#elvisExpression]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
{color:blue}*:*{color} [#elvisExpression] {color:blue}*\(*{color}[#isOperation] [#isRHS]{color:blue}*\)*{color}{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:elvisExpression}\[{color:grey}Used by [#namedInfix], [#decomposerPattern]{color}\]
|
||||
*elvisExpression*
|
||||
{color:blue}*:*{color} [#infixFunctionCall] {color:blue}*\(*{color}{color:green}*{{"?:"}}*{color} [#infixFunctionCall]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:infixFunctionCall}\[{color:grey}Used by [#elvisExpression]{color}\]
|
||||
*infixFunctionCall*
|
||||
{color:blue}*:*{color} [#rangeExpression] {color:blue}*\(*{color}[#SimpleName] [#rangeExpression]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:rangeExpression}\[{color:grey}Used by [#infixFunctionCall]{color}\]
|
||||
*rangeExpression*
|
||||
{color:blue}*:*{color} [#additiveExpression] {color:blue}*\(*{color}{color:green}*{{".."}}*{color} [#additiveExpression]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:additiveExpression}\[{color:grey}Used by [#rangeExpression]{color}\]
|
||||
*additiveExpression*
|
||||
{color:blue}*:*{color} [#multiplicativeExpression] {color:blue}*\(*{color}[#additiveOperation] [#multiplicativeExpression]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:multiplicativeExpression}\[{color:grey}Used by [#additiveExpression]{color}\]
|
||||
*multiplicativeExpression*
|
||||
{color:blue}*:*{color} [#typeRHS] {color:blue}*\(*{color}[#multiplicativeOperation] [#typeRHS]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:typeRHS}\[{color:grey}Used by [#multiplicativeExpression]{color}\]
|
||||
*typeRHS*
|
||||
{color:blue}*:*{color} [#prefixUnaryExpression] {color:blue}*\(*{color}[#typeOperation] [#prefixUnaryExpression]{color:blue}*\)*{color}{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:prefixUnaryExpression}\[{color:grey}Used by [#typeRHS]{color}\]
|
||||
*prefixUnaryExpression*
|
||||
{color:blue}*:*{color} [#prefixUnaryOperation]{color:blue}*\**{color} [#postfixUnaryExpression]
|
||||
;
|
||||
|
||||
{anchor:postfixUnaryExpression}\[{color:grey}Used by [#prefixUnaryExpression], [#postfixUnaryOperation]{color}\]
|
||||
*postfixUnaryExpression*
|
||||
{color:blue}*:*{color} [#atomicExpression] [#postfixUnaryOperation]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
|
||||
{anchor:atomicExpression}\[{color:grey}Used by [#postfixUnaryExpression]{color}\]
|
||||
*atomicExpression*
|
||||
{color:blue}*:*{color} {color:green}*{{"("}}*{color} [#expression] {color:green}*{{")"}}*{color}
|
||||
{color:blue}*:*{color} [#literalConstant]
|
||||
{color:blue}*:*{color} [#functionLiteral]
|
||||
{color:blue}*:*{color} [#tupleLiteral]
|
||||
{color:blue}*:*{color} {color:green}*{{"this"}}*{color} [#label]{color:blue}*?*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"super"}}*{color} {color:blue}*\(*{color}{color:green}*{{"<"}}*{color} [#type] {color:green}*{{">"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#label]{color:blue}*?*{color}
|
||||
{color:blue}*:*{color} [#if]
|
||||
{color:blue}*:*{color} [#when]
|
||||
{color:blue}*:*{color} [#try]
|
||||
{color:blue}*:*{color} [#objectLiteral]
|
||||
{color:blue}*:*{color} [#jump]
|
||||
{color:blue}*:*{color} [#loop]
|
||||
{color:blue}*:*{color} [#SimpleName]
|
||||
{color:blue}*:*{color} [#FieldName]
|
||||
{color:blue}*:*{color} {color:green}*{{"namespace"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:label}\[{color:grey}Used by [#callSuffix], [#prefixUnaryOperation], [#atomicExpression], [#jump]{color}\]
|
||||
*label*
|
||||
{color:blue}*:*{color} {color:green}*{{"@"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"@@"}}*{color}
|
||||
{color:blue}*:*{color} [#LabelName]
|
||||
;
|
||||
|
||||
{anchor:literalConstant}\[{color:grey}Used by [#atomicExpression], [#constantPattern]{color}\]
|
||||
*literalConstant*
|
||||
{color:blue}*:*{color} {color:green}*{{"true"}}*{color} {color:blue}*|*{color} {color:green}*{{"false"}}*{color}
|
||||
{color:blue}*:*{color} [#stringTemplate]
|
||||
{color:blue}*:*{color} [#NoEscapeString]
|
||||
{color:blue}*:*{color} [#IntegerLiteral]
|
||||
{color:blue}*:*{color} [#HexadecimalLiteral]
|
||||
{color:blue}*:*{color} [#CharacterLiteral]
|
||||
{color:blue}*:*{color} [#FloatLiteral]
|
||||
{color:blue}*:*{color} {color:green}*{{"null"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:stringTemplate}\[{color:grey}Used by [#literalConstant]{color}\]
|
||||
*stringTemplate*
|
||||
{color:blue}*:*{color} {color:green}*{{"\""}}*{color} [#stringTemplateElement]{color:blue}*\**{color} {color:green}*{{"\""}}*{color}
|
||||
;
|
||||
|
||||
{anchor:stringTemplateElement}\[{color:grey}Used by [#stringTemplate]{color}\]
|
||||
*stringTemplateElement*
|
||||
{color:blue}*:*{color} (!) *Undeclared!* [#RegularStringPart]
|
||||
{color:blue}*:*{color} (!) *Undeclared!* [#ShortTemplateEntrySTART] {color:blue}*\(*{color}[#SimpleName] {color:blue}*|*{color} {color:green}*{{"this"}}*{color}{color:blue}*\)*{color}
|
||||
{color:blue}*:*{color} (!) *Undeclared!* [#EscapeSequence]
|
||||
{color:blue}*:*{color} [#longTemplate]
|
||||
;
|
||||
|
||||
{anchor:longTemplate}\[{color:grey}Used by [#stringTemplateElement]{color}\]
|
||||
*longTemplate*
|
||||
{color:blue}*:*{color} {color:green}*{{"$\{"}}*{color} [#expression] {color:green}*{{"}"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
{anchor:isRHS}\[{color:grey}Used by [#namedInfix], [#whenCondition]{color}\]
|
||||
*isRHS*
|
||||
{color:blue}*:*{color} [#pattern]
|
||||
;
|
||||
|
||||
{anchor:declaration}\[{color:grey}Used by [#statement]{color}\]
|
||||
*declaration*
|
||||
{color:blue}*:*{color} [#function]
|
||||
{color:blue}*:*{color} [#property]
|
||||
{color:blue}*:*{color} [#class]
|
||||
{color:blue}*:*{color} [#typedef]
|
||||
{color:blue}*:*{color} [#object]
|
||||
;
|
||||
|
||||
{anchor:statement}\[{color:grey}Used by [#statements]{color}\]
|
||||
*statement*
|
||||
{color:blue}*:*{color} [#declaration]
|
||||
{color:blue}*:*{color} [#expression]
|
||||
;
|
||||
|
||||
{anchor:multiplicativeOperation}\[{color:grey}Used by [#multiplicativeExpression]{color}\]
|
||||
*multiplicativeOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"\*"}}*{color} {color:blue}*:*{color} {color:green}*{{"/"}}*{color} {color:blue}*:*{color} {color:green}*{{"%"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:additiveOperation}\[{color:grey}Used by [#additiveExpression]{color}\]
|
||||
*additiveOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"+"}}*{color} {color:blue}*:*{color} {color:green}*{{"-"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:inOperation}\[{color:grey}Used by [#namedInfix]{color}\]
|
||||
*inOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"in"}}*{color} {color:blue}*:*{color} {color:green}*{{"\!in"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:typeOperation}\[{color:grey}Used by [#typeRHS]{color}\]
|
||||
*typeOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"as"}}*{color} {color:blue}*:*{color} {color:green}*{{"as?"}}*{color} {color:blue}*:*{color} {color:green}*{{":"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:isOperation}\[{color:grey}Used by [#namedInfix]{color}\]
|
||||
*isOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"is"}}*{color} {color:blue}*:*{color} {color:green}*{{"\!is"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:comparisonOperation}\[{color:grey}Used by [#comparison]{color}\]
|
||||
*comparisonOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"<"}}*{color} {color:blue}*:*{color} {color:green}*{{">"}}*{color} {color:blue}*:*{color} {color:green}*{{">="}}*{color} {color:blue}*:*{color} {color:green}*{{"<="}}*{color}
|
||||
;
|
||||
|
||||
{anchor:equalityOperation}\[{color:grey}Used by [#equalityComparison]{color}\]
|
||||
*equalityOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"\!="}}*{color} {color:blue}*:*{color} {color:green}*{{"=="}}*{color}
|
||||
;
|
||||
|
||||
{anchor:assignmentOperator}\[{color:grey}Used by [#expression]{color}\]
|
||||
*assignmentOperator*
|
||||
{color:blue}*:*{color} {color:green}*{{"="}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"+="}}*{color} {color:blue}*:*{color} {color:green}*{{"-="}}*{color} {color:blue}*:*{color} {color:green}*{{"\*="}}*{color} {color:blue}*:*{color} {color:green}*{{"/="}}*{color} {color:blue}*:*{color} {color:green}*{{"%="}}*{color}
|
||||
;
|
||||
|
||||
{anchor:prefixUnaryOperation}\[{color:grey}Used by [#prefixUnaryExpression]{color}\]
|
||||
*prefixUnaryOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"-"}}*{color} {color:blue}*:*{color} {color:green}*{{"+"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"++"}}*{color} {color:blue}*:*{color} {color:green}*{{"--"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"\!"}}*{color}
|
||||
{color:blue}*:*{color} [#annotations]
|
||||
{color:blue}*:*{color} [#label]
|
||||
;
|
||||
|
||||
{anchor:postfixUnaryOperation}\[{color:grey}Used by [#postfixUnaryExpression]{color}\]
|
||||
*postfixUnaryOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"++"}}*{color} {color:blue}*:*{color} {color:green}*{{"--"}}*{color}
|
||||
{color:blue}*:*{color} [#callSuffix]
|
||||
{color:blue}*:*{color} [#arrayAccess]
|
||||
{color:blue}*:*{color} [#memberAccessOperation] [#postfixUnaryExpression]
|
||||
;
|
||||
|
||||
{anchor:callSuffix}\[{color:grey}Used by [#constructorInvocation], [#postfixUnaryOperation]{color}\]
|
||||
*callSuffix*
|
||||
{color:blue}*:*{color} [#typeArguments]{color:blue}*?*{color} [#valueArguments] {color:blue}*\(*{color}[#label]{color:blue}*?*{color} [#functionLiteral]{color:blue}*\)*{color}
|
||||
{color:blue}*:*{color} [#typeArguments] {color:blue}*\(*{color}[#label]{color:blue}*?*{color} [#functionLiteral]{color:blue}*\)*{color}
|
||||
;
|
||||
|
||||
{anchor:memberAccessOperation}\[{color:grey}Used by [#postfixUnaryOperation]{color}\]
|
||||
*memberAccessOperation*
|
||||
{color:blue}*:*{color} {color:green}*{{"."}}*{color} {color:blue}*:*{color} {color:green}*{{"?."}}*{color} {color:blue}*:*{color} {color:green}*{{"?"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:typeArguments}\[{color:grey}Used by [#callSuffix], [#decomposerPattern], [#annotationEntry]{color}\]
|
||||
*typeArguments*
|
||||
{color:blue}*:*{color} {color:green}*{{"<"}}*{color} [#type]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{">"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:valueArguments}\[{color:grey}Used by [#callSuffix], [#annotationEntry], [#initializer]{color}\]
|
||||
*valueArguments*
|
||||
{color:blue}*:*{color} {color:green}*{{"("}}*{color} {color:blue}*\(*{color}[#SimpleName] {color:green}*{{"="}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#expression]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{")"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:jump}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*jump*
|
||||
{color:blue}*:*{color} {color:green}*{{"throw"}}*{color} [#expression]
|
||||
{color:blue}*:*{color} {color:green}*{{"return"}}*{color} [#label]{color:blue}*?*{color} [#expression]{color:blue}*?*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"continue"}}*{color} [#label]{color:blue}*?*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"break"}}*{color} [#label]{color:blue}*?*{color}
|
||||
|
||||
;
|
||||
|
||||
{anchor:tupleLiteral}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*tupleLiteral*
|
||||
{color:blue}*:*{color} {color:green}*{{"#"}}*{color} {color:green}*{{"("}}*{color} {color:blue}*\(*{color}{color:blue}*\(*{color}{color:blue}*\(*{color}[#SimpleName] {color:green}*{{"="}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#expression]{color:blue}*\)*{color}{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{")"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
{anchor:functionLiteral}\[{color:grey}Used by [#callSuffix], [#atomicExpression]{color}\]
|
||||
*functionLiteral*
|
||||
{color:blue}*:*{color} {color:green}*{{"\{"}}*{color} [#statements] {color:green}*{{"}"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"\{"}}*{color} {color:blue}*\(*{color}[#modifiers] [#SimpleName]{color:blue}*\)*{color}{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{"->"}}*{color} [#statements] {color:green}*{{"}"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"\{"}}*{color} {color:blue}*\(*{color}[#type] {color:green}*{{"."}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{"("}}*{color} {color:blue}*\(*{color}[#modifiers] [#SimpleName] {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#type]{color:blue}*\)*{color}{color:blue}*?*{color}{color:blue}*\)*{color}{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{")"}}*{color} {color:blue}*\(*{color}{color:green}*{{":"}}*{color} [#type]{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{"->"}}*{color} [#statements] {color:green}*{{"}"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:statements}\[{color:grey}Used by [#block], [#functionLiteral]{color}\]
|
||||
*statements*
|
||||
{color:blue}*:*{color} [#SEMI]{color:blue}*\**{color} [#statement]{color:blue}*\{*{color}[#SEMI]{color:blue}*+*{color}{color:blue}*\}*{color} [#SEMI]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:constructorInvocation}\[{color:grey}Used by [#delegationSpecifier], [#initializer]{color}\]
|
||||
*constructorInvocation*
|
||||
{color:blue}*:*{color} [#userType] [#callSuffix]
|
||||
;
|
||||
|
||||
{anchor:arrayAccess}\[{color:grey}Used by [#postfixUnaryOperation]{color}\]
|
||||
*arrayAccess*
|
||||
{color:blue}*:*{color} {color:green}*{{"\["}}*{color} [#expression]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{"]"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:objectLiteral}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*objectLiteral*
|
||||
{color:blue}*:*{color} {color:green}*{{"object"}}*{color} {color:green}*{{":"}}*{color} [#delegationSpecifier]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*?*{color} [#classBody]
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
h4. Pattern matching
|
||||
|
||||
bq. See [Pattern matching]
|
||||
|
||||
|
||||
{anchor:when}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*when*
|
||||
{color:blue}*:*{color} {color:green}*{{"when"}}*{color} {color:blue}*\(*{color}{color:green}*{{"("}}*{color} {color:blue}*\(*{color}[#modifiers] {color:green}*{{"val"}}*{color} [#SimpleName] {color:green}*{{"="}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#expression] {color:green}*{{")"}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{"\{"}}*{color}
|
||||
[#whenEntry]{color:blue}*\**{color}
|
||||
{color:green}*{{"}"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:whenEntry}\[{color:grey}Used by [#when]{color}\]
|
||||
*whenEntry*
|
||||
|
||||
{color:blue}*:*{color} [#whenCondition]{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color} {color:green}*{{"->"}}*{color} [#expression] [#SEMI]
|
||||
{color:blue}*:*{color} {color:green}*{{"else"}}*{color} {color:green}*{{"->"}}*{color} [#expression] [#SEMI]
|
||||
;
|
||||
|
||||
{anchor:whenCondition}\[{color:grey}Used by [#whenEntry]{color}\]
|
||||
*whenCondition*
|
||||
{color:blue}*:*{color} [#expression]
|
||||
{color:blue}*:*{color} {color:blue}*\(*{color}{color:green}*{{"in"}}*{color} {color:blue}*|*{color} {color:green}*{{"\!in"}}*{color}{color:blue}*\)*{color} [#expression]
|
||||
{color:blue}*:*{color} {color:blue}*\(*{color}{color:green}*{{"is"}}*{color} {color:blue}*|*{color} {color:green}*{{"\!is"}}*{color}{color:blue}*\)*{color} [#isRHS]
|
||||
;
|
||||
|
||||
{anchor:pattern}\[{color:grey}Used by [#isRHS], [#pattern], [#binding], [#tuplePattern]{color}\]
|
||||
*pattern*
|
||||
{color:blue}*:*{color} [#annotations] [#pattern]
|
||||
{color:blue}*:*{color} [#type]
|
||||
|
||||
{color:blue}*:*{color} [#tuplePattern]
|
||||
{color:blue}*:*{color} [#decomposerPattern]
|
||||
{color:blue}*:*{color} [#constantPattern]
|
||||
{color:blue}*:*{color} [#bindingPattern]
|
||||
{color:blue}*:*{color} {color:green}*{{"\*"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:decomposerPattern}\[{color:grey}Used by [#pattern]{color}\]
|
||||
*decomposerPattern*
|
||||
{color:blue}*:*{color} [#type]
|
||||
|
||||
{color:blue}*:*{color} [#elvisExpression] [#typeArguments]{color:blue}*?*{color} [#tuplePattern]
|
||||
;
|
||||
|
||||
{anchor:constantPattern}\[{color:grey}Used by [#pattern]{color}\]
|
||||
*constantPattern*
|
||||
{color:blue}*:*{color} [#literalConstant]
|
||||
;
|
||||
|
||||
{anchor:tuplePattern}\[{color:grey}Used by [#pattern], [#decomposerPattern]{color}\]
|
||||
*tuplePattern*
|
||||
{color:blue}*:*{color} {color:green}*{{"("}}*{color} {color:blue}*\(*{color}{color:blue}*\(*{color}{color:blue}*\(*{color}[#SimpleName] {color:green}*{{"="}}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} [#pattern]{color:blue}*\)*{color}{color:blue}*\{*{color}{color:green}*{{","}}*{color}{color:blue}*\}*{color}{color:blue}*\)*{color}{color:blue}*?*{color} {color:green}*{{")"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:bindingPattern}\[{color:grey}Used by [#pattern]{color}\]
|
||||
*bindingPattern*
|
||||
{color:blue}*:*{color} {color:green}*{{"val"}}*{color} [#SimpleName] [#binding]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
{anchor:binding}\[{color:grey}Used by [#bindingPattern]{color}\]
|
||||
*binding*
|
||||
{color:blue}*:*{color} {color:green}*{{"is"}}*{color} [#pattern]
|
||||
{color:blue}*:*{color} {color:green}*{{"\!is"}}*{color} [#pattern]
|
||||
{color:blue}*:*{color} {color:green}*{{"in"}}*{color} [#expression]
|
||||
{color:blue}*:*{color} {color:green}*{{"\!in"}}*{color} [#expression]
|
||||
{color:blue}*:*{color} {color:green}*{{":"}}*{color} [#type]
|
||||
;
|
||||
|
||||
|
||||
h2. Modifiers
|
||||
|
||||
|
||||
{anchor:modifiers}\[{color:grey}Used by [#typeParameter], [#getter], [#packageHeader], [#class], [#property], [#typedef], [#functionLiteral], [#function], [#functionType], [#when], [#setter], [#enumEntry], [#classObject], [#functionParameter], [#constructor]{color}\]
|
||||
*modifiers*
|
||||
{color:blue}*:*{color} [#modifier]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:modifier}\[{color:grey}Used by [#modifiers]{color}\]
|
||||
*modifier*
|
||||
{color:blue}*:*{color} [#classModifier]
|
||||
{color:blue}*:*{color} [#accessModifier]
|
||||
{color:blue}*:*{color} [#varianceAnnotation]
|
||||
{color:blue}*:*{color} [#memberModifier]
|
||||
{color:blue}*:*{color} [#parameterKind]
|
||||
{color:blue}*:*{color} [#annotations]
|
||||
;
|
||||
|
||||
{anchor:classModifier}\[{color:grey}Used by [#modifier]{color}\]
|
||||
*classModifier*
|
||||
{color:blue}*:*{color} {color:green}*{{"abstract"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"final"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"enum"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"open"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"attribute"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:memberModifier}\[{color:grey}Used by [#modifier]{color}\]
|
||||
*memberModifier*
|
||||
{color:blue}*:*{color} {color:green}*{{"override"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"open"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"final"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"abstract"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:accessModifier}\[{color:grey}Used by [#modifier]{color}\]
|
||||
*accessModifier*
|
||||
{color:blue}*:*{color} {color:green}*{{"private"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"protected"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"public"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"internal"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:varianceAnnotation}\[{color:grey}Used by [#modifier], [#optionalProjection]{color}\]
|
||||
*varianceAnnotation*
|
||||
{color:blue}*:*{color} {color:green}*{{"in"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"out"}}*{color}
|
||||
;
|
||||
|
||||
{anchor:parameterKind}\[{color:grey}Used by [#modifier]{color}\]
|
||||
*parameterKind*
|
||||
{color:blue}*:*{color} {color:green}*{{"lazy"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"out"}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"ref"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
h2. Annotations
|
||||
|
||||
|
||||
{anchor:annotations}\[{color:grey}Used by [#modifier], [#catchBlock], [#pattern], [#prefixUnaryOperation], [#for], [#class], [#property], [#type], [#typeConstraint], [#function], [#initializer]{color}\]
|
||||
*annotations*
|
||||
{color:blue}*:*{color} [#annotation]{color:blue}*\**{color}
|
||||
;
|
||||
|
||||
{anchor:annotation}\[{color:grey}Used by [#annotations]{color}\]
|
||||
*annotation*
|
||||
{color:blue}*:*{color} {color:green}*{{"\["}}*{color} [#annotationEntry]{color:blue}*+*{color} {color:green}*{{"]"}}*{color}
|
||||
{color:blue}*:*{color} [#annotationEntry]
|
||||
;
|
||||
|
||||
{anchor:annotationEntry}\[{color:grey}Used by [#annotation]{color}\]
|
||||
*annotationEntry*
|
||||
{color:blue}*:*{color} [#SimpleName]{color:blue}*\{*{color}{color:green}*{{"."}}*{color}{color:blue}*\}*{color} [#typeArguments]{color:blue}*?*{color} [#valueArguments]{color:blue}*?*{color}
|
||||
;
|
||||
|
||||
|
||||
h1. Lexical structure
|
||||
|
||||
|
||||
{{helper}}
|
||||
{anchor:Digit}\[{color:grey}Used by [#IntegerLiteral], [#HexDigit]{color}\]
|
||||
*Digit*
|
||||
{color:blue}*:*{color} {color:blue}*\[*{color}{color:green}*{{"0"}}*{color}{color:blue}*.*{color}{color:blue}*.*{color}{color:green}*{{"9"}}*{color}{color:blue}*\]*{color};
|
||||
|
||||
{anchor:IntegerLiteral}\[{color:grey}Used by [#literalConstant]{color}\]
|
||||
*IntegerLiteral*
|
||||
{color:blue}*:*{color} [#Digit]{color:blue}*+*{color}{color:blue}*?*{color}
|
||||
|
||||
{anchor:FloatLiteral}\[{color:grey}Used by [#literalConstant]{color}\]
|
||||
*FloatLiteral*
|
||||
{color:blue}*:*{color} {color:green}*{{<java double literal>}}*{color};
|
||||
|
||||
{{helper}}
|
||||
{anchor:HexDigit}\[{color:grey}Used by [#HexadecimalLiteral]{color}\]
|
||||
*HexDigit*
|
||||
{color:blue}*:*{color} [#Digit] {color:blue}*|*{color} {color:blue}*\[*{color}{color:green}*{{"A"}}*{color}{color:blue}*.*{color}{color:blue}*.*{color}{color:green}*{{"F"}}*{color}, {color:green}*{{"a"}}*{color}{color:blue}*.*{color}{color:blue}*.*{color}{color:green}*{{"f"}}*{color}{color:blue}*\]*{color};
|
||||
|
||||
{anchor:HexadecimalLiteral}\[{color:grey}Used by [#literalConstant]{color}\]
|
||||
*HexadecimalLiteral*
|
||||
{color:blue}*:*{color} {color:green}*{{"0x"}}*{color} [#HexDigit]{color:blue}*+*{color};
|
||||
|
||||
{anchor:CharacterLiteral}\[{color:grey}Used by [#literalConstant]{color}\]
|
||||
*CharacterLiteral*
|
||||
{color:blue}*:*{color} {color:green}*{{<character as in Java>}}*{color};
|
||||
|
||||
|
||||
bq. See [Basic types]
|
||||
|
||||
|
||||
{anchor:StringWithTemplates}*StringWithTemplates*
|
||||
{color:blue}*:*{color} {color:green}*{{<single-quoted string, $ can be escaped>}}*{color};
|
||||
|
||||
{anchor:NoEscapeString}\[{color:grey}Used by [#literalConstant]{color}\]
|
||||
*NoEscapeString*
|
||||
{color:blue}*:*{color} {color:green}*{{<"""-quoted string>}}*{color};
|
||||
|
||||
|
||||
bq. See [String templates|Strings#Templates]
|
||||
|
||||
|
||||
{anchor:SEMI}\[{color:grey}Used by [#whenEntry], [#if], [#statements], [#packageHeader], [#property], [#import]{color}\]
|
||||
*SEMI*
|
||||
{color:blue}*:*{color} {color:green}*{{<semicolon or newline>}}*{color};
|
||||
|
||||
|
||||
{anchor:SimpleName}\[{color:grey}Used by [#typeParameter], [#for], [#LabelName], [#package], [#packageHeader], [#object], [#function], [#parameter], [#FieldName], [#bindingPattern], [#when], [#setter], [#import], [#valueArguments], [#tupleLiteral], [#catchBlock], [#simpleUserType], [#atomicExpression], [#class], [#property], [#tuplePattern], [#typedef], [#annotationEntry], [#infixFunctionCall], [#functionLiteral], [#enumEntry], [#stringTemplateElement], [#typeConstraint]{color}\]
|
||||
*SimpleName*
|
||||
{color:blue}*:*{color} {color:green}*{{<java identifier>}}*{color}
|
||||
{color:blue}*:*{color} {color:green}*{{"`"}}*{color} {color:green}*{{<java identifier>}}*{color} {color:green}*{{"`"}}*{color}
|
||||
;
|
||||
|
||||
|
||||
bq. See [Java interoperability]
|
||||
|
||||
|
||||
{anchor:FieldName}\[{color:grey}Used by [#atomicExpression]{color}\]
|
||||
*FieldName*
|
||||
{color:blue}*:*{color} {color:green}*{{"$"}}*{color} [#SimpleName];
|
||||
|
||||
|
||||
bq. See [Properties And Fields]
|
||||
|
||||
|
||||
{anchor:LabelName}\[{color:grey}Used by [#label]{color}\]
|
||||
*LabelName*
|
||||
{color:blue}*:*{color} {color:green}*{{"@"}}*{color} [#SimpleName];
|
||||
|
||||
|
||||
bq. See [Returns and jumps]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
[Kotlin] is designed with *Java*\-compatibility in mind. Existing *Java* code can be called from [Kotlin] in a natural way, and [Kotlin] code can be used from *Java* rather smoothly as well.
|
||||
|
||||
h2. Calling Java code from [Kotlin]
|
||||
|
||||
In this section we describe some details about calling *Java* code from [Kotlin]. In most cases, you just use it:
|
||||
{jet}
|
||||
import java.util.*
|
||||
|
||||
fun demo(source : List<Int>) {
|
||||
val list = ArrayList<Int>()
|
||||
// 'for'-loops work for Java collections:
|
||||
for (item in source)
|
||||
list.add(item)
|
||||
// Operator conventions work as well:
|
||||
for (i in 0..source.size() - 1)
|
||||
list[i] = source[i] // get and set are called
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. {{void}}\-returning methods
|
||||
|
||||
If a *Java* method returns *void*, it will return {{Unit}} when called from [Kotlin]. If, by any chance, someone uses that return value, it will be assigned at the call site by the [Kotlin] compiler, since the value itself is known in advance (being {{()}}).
|
||||
|
||||
h3. Escaping for Java identifiers that are keywords in [Kotlin]
|
||||
|
||||
Some of the [Kotlin] keywords are valid identifiers in *Java*: *in*, *object*, *is*, etc. It may happen that some of your favorite *Java* libraries use these words as names for methods. In this situation you still can call those methods from [Kotlin], but you need to _escape_ their names with backticks:
|
||||
{jet}
|
||||
foo.`is`(bar)
|
||||
{jet}
|
||||
|
||||
h3. Null-safety
|
||||
|
||||
Any reference in *Java* may be {{null}}. So, all the *Java* methods called from [Kotlin] return [nullable references|Null-safety] (except for those annotated with [{{@NotNull}}|http://www.jetbrains.com/idea/documentation/howto.html]). This allows [Kotlin] to keep the guarantee of [having no {{NullPointerExceptions}}|Null-safety] unless they are explicitly thrown by [Kotlin] code or caused by something inside *Java* code called from [Kotlin].
|
||||
|
||||
Consider the following examples:
|
||||
{jet}
|
||||
val list = ArrayList<Int>() // non-null (constructor result)
|
||||
val size = list.size() // non-null (primitive int)
|
||||
val iterator = list.iterator() // nullable (ordinary method)
|
||||
{jet}
|
||||
|
||||
h3. Checked exceptions
|
||||
|
||||
In [Kotlin], [all exceptions are unchecked|Exceptions], meaning that the compiler does not force you to catch any of them. So, when you call a *Java* method that declares a checked exception, [Kotlin] does not force you to do anything:
|
||||
|
||||
{jet}
|
||||
fun render(list : List<out Any?>, to : Appendable) {
|
||||
for (item in list)
|
||||
to.append(item.toString()) // Java would require us to catch IOException here
|
||||
}
|
||||
{jet}
|
||||
|
||||
{anchor:Java generics}
|
||||
|
||||
h3. Java generics in [Kotlin]
|
||||
|
||||
[Kotlin]'s generics are a little different from *Java*'s (see [Generics]). When importing *Java* types to [Kotlin] we perform some conversions:
|
||||
* *Java*'s wildcards are converted into [type projections|Generics#Type projections]
|
||||
** {{Foo<? extends Bar>}} becomes {{Foo<out Bar>}}
|
||||
** {{Foo<? super Bar>}} becomes {{Foo<in Bar>}}
|
||||
* *Java*'s raw types are converted into [star projections|Generics#Star-projections]
|
||||
** {{List}} becomes {{List<*>}}, i.e. {{List<out Any?>}}
|
||||
|
||||
Besides, *Java*'s generics are not [retained at runtime|Generics#Reified generics], i.e. *Java* objects do not carry information about actual type arguments passed to their constructors, i.e. {{new ArrayList<Integer>()}} is indistinguishable from {{new ArrayList<Character>()}}. This makes it impossible to perform *instanceof*\-checks that take *Java* generics into account. [Kotlin] only allows *is*\-checks for [star-projected|Generics#Star-projections] *Java*'s generic types:
|
||||
{jet}
|
||||
if (a is <error desc="java.util.List is a Java class and its generic application to <Int> cannot be used in 'is'">java.util.List<Int></error>) // Error: cannot check if it is really a List of Ints
|
||||
// but
|
||||
if (a is java.util.List<*>) // OK: no guarantees about the contents of the list
|
||||
{jet}
|
||||
|
||||
{anchor:Arrays}
|
||||
|
||||
h3. Invariant arrays
|
||||
|
||||
Arrays in [Kotlin] are [_invariant_|Generics#Declaration-site variance], unlike [*Java*|http://c2.com/cgi/wiki?JavaArraysBreakTypeSafety]. This means that [Kotlin] does not let us assign an {{Array<String>}} to an {{Array<Any>}}, which prevents a possible runtime failure. Neither does it allow us to pass an array of a subclass as an array of superclass to a *Java* method. In most cases, this should not be a major obstacle, but if one _really_ needs to pass an array in a covariant way, they may cast explicitly.
|
||||
|
||||
On the Java platform, having a generic class {{Array}} to represent arrays leads to a lot of boxing/unboxing operations. As arrays are mostly use where performance is critical, we introduced a workaround for this issue and defined classes {{IntArray}}, {{DoubleArray}}, {{CharArray}} and so on, which are not related to the Array class and are compiled down to Java's primitive arrays.
|
||||
|
||||
h3. Object methods
|
||||
|
||||
When *Java* types are imported into [Kotlin], all the references of type {{java.lang.Object}} are turned into {{Any?}}, for any reference may be used there.
|
||||
|
||||
The big difference between {{java.lang.Object}} and {{Any}} is that {{Any}} does not declare _any_ members at all. This is due to the [inheritance rules|Classes and Inheritance#Overriding rules] in [Kotlin]. Now, what do we do if we need our {{toString()}}, {{equals()}} etc?
|
||||
|
||||
h5. toString()
|
||||
|
||||
{{toString()}} is declared as an [extension function|Extension functions] that looks for an instance function named {{toString}} and calls it. If there's no {{toString}} it returns some default like {{this.javaClass.getName() + "@" + System.identityHashCode(this)}}.
|
||||
|
||||
From the programmer's perspective almost nothing changes compared to *Java*: all the existing *toString()* implementations work, and when you need a custom {{toString}} for your class, you simply put if there:
|
||||
{jet}
|
||||
class A() {
|
||||
fun toString() : String = "A"
|
||||
}
|
||||
{jet}
|
||||
You don't have to make it *virtual*, and you are allowed to put *override* there only if one of the superclasses declares it *virtual*.
|
||||
|
||||
h5. equals()
|
||||
|
||||
In [Kotlin], {{==}} stands for a [guarded call to {{equals()}}|Basic operations#Equality]. The expression on the left-hand side must have a method named {{equals}} that takes one parameter of type {{Any?}} and returns {{Boolean}}. Thus, all the *Java* objects have it out of the box. On the other hand, there's an extension function to {{Any?}} that performs the same kind of lookup as {{toString()}}.
|
||||
|
||||
h5. hashCode()
|
||||
|
||||
{{hashCode()}} works for *Java* objects.
|
||||
|
||||
In the upcoming [Kotlin] standard library we plan to have a {{Hashable}} interface that is required for something to be put into a _non-identity_ hash-map.
|
||||
|
||||
h5. wait()/notify()
|
||||
|
||||
[Effective Java|http://java.sun.com/docs/books/effective] Item 69 kindly suggests to *Prefer concurrency utilities to wait and notify*. Thus, these methods are not available on references of type {{Any}}, only on *Java* objects.
|
||||
|
||||
h5. getClass()
|
||||
|
||||
To retrieve the type information from an object, one uses the [{{javaClass}}|Runtime Type Information] extension function. {{getClass()}} is available for *Java* objects.
|
||||
|
||||
h5. finalize()
|
||||
|
||||
{{finalize()}} can be overridden exactly like {{toString()}}
|
||||
|
||||
h5. clone()
|
||||
|
||||
{{clone()}} can be overridden like {{toString()}} but with specifying {{Cloneable}} as a supertype. Do not forget about [Effective Java|http://java.sun.com/docs/books/effective] Item 11: *Override clone judiciously*.
|
||||
|
||||
h3. Inheritance from Java classes
|
||||
|
||||
At most one *Java*\-class (and as many *Java* interfaces as you like) can be a supertype for a class in [Kotlin]. This class must go first in the supertype list.
|
||||
|
||||
h3. Accessing static members
|
||||
|
||||
Static members of *Java* classes form "class objects" for these classes. One cannot pass such a "class object" around as a value, but can access the members explicitly, for example
|
||||
{jet}
|
||||
if (Character.isLetter(a)) {
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
|
||||
h2. Calling [Kotlin] code from Java
|
||||
|
||||
We plan to target more platforms in the future, but currently, [Kotlin] is only compiled for the *Java* platform. This means that the compiler generates *Java* bytecode, and thus the code that we write in [Kotlin] can be called from *Java*. There are some concepts in [Kotlin] that are not available in *Java*, though. In this section, we briefly describe how these concepts are mapped to *Java* concepts.
|
||||
|
||||
h3. Package-level functions
|
||||
|
||||
All the functions and properties declared inside a [*package*|Packages] {{org.foo.bar}} are put into a *Java* class named {{org.foo.bar.namespace}}.
|
||||
|
||||
{jet}
|
||||
package demo {
|
||||
class Foo() {
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
{code}
|
||||
// Java
|
||||
new Foo();
|
||||
demo.namespace.bar();
|
||||
{code}
|
||||
|
||||
h3. Checked exceptions
|
||||
|
||||
As we mentioned above, [Kotlin] does not have checked exceptions. So, normally, the *Java* signatures of [Kotlin] functions do not declare exceptions thrown. Thus if we have a function in [Kotlin] like this:
|
||||
{jet}
|
||||
package demo
|
||||
|
||||
fun foo() {
|
||||
throw IOException();
|
||||
}
|
||||
{jet}
|
||||
And we want to call it from *Java* and catch the exception:
|
||||
{jet}
|
||||
// Java
|
||||
try {
|
||||
demo.namespace.foo();
|
||||
}
|
||||
catch (<error desc="Exception IOException is never thrown in the corresponding try block">IOException e</error>) { // error: foo() does not declare IOException in the throws list
|
||||
// ...
|
||||
}
|
||||
{jet}
|
||||
we get an error message from the *Java* compiler, because {{foo()}} does not declare {{IOException}}. Now, what should we do? There are a few options:
|
||||
* Option one (suggested in the comments below) is to create a pseudo-throwing function in Java:
|
||||
{code}
|
||||
// Java
|
||||
<E extends Throwable> void mayThrow(Class<E> eClass) throws E {
|
||||
// Do nothing
|
||||
}
|
||||
{code}
|
||||
And then write:
|
||||
{code}
|
||||
// Java
|
||||
try {
|
||||
mayThrow(IOException.class);
|
||||
demo.namespace.foo();
|
||||
}
|
||||
catch (IOException e) { // No problem
|
||||
// ...
|
||||
}
|
||||
{code}
|
||||
* Option two is to catch {{Throwable}} and do an *instanceof* check. This is not very elegant, but will work.
|
||||
* Option three is to write a wrapper function in *Java*:
|
||||
{jet}
|
||||
void foo() throws IOException { // Java does not require us to throw an exception if we declare one
|
||||
demo.namespace.foo();
|
||||
}
|
||||
{jet}
|
||||
Now, you can call {{foo()}} instead of {{demo.namespace.foo()}}, and catch the exception.
|
||||
* Option four is to make [Kotlin] put a *throws* list to the {{foo()}}'s signature with the *throws* annotation:
|
||||
{jet}
|
||||
throws<IOException> fun foo() {
|
||||
throw IOException();
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. Runtime Type Information
|
||||
|
||||
{note:title=Runtime Generics are not implemented yet}{note}
|
||||
|
||||
[Kotlin]'s generics are retained at runtime, this means that upon object creation, we pass the type information as parameter to the constructor:
|
||||
{code}
|
||||
// Java
|
||||
new SomeClassDesclaredInKotlin<Integer>(TypeInfos.Int()) // We are passing a TypeInfo object explicitly
|
||||
{code}
|
||||
|
||||
And the same for generic functions.
|
||||
|
||||
h3. Null-safety
|
||||
|
||||
When calling [Kotlin] functions from *Java*, nobody prevents us from passing a {{null}} as a non-null parameter. That's why [Kotlin] generates runtime checks for all *public* functions that expect non-nulls. This way we get a {{NullPointerException}} in the *Java* code immediately.
|
||||
|
||||
h3. Properties
|
||||
|
||||
Property getters are turned into {{get}}\-methods, and setters -- into {{set}}\-methods.
|
||||
@@ -1,60 +0,0 @@
|
||||
h3. Kontributors to the [Kotlin project|https://github.com/jetbrains/kotlin]
|
||||
|
||||
See all pull requests [here|https://github.com/jetbrains/kotlin/pulls].
|
||||
|
||||
* [James Strachan (Kommitter)|https://github.com/jstrachan]
|
||||
* [Evgeny Goldin (Kommitter)|https://github.com/evgeny-goldin]
|
||||
* [Sergey Lukjanov|https://github.com/Frostman]
|
||||
* [Taro Nagasawa|https://github.com/ntaro]
|
||||
* [Oleg Kunov|https://github.com/olegkunov]
|
||||
* [Hiram Chirino|https://github.com/chirino]
|
||||
|
||||
h3. How to Contribute
|
||||
|
||||
* Find a task that you would like to work on. If you don't have any itch to scratch, check out the [requests tagged as Newbie|http://youtrack.jetbrains.com/issues/KT?q=tag%3A+Newbie+%23unresolved] in the Kotlin issue tracker.
|
||||
* Leave a comment on the issue telling the team and other potential contributors that you're working on it.
|
||||
* Fork [our repository on GitHub|https://github.com/jetbrains/kotlin].
|
||||
* Implement your solution. Please make sure to provide tests for your new features and bugfixes.
|
||||
* Send us a pull request. We will review your changes and integrate them into the codebase or let you know about the problems we've noticed.
|
||||
|
||||
If you're interested in closer collaboration with the project and your initial contributions have been successful, you may get commit access to the project. In that case, you will need to sign the [Kontributor License Agreement|^kotlin-cla.pdf] and send it to JetBrains.
|
||||
|
||||
h3. Standalone Projects
|
||||
* Scripting
|
||||
** [kotlin-script|https://github.com/andrewoma/kotlin-script]
|
||||
** [aztec|https://github.com/kondratovich/aztec]
|
||||
* Editor profiles
|
||||
** [kotlin-vim|https://github.com/ignatov/kotlin-vim]
|
||||
** [kotlin-textmate-bundle|https://github.com/k33g/kotlin-textmate-bundle]
|
||||
** [kotkit|https://github.com/bjarneh/kotkit] includes syntax definitions for vim and nano
|
||||
* Building
|
||||
** [aztec|https://github.com/kondratovich/aztec]
|
||||
** [griffon-kotlin-plugin|https://github.com/griffon/griffon-kotlin-plugin]
|
||||
** [kotkit|https://github.com/bjarneh/kotkit] includes a script for building Kotlin programs
|
||||
* Library Ports/Examples
|
||||
** [jasmine-kotlin|https://github.com/xian/jasmine-kotlin]
|
||||
** [KotlinPrimavera|https://github.com/cobaltolabs/KotlinPrimavera]
|
||||
** [mailchimp-kotlin|https://github.com/ae6rt/mailchimp-kotlin]
|
||||
|
||||
h3. Benchmarks/Program collections
|
||||
|
||||
* [99 Bottles of Beer|http://99-bottles-of-beer.net/language-kotlin-2818.html]
|
||||
* [Project Euler|https://github.com/abreslav/kotlin-euler]
|
||||
* Call to Arms
|
||||
** [PLEAC|http://pleac.sourceforge.net/]
|
||||
|
||||
h3. Talks/Demos/Presentations
|
||||
|
||||
* [An IDE screencast by Mark Derricutt|http://screencast.com/t/XJRIphU0ee]
|
||||
|
||||
h3. Aknowledgements
|
||||
|
||||
The [Kotlin] team thanks the following people for their help (design flaws they pointed out, important features they suggested, etc.):
|
||||
|
||||
* Ilya Ryzhenkov
|
||||
* Roman Elizarov
|
||||
* Mads Torgersen
|
||||
* Kevin Bourrillion
|
||||
* Bob Lee
|
||||
* Jan Martin Persch
|
||||
* Alexander Kiel
|
||||
@@ -1,247 +0,0 @@
|
||||
{toc:style=disc|indent=20px}
|
||||
h1. Ant
|
||||
|
||||
|
||||
h2. Defining {{*<kotlinc>*}} task using local Kotlin setup
|
||||
|
||||
One way to define Ant's {{*<kotlinc>*}} task is by using your local Kotlin setup and {{*KOTLIN_HOME*}} environment variable:
|
||||
|
||||
{code:xml}
|
||||
<property environment="env"/>
|
||||
<taskdef resource = "org/jetbrains/kotlin/ant/antlib.xml">
|
||||
<classpath>
|
||||
<fileset dir = "${env.KOTLIN_HOME}/lib" includes = "*.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
{code}
|
||||
|
||||
|
||||
Alternatively, you can copy all jar files from Kotlin distribution to Ant's {{"lib"}} folder.
|
||||
|
||||
|
||||
h2. {{*<kotlinc>*}} attributes
|
||||
|
||||
|
||||
|| {align:center}Name{align} || {align:center}Description{align} || {align:center}Required{align} || {align:center}Default Value{align} ||
|
||||
| {align:center}{{*src*}}{align} | Kotlin source file or directory to compile | {{"src"}} or {{"module"}} needs to be specified | |
|
||||
| {align:center}{{*module*}}{align} | Kotlin [module|http://confluence.jetbrains.net/display/Kotlin/Modules+and+Compilation] to compile | {{"src"}} or {{"module"}} needs to be specified | |
|
||||
| {align:center}{{*output*}}{align} | Destination directory | If {{"src"}} is used - {{"output"}} or {{"jar"}} needs to be specified | |
|
||||
| {align:center}{{*jar*}}{align} | Destination jar file | If {{"src"}} is used - {{"output"}} or {{"jar"}} needs to be specified
|
||||
If {{"module"}} is used - only {{"jar"}} can be specified or it can be omitted | {align:center}{{"moduleName.jar"}}{align} |
|
||||
| {align:center}{{*classpath*}}{align} | Compilation class path | {align:center}{{false}}{align} | |
|
||||
| {align:center}{{*classpathref*}}{align} | Compilation class path reference | {align:center}{{false}}{align} | |
|
||||
| {align:center}{{*stdlib*}}{align} | Path to {{"kotlin-runtime.jar"}} | {align:center}{{false}}{align} | {align:center}{{""}}{align} |
|
||||
| {align:center}{{*includeRuntime*}}{align} | If {{"jar"}} is used - whether Kotlin runtime library is included | {align:center}{{false}}{align} | {align:center}{{true}}{align} |
|
||||
|
||||
|
||||
{{<kotlinc>}} accepts a nested {{<classpath>}} element, similarly to [{{<javac>}}|http://evgeny-goldin.org/javadoc/ant/Tasks/javac.html].
|
||||
|
||||
|
||||
h2. Examples
|
||||
|
||||
|
||||
{code:xml}
|
||||
<kotlinc src = "test/longer-examples/Bottles.kt" output = "dist"/>
|
||||
<kotlinc src = "test/longer-examples" output = "dist"/>
|
||||
|
||||
<kotlinc src = "test/longer-examples/Bottles.kt" jar = "dist.jar"/>
|
||||
<kotlinc src = "test/longer-examples" jar = "dist.jar"/>
|
||||
|
||||
<kotlinc module = "test/modules/smoke/Smoke.kts" jar = "dist.jar"/>
|
||||
<kotlinc module = "test/modules/smoke/Smoke.kts"/> => "smoke.jar"
|
||||
{code}
|
||||
|
||||
{{"Smoke.kts"}}:
|
||||
|
||||
{code}
|
||||
import kotlin.modules.*
|
||||
|
||||
fun project() {
|
||||
module("smoke") {
|
||||
sources += "Smoke.kt"
|
||||
}
|
||||
}
|
||||
{code}
|
||||
{{"Smoke.kt"}}:
|
||||
|
||||
{code}
|
||||
package Smoke
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
print("${args[0]}|${args[1]}|${args[2]}")
|
||||
}
|
||||
{code}
|
||||
|
||||
|
||||
h3. Classpath examples
|
||||
|
||||
|
||||
{code:xml}
|
||||
<path id="junit-jar">
|
||||
<fileset file="lib/junit.jar"/>
|
||||
</path>
|
||||
|
||||
<kotlinc src = "src/unit-tests" jar = "tests.jar" classpath = "lib/junit.jar"/>
|
||||
|
||||
<kotlinc src = "src/unit-tests" jar = "tests.jar" classpathref = "junit-jar"/>
|
||||
|
||||
<kotlinc src = "src/unit-tests" jar = "tests.jar">
|
||||
<classpath>
|
||||
<path refid="junit-jar"/>
|
||||
</classpath>
|
||||
</kotlinc>
|
||||
|
||||
<kotlinc src = "src/unit-tests" jar = "tests.jar">
|
||||
<classpath>
|
||||
<fileset file="lib/junit.jar"/>
|
||||
</classpath>
|
||||
</kotlinc>
|
||||
{code}
|
||||
|
||||
|
||||
h1. Maven
|
||||
|
||||
"kotlin-maven-plugin" compiles Kotlin sources and modules.
|
||||
Note: only Maven 3 is supported for now.
|
||||
|
||||
{note}The old [{{"kotlin-maven-plugin"}}|http://evgeny-goldin.com/wiki/Kotlin-maven-plugin] is no longer supported.{note}
|
||||
|
||||
h3. Repositories
|
||||
|
||||
Kotlin maven artifacts are published on http://repository.jetbrains.com.
|
||||
|
||||
Add references to it in your pom or settings file:
|
||||
|
||||
{code}
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jetbrains-release</id>
|
||||
<url>http://repository.jetbrains.com/releases</url>
|
||||
<releases> <enabled>true</enabled> </releases>
|
||||
<snapshots> <enabled>false</enabled> </snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jetbrains-snapshots</id>
|
||||
<url>http://repository.jetbrains.com/snapshots</url>
|
||||
<releases> <enabled>false</enabled> </releases>
|
||||
<snapshots> <enabled>true</enabled> </snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>jetbrains-release</id>
|
||||
<url>http://repository.jetbrains.com/releases</url>
|
||||
<releases> <enabled>true</enabled> </releases>
|
||||
<snapshots> <enabled>false</enabled> </snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>jetbrains-snapshots</id>
|
||||
<url>http://repository.jetbrains.com/snapshots</url>
|
||||
<releases> <enabled>false</enabled> </releases>
|
||||
<snapshots> <enabled>true</enabled> </snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
{code}
|
||||
|
||||
h3. Versions
|
||||
|
||||
Define Kotlin version in *kotlin.version*. Possible values are:
|
||||
|
||||
* *X.Y-SNAPSHOT* - snapshot versions for *X.Y* release, updated with every successful build on our continuous integration server.
|
||||
Highly unstable, recommended for testing new compiler features.
|
||||
Currently, all builds are published as *0.1-SNAPSHOT*.
|
||||
|
||||
* *X.Y.Z* - release or milestone version *X.Y.Z*, updated manually, stable.
|
||||
|
||||
Here's the table of versions corresponding to milestone codes:
|
||||
|
||||
||Milestone||Version||
|
||||
|M1 | 0.1.2090 |
|
||||
|
||||
h3. Dependencies
|
||||
|
||||
Kotlin has an extensive standard library, use it in your program:
|
||||
|
||||
{code}
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
{code}
|
||||
|
||||
h3. Compile Kotlin sources
|
||||
|
||||
Specify source directories in <build> tag:
|
||||
|
||||
{code}
|
||||
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
||||
{code}
|
||||
|
||||
Reference kotlin-maven-plugin to compile sources:
|
||||
|
||||
{code}
|
||||
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals> <goal>compile</goal> </goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals> <goal>test-compile</goal> </goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
{code}
|
||||
|
||||
h3. Compile mixed Kotlin/Java sources
|
||||
|
||||
To compile mixed code applications Kotlin compiler should be invoked before Java compiler.
|
||||
In maven terms that means kotlin-maven-plugin should be run before maven-compiler-plugin.
|
||||
|
||||
It could be done by moving Kotlin compilation to previous phase, *process-sources* (feel free to suggest a better solution if you have one):
|
||||
|
||||
{code}
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals> <goal>compile</goal> </goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>process-test-sources</phase>
|
||||
<goals> <goal>test-compile</goal> </goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
{code}
|
||||
|
||||
h3. Example
|
||||
|
||||
Download a simple hello world application [here|^maven-hello-world-examples.zip].
|
||||
|
||||
h1. Gradle
|
||||
|
||||
_Coming soon._
|
||||
|
||||
h1. Griffon
|
||||
|
||||
See [{{"griffon-kotlin-plugin"}}|https://github.com/griffon/griffon-kotlin-plugin].
|
||||
@@ -1,26 +0,0 @@
|
||||
h2. KotlinDoc
|
||||
|
||||
KotlinDoc is the Kotlin equivalent of javadoc and is used to comment public APIs. Current recommendations for code that works nice with KotlinDoc are:
|
||||
|
||||
* use the Java style /*\* comments \*/ syntax
|
||||
* first sentence is used for the summary of a class/function/property and the rest of the documentation is for the detailed section
|
||||
* you can use either HTML tags or [markdown|http://daringfireball.net/projects/markdown/syntax#block] wiki markup for styling comments with bold, bullet lists, links and so forth
|
||||
* for linking to packages, classes, functions & properties we support WikiLink notation as: *\[\[expression\]\]* where expression can be a package name, class name, className.function() or className.property
|
||||
* try to include test code that is compiled and tested inside the documentation, rather than including source code inside comments which can soon get stale and typically isn't refactor-safe. You can include the source code of a function relative to your source file using the *@includeFunction* macro as shown below, giving the relative file and name of the function to be included. The function body will be included inside the comments.
|
||||
|
||||
Here are some [examples|https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/JLangIterables.kt].
|
||||
|
||||
{jet}
|
||||
/**
|
||||
* This is **bold**
|
||||
*
|
||||
* New paragraph using newlines.
|
||||
*
|
||||
* We can also support wiki links notation
|
||||
* for example [[List]] and [[Collection]] and [[java.util.Collection.size()]] will
|
||||
* generate hypertext links to classes
|
||||
*
|
||||
* @includeFunctionBody ../test/MyTest.kt someFunction
|
||||
*/
|
||||
fun anotherMethod(): Unit { ... }
|
||||
{jet}
|
||||
@@ -1,8 +0,0 @@
|
||||
*Note*: If you've come to this page from an external link, please start reading at the [Welcome] page, not this one.
|
||||
|
||||
!Kotlin.png|align=right,height=100px!
|
||||
Project [Kotlin] was born in [Saint Petersburg|http://en.wikipedia.org/wiki/Saint_Petersburg], Russia, where one of the main [JetBrains'|http://jetbrains.com] development offices is located. [_Kotlin_|http://en.wikipedia.org/wiki/Kotlin_Island] is the name of an island situated nearby Saint Petersburg, in the Gulf of Finland, with a beautiful town of [Kronstadt|http://en.wikipedia.org/wiki/Kronstadt] build upon the island. The current logo was inspired by the probably imagined connection of the word "Kotlin" with the word "Kettle", which was originally mentioned in the 1911 edition of Encyclopedia Britannica.
|
||||
|
||||
*Disclaimer 1*: We believe that no coffee or other exotic cultures are grown in Kotlin in any noticeable quantities.
|
||||
|
||||
*Disclaimer 2*: Despite the fact that [Kotlin Class Destroyers|http://en.wikipedia.org/wiki/Kotlin_class_destroyer] were named after the same island, our language is not intended for class destruction by any means.
|
||||
@@ -1,40 +0,0 @@
|
||||
{note}Modules are being redesigned{note}
|
||||
|
||||
A *module* is a _unit of compilation_ in [Kotlin]. Physically, modules are described by _build scripts_. Such scripts programmatically assemble _module descriptors_ that carry information about source files that constitute the module, dependencies, and compiler options used to build the module.
|
||||
|
||||
Being a unit of compilation means that all the analyses and optimizations may be performed module-wise, and that binary compatibility issues arise only on module boundaries.
|
||||
|
||||
h3. Module identifiers and root namespaces
|
||||
|
||||
Each module must have a unique identifier. This becomes and identifiers for the module's _root namespace_ -- the one all other namespaces in that module reside in.
|
||||
|
||||
h3. Default imports
|
||||
|
||||
A build script for a module may specify a set of _default imports_ for its source files. It is convenient to import ubiquitously used libraries (like collections, UI, etc) by default.
|
||||
|
||||
h3. Filesystem layout
|
||||
|
||||
[Kotlin] does not require any particular layout of source files in the file system: a *namespace* may not correspond to a directory, and a *class* may not occupy its own file. I.e. one can put all the source code for a *module* into a single source file.
|
||||
|
||||
h3. Dependencies
|
||||
|
||||
Modules can depend on other modules, and specify version requirements for their dependencies.
|
||||
|
||||
While exact API is not settled yet, the module script file may look like this:
|
||||
{jet}
|
||||
val homeDir = "..."
|
||||
|
||||
module("org.jetbrains.test") {
|
||||
depends(MavenRepo["junit.junit@4.8.2"])
|
||||
|
||||
importNamespace("java.lang")
|
||||
importNamespace("org.junit")
|
||||
|
||||
sourceRoot("$homeDir/src")
|
||||
testSourceRoot("$homeDir/tests")
|
||||
}
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Packages]
|
||||
@@ -1,122 +0,0 @@
|
||||
h1. Nullable types and Non-null types
|
||||
|
||||
One of the most common pitfalls in Java programming is accessing a member of a {{null}} reference, that results in a {{NullPointerException}}, because virtually any reference in a Java program can hold {{null}}. It happens so often that we have a casual abbreviation for it: {{NPE}}. Also have a look at this talk: ["The Billion Dollar Mistake"|http://qconlondon.com/london-2009/presentation/Null+References:+The+Billion+Dollar+Mistake].
|
||||
|
||||
[Kotlin]'s type system is aimed to eliminate {{NullPointerException}}'s from our code. The only possible causes of {{NPE}}'s may be
|
||||
# Someone had explicitly thrown is ({{throw NullPointerException()}})
|
||||
# Someone called external *Java* code that caused it
|
||||
# There's data inconsistency w.r.t initialization (an uninitialized {{this}} available in a constructor is used somewhere)
|
||||
|
||||
In [Kotlin] the type system distinguishes between references that can hold {{null}} (_nullable_ references) and those that can not (_non-null_ references). For example, a regular variable of type {{String}} can not hold {{null}}:
|
||||
{jet}
|
||||
var a : String = "abc"
|
||||
a = <error desc="Incompatible types: cannot assign null to a variable of type String">null</error> // compilation error
|
||||
{jet}
|
||||
To allow nulls, one declares a variable as _nullable string_, written {{String?}}:
|
||||
{jet}
|
||||
var b : String? = "abc"
|
||||
b = null // ok
|
||||
{jet}
|
||||
Now, if you call a method on {{a}}, it's guaranteed not to cause an {{NPE}}, so you can safely say
|
||||
{jet}
|
||||
val l = a.length()
|
||||
{jet}
|
||||
But if you want to call the same method on {{b}}, that would not be safe, and the compiler reports an error:
|
||||
{anchor:example}
|
||||
{jet}
|
||||
val l = b<error desc="'b' can be null. Use safe call (?.) or check for null explicitly">.</error>length() // error: variable 'b' can be null
|
||||
{jet}
|
||||
But we still need to call that method, right? There are a few ways of doing that.
|
||||
|
||||
h2. Checking for {{null}} in conditions
|
||||
|
||||
First, you can explicitly check if {{b}} _is_ {{null}}, and handle the two options separately:
|
||||
{jet}
|
||||
val l = if (b != null) b.length() else -1
|
||||
{jet}
|
||||
The compiler tracks the information about the check you performed, and allows the call to {{length()}} inside the {{if}}. More complex conditions are supported as well:
|
||||
{jet}
|
||||
if (b != null && b.length() > 0)
|
||||
print("String of length ${b.length()}")
|
||||
else
|
||||
print("Empty string")
|
||||
{jet}
|
||||
|
||||
Note that this only works where {{b}} is immutable (i.e. a local *val* or a member *val* which has a backing field and is not overridable), because otherwise it might happen that {{b}} changes to *null* _after_ the check.
|
||||
|
||||
h2. Safe calls
|
||||
|
||||
Your second option is the _safe call_ operator, written {{?.}}:
|
||||
{jet}
|
||||
b?.length()
|
||||
{jet}
|
||||
This returns {{b.length()}} if {{b}} is not {{null}}, and {{null}} otherwise. The type of this expression is {{Int?}}.
|
||||
|
||||
Safe calls are useful in chains. For example, if Bob, an {{Employee}}, _may_ be assigned to a {{Department}} (or not), that in turn _may_ have another {{Employee}} as a department {{head}}, then to obtain the {{name}} of Bob's department head, if any), we write the following:
|
||||
{jet}
|
||||
bob?.department?.head?.name
|
||||
{jet}
|
||||
Such a chain returns {{null}} if any of the properties in it is {{null}}.
|
||||
|
||||
h2. Elvis operator
|
||||
|
||||
When we have a _nullable_ reference {{r}}, we can say "if {{r}} is not null, use it, otherwise use some _non-null_ value {{x}}":
|
||||
{jet}
|
||||
val l : Int = if (b != null) b.length() else -1
|
||||
{jet}
|
||||
Along with the complete {{if}} expression, this can be expressed with the _Elvis_ operator, written {{?:}}:
|
||||
{jet}
|
||||
val l = b?.length() ?: -1
|
||||
{jet}
|
||||
If the expression to the left of {{?:}} is not null, the elvis operator returns it, otherwise it returns the expression to the right. Note that the right-hand side expression is evaluated only if the left-hand side is *null*.
|
||||
|
||||
{anchor:sure}
|
||||
h2. The {{\!\!}} operator
|
||||
|
||||
The third option is for {{NPE}}\-lovers. One can write {{b!!}}, and this will return a non-null value of {{b}} (e.g., a {{String}} in our [example|#example]) or throw an {{NPE}} if {{b}} is {{null}}:
|
||||
{jet}
|
||||
val l = b!!.length()
|
||||
{jet}
|
||||
Thus, if you want an {{NPE}}, you can have it, but you have to ask for it explicitly, and it does not appear out of the blue.
|
||||
|
||||
By the way, {{!!}} is added for conciseness, and formerly was emulated by an _extension function_ from the standard library, defined as follows:
|
||||
{jet}
|
||||
inline fun <T : Any> T?.sure() : T =
|
||||
if (this == null)
|
||||
throw NullPointerException()
|
||||
else
|
||||
this
|
||||
{jet}
|
||||
|
||||
h1. Safe casts
|
||||
|
||||
Regular casts may result into a {{ClassCastException}} if the object is not of the target type. Another option is to use _safe casts_ that return {{null}} is the attempt was not successful:
|
||||
{jet}
|
||||
val aInt : Int? = a as? Int
|
||||
{jet}
|
||||
|
||||
h1. Best practices related to this feature
|
||||
|
||||
[J. Bloch, Effective Java. Second Edition |http://java.sun.com/docs/books/effective/]
|
||||
*Item 38*: Check parameters for validity
|
||||
*Item 43*: Return empty arrays or collections, not nulls
|
||||
|
||||
|
||||
[Null Object Design Pattern |http://en.wikipedia.org/wiki/Null_Object_pattern]
|
||||
(Originally proposed by [B. Woolf |http://portal.acm.org/citation.cfm?id=273448.273450])
|
||||
|
||||
h1. Similar features in other languages
|
||||
|
||||
In *Java*, one can use annotations on methods and parameters (or on types, when JSR-308 is accepted), these annotations can be used by external tools to verify null-safety. For example, one can use the [{{@NotNull}} annotation supported by *IntelliJ IDEA*|http://www.jetbrains.com/idea/documentation/howto.html].
|
||||
|
||||
*Scala* promotes using the [{{Option}} type |http://www.scala-lang.org/api/current/scala/Option.html] to control absent values. This introduces run-time overhead because values are wrapped into objects of type {{Option}}, and the syntax is a little verbose.
|
||||
|
||||
*C#* has [Nullable types |hhttp://msdn.microsoft.com/en-us/library/1t3y8s4s(v=vs.80).aspx] that boil down to wrapping references into _value types_ allocated on the stack, and there's no actual static checks that would prohibit calling methods on a {{null}} reference.
|
||||
|
||||
*Groovy* has [Safe navigation |http://docs.codehaus.org/display/GROOVY/Operators#Operators-SafeNavigationOperator%28%3F.%29] and [Elvis |http://docs.codehaus.org/display/GROOVY/Operators#Operators-ElvisOperator%28%3F%3A%29] operators.
|
||||
|
||||
*Gosu*'s [approach |http://gosu-lang.org/doc/wwhelp/wwhimpl/api.htm?&context=gosu&src=expressions&topic=Handling_Null_Values_In_Expressions] is close to ours.
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Exceptions]
|
||||
@@ -1,74 +0,0 @@
|
||||
_Packages_ are containers for [classes|Classes and Inheritance], [objects|Object expressions and Declarations], [functions|Functions] and [properties|Properties And Fields]. A Kotlin package is _something like_ a package in *Java*, but it is not tied up to any physical file-system entity.
|
||||
|
||||
h3. Root package
|
||||
|
||||
Every [module|Modules and Compilation] declares a unique _root package_, that contains all the packages declared in this module.
|
||||
|
||||
h3. Header package declaration
|
||||
|
||||
A source file may start with a _header package declaration_ (see [the grammar|Grammar#packageHeader]):
|
||||
{jet}
|
||||
package foo.bar
|
||||
|
||||
// ...
|
||||
{jet}
|
||||
|
||||
All the contents of the source file are (directly or indirectly) contained by its header package. If the header is not specified, the module's root package is used.
|
||||
|
||||
h3. Imports
|
||||
|
||||
Besides the [default imports|Modules and Compilation#Default imports] declared by the module, each file may contain its own import directives.
|
||||
|
||||
Syntax for imports is described [here|Grammar#import].
|
||||
|
||||
One can import either a single name, e.g.
|
||||
{jet}
|
||||
import foo.Bar // Bar is now accessible withou qualification
|
||||
{jet}
|
||||
or all the accessible contents of a scope (package, class, object etc):
|
||||
{jet}
|
||||
import foo.* // everything in 'foo' becomes accessible
|
||||
{jet}
|
||||
If there is a name clash, one can disambiguate by using {{as}} keyword to locally rename the clashing entity:
|
||||
{jet}
|
||||
import foo.Bar // Bar is accessible
|
||||
import bar.Bar as bBar // bBar stands for 'bar.Bar'
|
||||
{jet}
|
||||
|
||||
h3. Absolute and relative names
|
||||
|
||||
Consider the following example (syntax is fictional):
|
||||
{jet}
|
||||
package a {
|
||||
package b {
|
||||
val x = 1
|
||||
package a {
|
||||
val y = a.b.x // Problem
|
||||
}
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
At the line marked "Problem" we have the following potential ambiguity: what does {{a}} stand for: the outer *package* {{a}} or the inner one? The rule here is that names are always _relative_: {{a}} is resolved in its scope of occurrence that makes it mean the inner *package* {{a}}, so this code does not compile.
|
||||
|
||||
To fix it, we need an _absolute_ name. These start with the *package* keyword:
|
||||
|
||||
{jet}
|
||||
package a {
|
||||
package b {
|
||||
val x = 1
|
||||
package a {
|
||||
val y = package.root.a.b.x // Fixed
|
||||
}
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
In this example, we assumed that the root package of our module is named {{root}}.
|
||||
|
||||
Absolute names may be used in imports as well:
|
||||
{jet}
|
||||
import package.root.a.b.a.*
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Functions]
|
||||
@@ -1,136 +0,0 @@
|
||||
Pattern matching allows us to check if an object has some particular structure. For example, that a node of a binary tree has both children, or that it has a left child that has no children, and so on.
|
||||
|
||||
h3. Pattern matching operators ({{is}} and {{\!is}})
|
||||
|
||||
Pattern matching is performed by *is* operator that returns *true* if the pattern matched successfully and *false* otherwise. It has a negated form *\!is*. The simplest form of pattern matching simply checks if an object conforms to a given type (similar to *Java*'s *instanceof* check):
|
||||
{jet}
|
||||
//is
|
||||
if (obj is String) {
|
||||
print(obj.length)
|
||||
}
|
||||
// !is
|
||||
if (obj !is String) {
|
||||
print("Not a String")
|
||||
}
|
||||
else {
|
||||
print(obj.length)
|
||||
}
|
||||
{jet}
|
||||
See [smart casts|Type casts].
|
||||
|
||||
*Is* and *\!is* may be used as branch conditions in *when* expressions:
|
||||
{jet}
|
||||
when (x) {
|
||||
is Int -> print(x)
|
||||
is List<Int> -> print(x.sum())
|
||||
!is Number -> print("Not even a number")
|
||||
else -> print("can't do anything")
|
||||
}
|
||||
{jet}
|
||||
{info:title=When-expressions can replace switch-statement without pattern matching}See more on *when* expressions [here|Control structures#When expression].{info}
|
||||
|
||||
h3. Patterns
|
||||
|
||||
Patterns on the right-hand side of *is* and *\!is* allow to match against types, constants, structure of tuples and other objects, and to bind objects matched by sub-patterns, to variables.
|
||||
|
||||
See the [grammar for patterns|Grammar#pattern].
|
||||
|
||||
{note:title=Complex patterns are not implemented} For now you can only use a type after *is*/*!is*. See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-186].{note}
|
||||
|
||||
h4. Tuple patterns, constant and wildcard patterns
|
||||
|
||||
One can match not only against a type. One useful kind of patterns is _tuple patterns_. Note that the following code just checks the type of {{x}} to be {{(Int, String)}}:
|
||||
{jet}
|
||||
x is #(Int, String)
|
||||
{jet}
|
||||
But we can use other things than types as tuple components:
|
||||
{jet}
|
||||
x is #(1, String)
|
||||
{jet}
|
||||
This matches a tuple whose first component is {{1}}, and the second one is any {{String}} value. One can use any literal constants as patterns, and nest tuples:
|
||||
{jet}
|
||||
x is #("a", #(1.0, (false, Any?)))
|
||||
{jet}
|
||||
Note that nullable types can also occur in patterns, e.g. {{Any?}} matches any object or *null*, i.e. it matches _anything_. [Kotlin] has a shorthand for this, called a _wildcard pattern_, and written {{\*}}:
|
||||
{jet}
|
||||
x is #(*, *, *)
|
||||
{jet}This matches any tuple of three components.
|
||||
|
||||
h4. Binding patterns
|
||||
|
||||
Often times we need to capture a part of what we've been matching. This is what _binding patterns_ are for. A binding patterns basically declares a variable iside a pattern. For example, we might want to say "if x is a tuple of two components, named a and b ":
|
||||
{jet}
|
||||
if (x is #(val a, val b)) {
|
||||
print(a)
|
||||
print(b)
|
||||
}
|
||||
{jet}
|
||||
A plain binding pattern {{val a}} matches anything and assigns it to {{a}}. Additionally, it can be restricted by
|
||||
* a pattern: {{val a is #(*, \*)}}
|
||||
* a range: {{val a in 1..10}}
|
||||
* a static type (rarely used): {{val a : Boolean}}
|
||||
|
||||
Consider a *when* expression with binding patterns:
|
||||
{jet}
|
||||
when (some_complex_expression) {
|
||||
is #(val a, val b is String) -> print("$a and ${b.length}")
|
||||
is #(val a is Int, val b is Int) -> print(a + b)
|
||||
is #(*, val b in 1..100) -> print(b)
|
||||
}
|
||||
{jet}
|
||||
|
||||
h4. Decomposer patterns
|
||||
|
||||
Tuples are not the only structures we can pattern-match against. For regular objects, [Kotlin] provides _decomposer patterns_. For example, when we want to match against a binary tree structure, we can do it this way:
|
||||
{jet}
|
||||
when (xml) {
|
||||
is Tree#(*, null) -> print("no right child")
|
||||
is Tree#(val l is Tree, val r is Tree) -> print("two children: $l and $r")
|
||||
is Tree -> print("just a tree")
|
||||
}
|
||||
{jet}
|
||||
|
||||
Decomposer patterns are available by default for [*enum* classes|Enum classes] and classes that [declare all their primary constructor parameters *val*|Classes and Inheritance#bean-class], i.e. make them properties, e.g. the {{Tree}} class could be defined this way:
|
||||
{jet}
|
||||
class Tree(val left : Tree?, val right : Tree?)
|
||||
{jet}
|
||||
|
||||
Actually, this only makes the compiler generate a _decomposer function_ automatically. One can declare such a function by herself.
|
||||
|
||||
h5. Decomposer functions
|
||||
|
||||
A _decomposer function_ is a function that is called on the pattern-matched object ({{x}} in case of {{x is pattern}}), it must return a tuple that is matched against the one provided after the decomposer name, or *null*. In the {{Tree}} example above, {{Tree}} coming in front of {{#}} is not a class name, but a decomposer function name. This function (automatically generated by the compiler) looks like this:
|
||||
{jet}
|
||||
decomposer fun Any?.Tree() : #(Tree?, Tree?)? {
|
||||
if (this is Tree)
|
||||
return #(this.left, this.right)
|
||||
return null
|
||||
}
|
||||
{jet}
|
||||
Note the *decomposer* annotation, it tells the compiler _not to call_ this function outside pattern-matching. Otherwise it would get confused with the constructor for {{Tree}}. This annotation is optional.
|
||||
|
||||
Generally, a decomposer is looked up as a function applicable for matching subject, i.e. it can have arbitrary name and it can be an member function:
|
||||
{jet}
|
||||
class Date(val timestamp : Long) {
|
||||
fun mmddyy() : #(Int, Int, Int)? = #(month, day, year)
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
fun demo(d : Date) {
|
||||
when (d) {
|
||||
is mmddyy#(05, 13, val a) -> print("May 13th of $a"))
|
||||
// ...
|
||||
}
|
||||
}
|
||||
{jet}
|
||||
|
||||
or extension function:
|
||||
|
||||
{jet}
|
||||
fun Date.mmddyy() : #(Int, Int, Int)? = #(month, day, year)
|
||||
{jet}
|
||||
|
||||
h3. What's next
|
||||
|
||||
* [Classes and Inheritance]
|
||||
@@ -1,193 +0,0 @@
|
||||
h1. Field accessors in Java
|
||||
|
||||
In *Java* world, we are so accustomed to writing _getters_ and _setters_ for our _fields_, that the advice by [Effective Java |http://java.sun.com/docs/books/effective/] Item 14: *In public classes, use accessor methods, not public fields* sort of goes without saying. All major IDEs help us here: they generate getters and setters, so that it is not that hard to produce a class like this:
|
||||
|
||||
{code}
|
||||
// Java
|
||||
public class Address {
|
||||
|
||||
private String name;
|
||||
private String street;
|
||||
private String city;
|
||||
private String state;
|
||||
private String zip;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getZip() {
|
||||
return zip;
|
||||
}
|
||||
|
||||
public void setZip(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
}
|
||||
{code}
|
||||
Most of the lines in this class are pure boilerplate code.
|
||||
|
||||
h1. Getting rid of field/get/set triples
|
||||
|
||||
In [Kotlin], there's no way to declare a _field_. All you have is _properties_. Read/write properties are declared with the {{var}} keyword, and read-only ones -- with {{val}} keyword. Thus, the class above can be rewritten as follows:
|
||||
{jet}
|
||||
public class Address() { // parentheses denote a _primary constructor_
|
||||
public var name : String = ...
|
||||
public var street String = ...
|
||||
public var city : String = ...
|
||||
public var state : String? = ...
|
||||
public var zip : String = ...
|
||||
}
|
||||
{jet}Here we have five _mutable_ properties, each of which has a _backing field_ that stores the value, and two accessors: getter and setter. Thus, the byte-code generated from this class will be almost equivalent to the one for the Java class above. The only difference will be property initializers, see [Null-safety].
|
||||
|
||||
(For even better option look [here|Classes and Inheritance#bean-class]).
|
||||
|
||||
To use a property, one simply refers to it by name, as if it were a field in Java:
|
||||
{jet}
|
||||
fun copyAddress(address : Address) : Address {
|
||||
val result = Address() // there's no 'new' keyword in Kotlin
|
||||
result.name = address.name // accessors are called
|
||||
result.street = address.street
|
||||
// ...
|
||||
return result
|
||||
}
|
||||
{jet}
|
||||
|
||||
|
||||
h2. Declaring properties and accessors
|
||||
|
||||
The full syntax for a _mutable_ property declaration is as follows:
|
||||
{jet}
|
||||
var <propertyName> : <PropertyType> [= <property_initializer>]
|
||||
<getter>
|
||||
<setter>
|
||||
{jet}
|
||||
The initializer, getter and setter are optional. Property type is optional if it can be inferred from the initializer or from the base class member being [overridden |#Overriding properties].
|
||||
|
||||
Examples:
|
||||
{jet}
|
||||
var <error:>allByDefault : Int? // error: explicit initializer required, default getter and setter implied
|
||||
var initialized = 1 // has type Int, default getter and setter
|
||||
var setterVisibility : String = "abc" // Initializer required, not a nullable type
|
||||
private set // the setter is private and has the default implementation
|
||||
{jet}
|
||||
Note that types are not inferred for properties exposed as parts of the public API, i.e. *public* and *protected*, because changing the initializer may cause an unintentional change in the public API then. For example
|
||||
{jet}
|
||||
public val <error:>example = 1 // A public property must have a type specified explicitly
|
||||
{jet}
|
||||
|
||||
The full syntax of an _immutable_ property declaration differs from a _mutable_ one in two ways: it starts with {{val}} instead of {{var}} and does not allow a setter:
|
||||
{jet}
|
||||
val simple : Int? // has type Int, default getter, must be initialized in constructor
|
||||
val inferredType = 1 // has type Int and a default getter
|
||||
{jet}
|
||||
|
||||
We can write custom accessors, very much like ordinary functions, right inside a property declaration. Here's an example of a custom getter:
|
||||
{jet}
|
||||
val isEmpty : Boolean
|
||||
get() = this.size == 0
|
||||
{jet}
|
||||
Since this property is purely derived from others, the compiler will not generate a _backing field_ for it.
|
||||
|
||||
A custom setter looks like this:
|
||||
{jet}
|
||||
var stringRepresentation : String
|
||||
get() = this.toString()
|
||||
set(value) {
|
||||
setDataFromString(value) // parses the string and assigns values to other properties
|
||||
}
|
||||
{jet}
|
||||
|
||||
h2. Backing fields
|
||||
|
||||
As we mentioned above, some properties have _backing fields_, i.e. from the client's point of view, a property is a pair of accessors (or just one getter), but physically the accessors may read and write data from/to a real _field_. One can not _declare_ a field explicitly in [Kotlin], the compiler figures it out for us.
|
||||
|
||||
In the simple cases, when we do not provide custom accessor implementations, it is obvious that a property must have a backing field, otherwise what should the default accessors do in the following case?
|
||||
{jet}
|
||||
var counter : Int = 0
|
||||
{jet}
|
||||
|
||||
But when there is a custom accessor, it _may_ or _may not_ rely on a backing field.
|
||||
To access a backing field of a property {{x}}, one says {{$x}} (the dollar sign cannot be used as a part of an identifier in [Kotlin]):
|
||||
{jet}
|
||||
var counter = 0 // the initializer value is written directly to the backing field
|
||||
set(value) {
|
||||
if (value >= 0)
|
||||
$counter = value
|
||||
}
|
||||
{jet}
|
||||
The {{$counter}} field can be read or written inside the accessors of {{counter}} and can only be assigned to inside constructors. In other places, there's no access to {{$counter}}.
|
||||
|
||||
The compiler looks at the accessors' bodies, and if they use the backing field (or the accessor implementation is left by default), a backing field is generated, otherwise it is not.
|
||||
|
||||
For example, in the following case there will be _no backing field_:
|
||||
{jet}
|
||||
val isEmpty : Boolean
|
||||
get() = this.size > 0
|
||||
{jet}
|
||||
The backing field is not needed because the only accessor does not refer to it.
|
||||
|
||||
h3. What if I want to do ... ?
|
||||
|
||||
If you want to do something that does not fit into this "implicit backing field" scheme, you can always fall back to having a "backing property":
|
||||
{jet}
|
||||
private var _table : Map<String, Int>? = null
|
||||
public val table : Map<String, Int>
|
||||
get() {
|
||||
if (_table == null)
|
||||
_table = HashMap() // Type parameters are inferred
|
||||
return _table ?: throw AssertionError("Set to null by another thread")
|
||||
}
|
||||
{jet}
|
||||
In all respects, this is just the same as in Java since access to private properties with default getters and setters is optimized so that no function call overhead is introduced.
|
||||
|
||||
h2. Overriding properties
|
||||
|
||||
See [Overriding properties|Classes and Inheritance#Overridable properties and accessors].
|
||||
|
||||
h1. Best practices related to this feature
|
||||
|
||||
[J. Bloch. Effective Java Second Edition |http://java.sun.com/docs/books/effective/]
|
||||
*Item 14*: In public classes, use accessor methods, not public fields
|
||||
|
||||
See also: [JavaBeans |http://www.oracle.com/technetwork/java/javase/tech/index-jsp-138795.html]
|
||||
|
||||
h1. Similar features in other languages
|
||||
|
||||
Java IDEs generate accessors [automatically|http://www.jetbrains.com/idea/features/code_generation.html#link1].
|
||||
|
||||
For *Java*, there's [Project Lombok |http://projectlombok.org/]: the syntax for properties is based on Java annotations.
|
||||
|
||||
In [*C#*|http://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx], [*Groovy* Beans |http://groovy.codehaus.org/Groovy+Beans] and [*Gosu*|http://gosu-lang.org/doc/wwhelp/wwhimpl/api.htm?&context=gosu&src=classes&topic=Properties] one still writes getters and setters alongside their backing fields that are declared explicitly, although the access looks like property access. [*Scala*|http://www.scala-lang.org/node/29] does not distinguish between a field and a property, but to customize a setter one needs to write a separate function named by convention.
|
||||
|
||||
h1. What's next
|
||||
|
||||
* [Basic types]
|
||||
@@ -1,52 +0,0 @@
|
||||
h3. Upcoming
|
||||
* [ÜberConf'12|http://uberconf.com/], June 19-22, Denver, CO, USA
|
||||
* [JAZOON'12|http://jazoon.com/2012], June 27, Zurich, Switzerland
|
||||
* [OSCON'12|http://www.oscon.com/oscon2012/public/schedule/detail/23963], July 20, Portland, OR, USA
|
||||
|
||||
h3. Conference talks
|
||||
|
||||
* [DUMP-2012|http://dump-it.ru/sections/zapovednik-goblinov/], May 25-26, Ekaterinburg, Russia
|
||||
* [JEEConf|http://jeeconf.com/program/#kotlin], May 19th, Kiev, Ukraine
|
||||
** [Examples|https://github.com/abreslav/introduction-to-kotlin]
|
||||
* [GeeCON|http://2012.geecon.org/], May 16th, 17th, Poznań, Poland
|
||||
** University day tutorial [Kotlin in Action|http://2012.geecon.org/university-day], [Examples|https://github.com/abreslav/kotlin-demo-graphics]
|
||||
** Conference talk [Kotlin: An introduction to being Kool|http://2012.geecon.org/schedule]
|
||||
* A friendly visit to [EPFL|http://ic.epfl.ch/cms/lang/en/pid/77752], May 14-15, Lausanne, Switzerland
|
||||
** [Examples|https://github.com/abreslav/kotlin-scala-examples]
|
||||
* [ADD-3|http://www.addconf.ru/event.sdf/ru/add_3/authors/594/595], May 12, Moscow, Russia
|
||||
** [Video (in Russian)|http://vimeo.com/42612265]
|
||||
* [JUG.ru meeting|http://jugru.timepad.ru/event/23921], April 26, St. Petersburg, Russia
|
||||
** [Presentation|http://prezi.com/-xdrdpul_lsg/kotlin-jfokus/], Video (in Russian): [Part 1|http://vimeo.com/41319179], [Part 2|http://vimeo.com/41319180]
|
||||
* [JavaOne and Oracle Develop Russia|http://www.oracle.com/javaone/ru-en/savethedate/index.html], April 18, Moscow, Russia
|
||||
** [Presentation|http://prezi.com/-xdrdpul_lsg/kotlin-jfokus/]
|
||||
* [Codemotion Roma|http://www.codemotion.it/en/talk/bringing-kotlins-power-java-libraries], March 23-24, Rome, Italy
|
||||
** [Presentation|http://prezi.com/-xdrdpul_lsg/kotlin-jfokus/]
|
||||
* [33rd Degree|http://2012.33degree.org/talk/show/7], March 19-21, Krakow, Poland
|
||||
** [Presentation|http://prezi.com/-xdrdpul_lsg/kotlin-jfokus/]
|
||||
* [Jfokus|http://www.jfokus.se/jfokus/page.jsp?lang=en&id=schema_day1], February 14, Stockholm, Sweden.
|
||||
** [Presentation|http://prezi.com/-xdrdpul_lsg/kotlin-jfokus/]
|
||||
* [JavaDay SPb|http://oracle.timepad.ru/event/17633], February 10th, Saint Petersburg, Russia
|
||||
** [Presentation|http://prezi.com/4dr1n3uy3dgh/kotlin-javaday-spb/]
|
||||
* [Devclub.eu|http://www.devclub.eu/2011/12/09/announce-dec-2011/], December 21, Tallinn, Estonia
|
||||
** [Slides & Video (in Russian)|http://vimeo.com/34176209]
|
||||
* [Devoxx 2011|http://devoxx.com/display/DV11/The+Kotlin+Programming+Language], Nov 16th
|
||||
** [Slides|http://www.slideshare.net/abreslav/kotlin-devoxx-2011]
|
||||
** [Slides & Video|http://www.parleys.com/#st=5&id=2908&sl=52]
|
||||
* [RivieraDEV 2011|http://www.rivieradev.fr/application/talk?id=140], Oct 20th-21st
|
||||
** [Slides|http://www.slideshare.net/intelliyole/kotlin-riviera-dev/] and [Video|http://www.rivieradev.fr/application/talk?id=140]
|
||||
* [Yandex|http://yandex.ru] and [CSClub|http://logic.pdmi.ras.ru/csclub/en/node/1480]
|
||||
** [Slides|http://www.slideshare.net/abreslav/kotlin-csclub-yandex]
|
||||
** [Video from CS Club (in Russian)|http://www.lektorium.tv/lecture/?id=13381]
|
||||
* [Strange Loop 2011|https://thestrangeloop.com/sessions/the-kotlin-programming-language], Sept 19th
|
||||
** [Slides|http://www.slideshare.net/abreslav/kotlin-strangeloop-2011]
|
||||
** [Slides + Video|http://www.infoq.com/presentations/The-Kotlin-Programming-Language]
|
||||
* [SOCON 2011, Emerging Languages|http://www.oscon.com/oscon2011/public/schedule/detail/20924]
|
||||
** [The Kotlin Programming Language|Welcome^OSCON_Kotlin.pdf]
|
||||
* [JVM Language Summit 2011|http://www.wiki.jvmlangsummit.com/Kotlin]
|
||||
** [Video + Slides from the Presentation session|http://drdobbs.com/231500204]
|
||||
** Workshop slides: [Classes, Inheritance, Generics, Class objects|Welcome^JVMLS_workshop_2011.pdf]
|
||||
|
||||
h3. Other publications
|
||||
* [Why JetBrains needs Kotlin|http://blog.jetbrains.com/kotlin/2011/08/why-jetbrains-needs-kotlin/]
|
||||
* \[In Russian\] [Язык программирования Kotlin (журнал "Открытые системы", №09, 2011)|http://www.osp.ru/os/2011/09/13011550/]
|
||||
** Дополнительные разделы [сопоставление с образцом, обобщенные типы и вариантность|https://docs.google.com/document/d/1yjgW_SWgwFjAxF4FVKMqFsaVq2NHusZE0-B0hJNfyHc/edit]
|
||||
@@ -1,7 +0,0 @@
|
||||
With our [web-based editor|http://kotlin-demo.jetbrains.com/] you can
|
||||
* Write code with syntax and error highlighting
|
||||
* Use code completion (experimental)
|
||||
* Study running examples
|
||||
* Solve problems of the Code Challenge
|
||||
|
||||
[Have fun!|http://kotlin-demo.jetbrains.com/]
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 893 B |
Reference in New Issue
Block a user