blob: d52dd78978759f55535695682ec3c571f09fa517 [file] [log] [blame] [view] [edit]
# 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 :(
}
```