Как стать автором
Обновить

Комментарии 19

Спасибо за статью!
Получается, что поле, объявленное как val, поменяло значение в процессе исполнения кода. Почему так? Думаю, что это недочёт компилятора Kotlin, и в будущем, возможно, такое не скомпилируется, но на сегодняшний день всё так, как есть.

Вышло, даже, немного забавнее, похоже и вправду баг.
class TestA {
    constructor()
    init {
        immutableString = "44"
    }
    val immutableString = "42"
}

class TestB() {
    init {
        immutableString = "44"
    }
    val immutableString = "42"
}


TestA компилируется, TestB — нет. Если верить просмотрщику байткода в IDE, байткод генерируется одинаковый.
Может, стоит зарепортить на youtrack.jetbrains.net/issues/KT?
Случай и правда любопытный — зарепортил его. Может получу какие либо пряснения к данному конкретному случаю. Но скорее всего это проблема и ее надо вылечить
Замечу также, что результатом будет первичное присвоение. То есть, код в блоке инициализации просто не выполняется.
Это не так. Из блока инициализации мы вызываем метод showTestParam(), который использует значение testParam, присвоенное ему в блоке init. Вывод логов мы видим. Так что вся логика init блока отрабатывает
Точно, сам в этом убедился. Определенно это какой-то баг.
Даже еще интереснее!
class ThreadTest {
  constructor() {
    println("c1")
  }
  init {
    println("init_start, $bul")
    bul = false
    println("init_end")
  }
  val bul: Boolean = true
}

Не компилируется!
Если исследовать порядок выполнения, то видим, что код выполняется сверху вниз
fun main(args: Array<String>) {
  val a = ThreadTest()
  println(a.bul)
}

class ThreadTest {
  constructor() {
    println("constructor")
  }
  init {
    println("init_start")
    bul = f1()
    println("init_end")
  }

  private fun f1(): Int {
    println("assign1")
    return 3
  }

  val bul = f2()

  private fun f2(): Any {
    println("assign2")
    return 2
  }
}


Результат:

init_start
assign1
init_end
assign2
constructor
2
более того, если байт код того, что компилится мы преобразуем в java код, то компилятор на этот код будет ругаться. И еще: если в этих котлиновских классах объявление val поля сделать до init блока, то компилятор ругаться будет
Причем в этом коде оба присвоения будут в конструкторе. Но по факту срабатывать будет только последнее. Каким образом компилятор вымарывает первое срабатывание — большой вопрос.
И еще огромный вопрос вот в чем — а не может ли такого быть, что переменная объявляется фактически не финальной? Или финальная переменная действительно каким-то образом переписывается (хотя в JSR 133 это вроде невозможно)
То есть, могу ли я, имея несколько потоков, ухитриться получить одним из потоков первое значение вместо второго?
Думаю, что это тема для более глубокого исследования. И еще можно подождать что ответят на репорт.
Если смотреть на этот процесс как бы снаружи, то здесь единственное отличие от Java — отсутствие ключевого слова new при вызове конструктора.

Можно вспомнить про возможность передавать именованные параметры в конструкторы и функции. Полезно если несколько параметров опциональные и нужно передать значение для 2 или 3го (например какой-нибудь вызов joinToString(prefix = "")). Taк же может помочь в ревью, когда в метод\конструктор передаются однотипные данные а подсказок студии нет(к примеру пачка true\false)
class User(val name: String, val age: Int)
// порядок передачи параметров уже не важен
val mike = User(age = 25, name = "Mike")
Да, безусловно об этом стоило упомянуть — это очень удобная фишка Kotlin. Таким образом, создавая такой объект в Kotlin-коде мы можем этим воспользоваться. Для создания такого объекта из Java-кода все остается как обычно

Присоединяюсь — очень ценная статья для начинающих в Kotlin. Ждем продолжения.


Подскажите, а в вашей компании — FunCorp — насколько активно используется Kotlin?

Kotlin у нас используется наравне с Java. По моему личному мнению, есть еще все же вещи, которые удобнее (во всяком случае пока) писать на Java — об этом я буду писать в следующих статьях. Однако, это довольно субъективно.
С интересом прочитал, хоть ничего нового и не узнал. Буду ждать новые статьи.

Думаю, стоило бы упомянуть, что при использовании @JvmOverloads компилятор создаёт набор конструкторов с разным количеством аргументов.
Да, это так. Спасибо за коммент — это пояснение точно будет нелишним
Такого рода статьи значительно облегчают переход на Kotlin.
Спасибо Вам за статью.
Давайте сразу копать Kotlin во все стороны! Отдыхать не обязательно.
Все же отдохнуть немного придется. Написание подобных материалов требуют времени и подготовки. Однако комментарии от заинтересованных людей, конечно, мотивируют на ускорение подготовки нового материала
Хорошая статья! Ждём продолжения!

Стоило упомянуть, что в Kotlin нет свойств, а только поля. Это имеет прямое отношение к val и var параметрам первичного конструктора.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий