From 0dc1448d696b8d06f31d41e369faddc0160f4d86 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 31 Oct 2014 13:15:57 +0300 Subject: [PATCH] Secondary constructors specs --- spec-docs/secondary-constructors.md | 134 ++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 spec-docs/secondary-constructors.md diff --git a/spec-docs/secondary-constructors.md b/spec-docs/secondary-constructors.md new file mode 100644 index 00000000000..8ecbce01f17 --- /dev/null +++ b/spec-docs/secondary-constructors.md @@ -0,0 +1,134 @@ +# 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 + +- [ ] is delegation allowed when no primary constructor is present? +- [ ] 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 + : modifiers "constructor" valueParameters (":" constructorDelegationCall) block + ; + +constructorDelegationCall + : "this" valueArguments + | "super" valueArguments + ; +``` + +Passing lambdas outside parentheses is not allowed in `constructorDelegationCall`. + +## 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() { ... } +} +``` + +## 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 `init` keyword, without parentheses: + +``` kotlin +class C { + init { + ... // 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 +- absence of non-empty super call for enum constructors + +No secondary constructors can be declared for +- traits +- objects (named, anonymous, and default) +- bodies of enum literals + +Data classes should have a primary constructor