Compare commits

...

22 Commits

Author SHA1 Message Date
Andrey Breslav
3a3d557ed7 Update dynamic-types.md 2014-10-31 18:51:32 +03:00
Andrey Breslav
021bfe9942 Create dynamic-types.md 2014-10-31 14:17:50 +03:00
Andrey Breslav
12770cc0ef Update default-objects.md 2014-10-31 14:12:34 +03:00
Andrey Breslav
a2c8304d14 Create default-objects.md 2014-10-31 12:24:10 +03:00
Andrey Breslav
7c855f6796 Update secondary-constructors.md 2014-10-31 12:22:13 +03:00
Andrey Breslav
8fac9dde5b Update secondary-constructors.md 2014-10-31 12:21:27 +03:00
Andrey Breslav
b552b233b5 Update secondary-constructors.md 2014-10-31 12:19:47 +03:00
Andrey Breslav
7c76b4016b Create secondary-constructors.md 2014-10-31 12:15:57 +03:00
Andrey Breslav
41a53bb411 Update java-beans-as-kotlin-properties.md 2014-10-30 19:34:34 +03:00
Andrey Breslav
906bee22fd Update java-beans-as-kotlin-properties.md 2014-10-30 19:34:03 +03:00
Andrey Breslav
54e88cac7e Update java-beans-as-kotlin-properties.md 2014-10-30 19:15:24 +03:00
Andrey Breslav
eb06e5f627 examples 2014-10-30 19:14:51 +03:00
Andrey Breslav
8a8d910524 Create java-beans-as-kotlin-properties.md 2014-10-30 19:10:38 +03:00
Andrey Breslav
c8d2ec1ae3 Update multi-declarations-in-parameters.md 2014-10-30 18:19:35 +03:00
Andrey Breslav
54c954c443 Update multi-declarations-in-parameters.md 2014-10-30 18:19:11 +03:00
Andrey Breslav
17a9d84ecd Update multi-declarations-in-parameters.md 2014-10-30 14:51:41 +03:00
Andrey Breslav
b60d81cecb Update multi-declarations-in-parameters.md 2014-10-30 14:48:58 +03:00
Andrey Breslav
950c7a3a15 Update multi-declarations-in-parameters.md 2014-10-29 21:00:28 +03:00
Andrey Breslav
fa9b5d246b Update multi-declarations-in-parameters.md 2014-10-29 20:10:24 +03:00
Andrey Breslav
25cb77f21e Update multi-declarations-in-parameters.md 2014-10-29 18:53:48 +03:00
Andrey Breslav
61d308f646 Update multi-declarations-in-parameters.md 2014-10-29 18:53:05 +03:00
Andrey Breslav
91cfa8201b Create multi-declarations-in-parameters.md 2014-10-29 18:45:52 +03:00
5 changed files with 618 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
# Default objects
## Goals
- make class objects stand out a little less
- allow to write extensions for class objects
- let every addressable object have a name
## TODO
- [ ] Extensions for "class objects" of classes that don't declare them?
- [ ] Allow names on object expressions?
- [ ] Decide on default name for default objects: `Default`, maybe?
- [ ] Replace all occurences of "class object" in user-facing strings, e.g. error messages
## Syntactic changes
- `default` modifier is allowed on objects nested into classes and traits
- names of objects marked as `default` may be omitted, such objects get a name by default (e.g. `Default`, to be decided later)
External cliens may access default objects by their name (givem explicitly or by default) as well as by the name of the containing class.
Only one default object is allowed per container.
## PSI Changes
`JetClassObject` element goes away, default objects are simply named objects with a modifier.
## Semantics
Default objects work the same way class objects used to work, the changes are purely syntactic.
## Compatibility
- `class object` syntax is deprecated (works the same as `default object` + issues a warning)

View File

@@ -0,0 +1,47 @@
# Dynamic Types
## Goal
Interoperability with native JavaScript
## Examples
Unbounded dynamic type:
``` kotlin
fun jsFun(p: dynamic): dynamic
```
or
All types are dynamic by default
``` kotlin
dynamic fun jsFun(p, r = foo(), typed: Type /*this one is not dynamic*/) { }
```
Bounded dynamic type:
``` kotlin
fun foo(p: dynamic A): dynamic B
```
## TODO
- [ ] Dynamic functions?
- [ ] what is the default return type?
- [ ] Can we omit `return` expressions when the return type is `dynamic`?
- [ ] Can we return `Unit` when return type is `dynamic`?
- [ ] Dynamic classes/traits?
- [ ] All members are implicitly `dynamic`
- [ ] All types whose type constructors are marked `dynamic` are themselves dynamic types
## Typing rules
- `dynamic` is assignable to anything
- everything is assignable to `dynamic`
- `dynamic T` is assignable to `T`
- subtypes of `T` are assignable to `dynamic T`
- `dynamic` is the same as `dynamic Any?`
??? When receiver/argument is of type `R := dynamic T`
- if a call is resolved with `T` instead of `R`, it is a static call, no dynamicity involved
-

View File

@@ -0,0 +1,160 @@
# Java Beans as Kotlin Properties
## Goal
Make Java get/set pairs accessible as properties in Kotlin
## Examples
``` kotlin
// simple getter
A getA()
->
val a: A
```
``` kotlin
// getter and setter
A getA()
void setA(A)
->
var a: A
```
``` kotlin
// only setter (write-only)
void setA(A)
->
var a: A
// no get
set(v) {...}
```
``` kotlin
// private getter (effectively write-only)
private A getA()
public void setA(A)
->
var a: A
private get() = ...
public set(v) = ...
```
``` kotlin
// Different setter type
A getA()
void setA(B)
->
var a: A
get() = ...
set(v: B) = ...
```
``` kotlin
// Overloaded setters
A getA()
void setA(B)
void setA(C)
->
var a: A
get() = ...
set(v: B) = ...
set(v: C) = ...
```
## TODO
- field access (may clash with property)
- static field access (critical, syntax can't be changed)
- How much old code does this break?
- usages of Java APIs with getters/setters
- inheritors of Java classes overriding getters/setters
## Changes in Kotlin properties
- allow many setters (overloaded)
- allow no getter (no backing field + no explicit getter => no getter at all)
- allow different modifiers on getters and properties
- property modifiers are lub(get, set)
- property is no less visible than its accessors
- property is no "less final" than its accessors (`final` > `open` > `abstract`)
## Changes in JavaDescriptorResolver
**Definition**. Getter of name N is // TODO: recognize "is" prefix?
**Definition**. Setter of name N is // TODO
- All getters and setters of the same name are merged into (replaced by) a single property.
- Its visibility/modality is computed as lub of all getters' and setters' visibilities/modalities.
- (MAYBE) the respective functions (getters/setters) are also created as synthesized members (to enable calling them from Kotlin the Java way)
- see difficult cases below (two abstracts in J1 and J2)
## Difficult cases of inheritance
Two abstracts of incompatible shapes:
```
class J {
abstract void setA(A)
}
class K {
abstract fun setA(A)
}
class K1: J, K {
// can't override both var J.a and fun K.setA
// but the same problem exists in pure Kotlin code
// but if we create a concrete synthetic setA() in J it will override K.setA()
// but what if there are two setA()'s coming from J1 nad J2?
}
// Let's say we extend J and K with J1:
class J1 extend J, K {
@Override
void setA(A)
}
// and then extend it in K1
class K1 : J1 {
// we can override either val a or fun setA(), but not both, which is fine
}
// If setA() were abstract in J1, we shouldn't be able to override only `var`, because it breaks the substitution principle
```
Abstract is J and concrete fun in K
```
class J {
abstract void setA(A)
}
class K {
fun setA(A) {}
}
class K1: J, K {
override var a: A ...
}
```
Abstract is J and val in K is OK.
Abstract in J1 and J2:
```
class J1 {
abstract void setA(A)
}
class J2 {
abstract void setA(A)
}
class K : J1, J2 {
// if there are two final setA(A) synthesized for supertypes, it's a conflict :(
}
```

View File

@@ -0,0 +1,240 @@
# Multi-declarations in Parameters
* **Timeframe**: M10
* **Why**: Breaking changes in syntactic structures (lambdas)
## Goal
Support multi-declarations in parameters of lambdas, functions, constructors and setters.
## Examples
``` kotlin
// decomposing pairs in a lambda
listOfPairs.map {
(a, b) -> a + b
}
// decompose a parameter:
fun foo((a, b): Pair<Int, String>, c: Bar)
// can be called as
foo(pair, bar)
// decompose a constructor parameter
class C(val (a, b): Pair<Int, String>) {}
```
## TODO
- names of decomposed parameters in Kotlin, e.g. for named arguments
## Syntax
Old lambda syntax:
``` kotlin
{ a, b -> ... } // two parameters
{ (a, b) -> ... } // two parameters
{ (a: Int, b: String) -> ... } // parameter types
{ (a, b): Int -> ... } // return type
{ T.(a, b): Int -> ... } // receiver type
```
New syntax:
Common short form:
``` kotlin
{ a -> ... } // one parameter
{ a, b -> ... } // two parameters
{ (a, b) -> ... } // a decomposed pair
{ (a, b), c -> ... } // a decomposed pair and another parameter
{ ((a, b), c) -> ... } // ??? a decomposed pair whose first component is a pair
```
No return type nor receiver type in the short form:
``` kotlin
{ a: A -> ... } // one parameter
{ a, b: B -> ... } // two parameters
{ (a, b: B) -> ... } // a decomposed pair
{ (a, b): Pair<A, B> -> ... } // a decomposed pair
{ (a, b: B), c -> ... } // a decomposed pair and another parameter
{ ((a, b), c: C) -> ... } // ??? a decomposed pair whose first component is a pair
```
> (BAD OPTION) To disambiguate, we could demand a prefix:
``` kotlin
{ fun Recv.(((a: A, b: B): Pair<A, B>, c: C): Pair<Pair<A, B>, C>): R -> ... } // ??? a decomposed pair whose first component is a pair
{ fun (((a: A, b: B): Pair<A, B>, c: C): Pair<Pair<A, B>, C>): R -> ... } // ??? a decomposed pair whose first component is a pair
{ fun ( ((a, b), c) ): R -> ... } // ??? a decomposed pair whose first component is a pair
{ fun (((a, b), c: C)) -> ... } // ??? a decomposed pair whose first component is a pair
{ fun (((a, b), c): Pair<Pair<A, B>, C>) -> ... } // ??? a decomposed pair whose first component is a pair
```
Rather hairy.
But we have this form coming (needed for local returns):
``` kotlin
foo(fun(): R {
return r // local return
})
```
We can't omit return type in this form. But we use it only when we need return type/receiver type:
``` kotlin
fun Recv.(((a: A, b: B): Pair<A, B>, c: C): Pair<Pair<A, B>, C>): R { ... } // a decomposed pair whose first component is a pair
fun (((a: A, b: B): Pair<A, B>, c: C): Pair<Pair<A, B>, C>): R { ... } // a decomposed pair whose first component is a pair
fun ( ((a, b), c) ): R { ... } // ??? a decomposed pair whose first component is a pair
fun (((a, b), c: C)): R { ... } // ??? a decomposed pair whose first component is a pair
fun (((a, b), c): Pair<Pair<A, B>, C>): R { ... } // ??? a decomposed pair whose first component is a pair
fun (a) {} // return type is Unit
```
Difference from normal functions: we can omit parameter types, we can omit the name (don't have to).
Difference from lambdas: can specify return type and receiver type + returns are local.
### Quick summary of syntactic changes
- functions
- allow multi-declarations in parameters
- allow functions as expressions (anonymous or named)
- lambdas
- allow multi-declarations in lambda parameters
- no return type/receiver type in lambda parameters, use anonymous function instead
### Grammar
TODO
## PSI changes
Create a common superclass for lambdas and anonymous functions, most clients shouldn't notice the change
## Front-end checks and language rules
New concept introduced: "function expression" (looks like a function declaration, but works as an expression) as opposed to "lambda" (both are special cases of "function literal").
### Function call sites
From the outside a multi-declared parameter is seen as one parameter of the specified type:
``` kotlin
foo(pair) // caller can not pass two separate values here
```
No changes to the call-site checking are required.
### Function declaration sites
Function *declarations* are not allowed to omit types of their parameters:
``` kotlin
fun foo((a, b): Pair<A, B>) {...} // type is required
```
Types of individual components of the multi-declarations are optional:
``` kotlin
fun foo((a: A, b: B): Pair<A, B>) {...} // individual types of `a` and `b` are not required
```
Default values are only allowed for whole parameters, not for individual components:
``` kotlin
fun foo((a, b): AB = AB(1, 2)) {...}
```
All names in the parameter list belong to one and the same namespace:
``` kotlin
fun foo((a, b): AB, a: A) // redeclaration: two variables named `a`
```
One can use components of previously declared parameters in default values:
``` kotlin
fun foo((a, b): AB, c: C = C(a, b)) {...}
```
A parameter can be decomposed iff there are appropriate component functions available at the declaration site:
``` kotlin
fun Int.component1() = 1
fun Int.component2() = 1
fun foo((a, b): Int) {...}
```
other wise it's an error.
Component functions must be checked against the declared types of component parameters if they are present:
``` kotlin
fun foo((a: String, b): Int) {...} // error: Int.component1()'s return type is Int, incompatible with String
```
### Function expressions
Function expression syntax differs from function declaration syntax in the following ways:
- function name can be omitted
- consequently, receiver type can precede the parameter list directly
- type parameters are not allowed
- `where` clause is not allowed
- parameter types can be omitted (even for decomposed parameters)
- parameter default values are not allowed
- varargs are allowed, but useless (warning issued)
NOTE: local returns are allowed in function expressions without qualification.
ISSUE: when a function expression is inlined, unqualified returns must remain local. Wouldn't this confuse the reader?
NOTE: function expression can not be passed to a function call outside the parentheses
### Lambda expressions
In a lambda, only parameters (possibly decomposed) and their types can be specified. There's no way to explicitly specify the return type or receiver type. Those have to be inferred, otherwise function expression must be used.
TODO: support qualified returns in lambdas (when return type is unknown, nad has to be inferrred).
### Nested multi-declarations
Example:
``` kotlin
val (a, (b, c)) = abc // e.g. of type Pair<A, Pair<B, C>>
```
This translates to
```
tmp1 <- abc
a <- tmp1.component1()
tmp2 <- tmp1.component2()
b <- tmp2.component1()
c <- tmp2.component2()
```
If some of the types of `a`, `b` or `c` are specified, teh front-end verifies that respective component fucntion results match the expected types.
Biggest issue: type inference for function literals.
Expected type known entirely:
``` kotlin
fun foo((Pair<A, Pair<B, C>>) -> Unit) {}
foo { (a, (b, c)) -> ... }
```
In this case all we need is check that appropriate component functions are available (and that their types match specifications, if any).
Expected type contains type parameters:
``` kotlin
fun <T> foo(t: T, (T) -> Unit) {...}
foo(ABC) {(a, (b, c)) -> ...}
```
In this case we can't check the component conventions before T is fully resolved to a type.
It seems that this does not impose any significant issues on the inference, and can go right before the normal type checking of the body of a lambda.
## Semantics and Back-end changes
TODO
- what is the Java name of this parameter: `(a, b): Pair<A, B>`?
- maybe `a_b`
- make components available in default parameter values
- create locals for components, assign values (on nested decompositions, avoid calling smae component twice)
- make sure that funciton expressions are inlined as well as lambda expressions
## IDE Changes
New intentions:
- Convert lambda <-> anonymous function (mind the returns!)
Affected functionality:
- Change signature
- Move lambda outside/inside parentheses
- Specify types explicitly in a lambda (use conversion to anonymous function)

View File

@@ -0,0 +1,136 @@
# Secondary constructors
## Goal
Compatibility with Java hierarchies that demand multiple constructors, such as
- Android Views
- Swing dialogs
## Examples
With a primary constructor:
``` kotlin
class Foo(a: Bar): MySuper() {
// when there's a primary constructor, (direct or indirect) delegation to it is required
constructor() : this(Bar()) { ... } // can't call super() here
constructor(s: String) : this() { ... }
}
```
No primary constructor:
``` kotlin
class Foo: MySuper { // initialization of superclass is not allowed
constructor(a: Int): super(a + 1) { ... } // must call super() here
}
```
No primary constructor + two overloaded constructors
``` kotlin
class Foo: MySuper { // initialization of superclass is not allowed
constructor(a: Int): super(a + 1) { ... }
constructor() : this(1) { ... } // either super() or delegate to another constructor
}
```
## TODO
- [X] order of computation
- [X] property initializers
- [X] anonymous initializers
- [X] prefix for anonymous initializer
- [ ] is delegation allowed when no primary constructor is present?
- [X] prevent circular delegation of constructors
- [ ] Make `constructor` a soft keyword?
- [ ] Allow omitting parameterless delegating calls?
## Syntax for primary constructor
- There's a primary constructor if
- parentheses after class name, or
- there're no secondary constructors (default primary constructor)
- No parentheses after name and an explicit constructor present => no primary constructor
No primary constructor => no supertype initialization allowed in the class header:
``` kotlin
class Foo : Bar() { // Error
constructor(x: Int): this() {}
}
```
When a primary constructor is present, explicit constructors are called *secondary*.
Every class **must** have a constructor. the following is an error:
``` kotlin
class Parent
class Child : Parent { }
```
The error is: "superclass must be initialized". This class has a primary constructor, but does not initialize its superclass in teh class header.
## Syntax for explicit constructors
```
constructor
: "constructor" valueParameters (":" constructorDelegationCall) block
;
constructorDelegationCall
: "this" valueArguments
| "super" valueArguments
;
```
Passing lambdas outside parentheses is not allowed in `constructorDelegationCall`.
**??? CONSIDER: maybe we can make `constructor` a soft keyword.** That would mean simply that we can not have an annotation named `constructor` on class members, unless it's surrounded by square brackets.
## Rules for delegating calls
The only situation when an explicit constructor may not have an explicit delegating call is
- when there's no primary constructor **and** teh superclass has a constructor that can be called with no parameters passed to it
``` kotlin
class Parent {}
class Child: Parent {
constructor() { ... } // implicitly calls `super()`
}
```
If there's a primary constructor, all explicit constructors must have explicit delegating calls that (directly or indirectly) call the primary constructor.
``` kotlin
class Parent {}
class Child(): Parent() {
constructor(a: Int) : this() { ... }
}
```
**??? CONSIDER: maybe allow no explicit call when there is a constructor that can be called with no arguments passed?**
## Initialization code outside constructors
The primary constructor's body consists of
- super class intialization from class header
- assignments to properties from constructor parameters declared with `val` or `var`
- property initializers and bodies of anonymous initializers following in the order of appearence in the class body
If the primary constructor is not present, property initializers and anonymous initializers are conceptually "prepended" to the body
of each explicit constructor that has a delegating call to super class, and their contents are checked accordingly for definite
initialization of properties etc.
## Syntax for anonymous initializers
Anonymous initializer in the class body must be prefixed with the `constructor` keyword, without parentheses:
``` kotlin
class C {
constructor {
... // anonymous initializer
}
}
```
## Checks for constructors
All constructors must be checked for
- absence of circular delegation
- overload compatibility
- definite initialization of all properties that must be initialized