как-то так? `fun KProperty0<*>.isInitialized...
# russian
u
как-то так?
fun KProperty0<*>.isInitialized() = (this.apply { isAccessible = true }.getDelegate() as MyDelegate).isInitialized()
e
в чем необходимость
.apply { isAccessible = true }
?
я могу как-то ограничить применимость этой экстеншн функции только к определенному типу делегатов?
u
в чем необходимость
.apply { isAccessible = true }
?
это нужно, потому что вообще говоря, делегат это деталь реализации свойства, так же как и private backing field деталь реализации неделегированного свойства
т.е. тут нужно обойти инкапсуляцию, и для этого в рефлекшне (и в Kotlin, и в Java) нужно явно вызывать
isAccessible = true
я могу как-то ограничить применимость этой экстеншн функции только к определенному типу делегатов?
вроде нет, потому что в типе ссылки на свойство не закодировано ничего про тип её делегата (опять же, потому что это деталь реализации, может поменяться при перекомпиляции и т.д.)
e
а возможно в будущем сделать встроенный в язык типизированный доступ к делегатам свойств не через рефлекшн? это вообще технически возможно? мб такой вариант даже обсуждался?
что-то типа mProperty::delegate
e
Та же проблема с инкапусляций. Вы всегда можете явно определить public свойство delegate нужного вам типа как написал выше @miha-x64
e
я бы сказал, что это делает код менее понятным и читаемым, потому что где-то идет работа со свойством, а где-то с его делегатом и их связь не понятна с ходу;
но основная проблема возникает если таких свойств много в одном классе
получается мешанина из свойств и их делегатов, это все выглядит весьма некрасиво и неудобно
я изначально пытаюсь с помощью делегатов уйти от использования nullable потому что свойство один раз устанавливается и потом в одном месте очищается в конце работы. и я хочу очистить код от работы с nullability. но иногда нужно при этом иметь возможность определить настал ли уже момент инициализации или еще нет. вот тут нужен доступ к делегату
поэтому если делегаты объявлять в классе явно, то это практически нивелирует эффект
e
А можете дать небольшой пример кода, который вы пытались написать? Где и как нужно проверять “настал ли момент“?
e
да. вот например сейчас пишу класс работы с камерой в андроид. для камеры необходима куча разных сущностей, которые должны быть инициализированы в определенной последовательности.
и вот у меня есть свойство
private var mCameraParameters: Camera.Parameters by disposablePropertyManager.disposable()
оно устанавливается при открытии экрана с камерой.
и есть метод переключения режима вспышки
Copy code
override fun setFlash(flashMode: FlashMode) {

        if (this::mCameraParameters.hasValue()) {
            val flashes = mCameraParameters.supportedFlashModes
            val internalFlash = flashMode.cameraConstant
            if (flashes != null && flashes.contains(internalFlash)) {
                mCameraParameters.flashMode = internalFlash
                this.flashMode = flashMode
            } else {
                val currentFlash = this.flashMode.cameraConstant
                if (flashes == null || !flashes.contains(currentFlash)) {
                    mCameraParameters.flashMode = Camera.Parameters.FLASH_MODE_OFF
                    this.flashMode = FlashMode.Off
                }
            }

            mCamera.parameters = mCameraParameters

        } else {
            this.flashMode = flashMode
        }
    }
что-то в таком роде
e
Мне кажется это как раз то место где удобно иметь nullable свойство
e
в начале мне нужно понять инициализированы ли уже параметры камеры, и делать разную логику в этом случае
да, было бы удобно, если бы работали смарт касты
а они не работают, потому что поле var
e
В Kotlin-то, в отличие от Java, проблем с nullablity нет. Если у вас
private var mCameraParameters: Camera.Parameters?
, то оно будет отлично работать и Котлин не даст вам случайно NPE получить, забыв что оно nullable
mCameraParams?. let { … }
отлично работает чтобы сделать что-то если оно установлено
e
да, возможно это действительно лучший способ в данном случае.
но все-таки
mCameraParams?.let {} ?: {}
выглядит не так наглядно как
if (params != null) {} else {}
e
Rule of thumb: В Kotlin не надо пытаться избавиться от nullability. В Kotlin сделано всё, что nullable типы были не проблемой, а фичей
e
да, согласен. и меня не нулабилити в данном случае беспокоит, а снижение наглядности и читабельности кода
e
^^ выглядит не так наглядно только 1-ый месяц написания кода на Kotlin. Потом “нейронная сеть” обучается распознавать что это эквивалентно
e
подбивает написать
val params = this.params
и использовать класический наглядный if-else
😃 возможно, спасибо
e
Подавляйте в себе это желание, и через некоторое время
?.let { ... }
не будет вам казаться непонятным
e
да он понятный
скорее ?: {} не очень на else смахивает 😃
выглядит как обработка ошибки или какой-то особой ситуации. а на самом деле это один из равноценных вариантов
@elizarov а как быть если нужно два свойства проверить? три? вложенные ?.let вообще неприятно выглядят же
кроме того могу ли я как-то написать блок, а не один вызов после
?:
? я получаю ошибку что ожидается
Unit
, а не
() -> Unit
e
run { ... }
если нужен блок
e
да, мне уже в чате тоже подсказали про run
но все же
} ?: run {
выглядит имхо сильно менее читабельно и очевидно чем
} else {
.
а в команде котлин не обсуждался вариант аля Swift:
if (let localA = a, let localB = b) {} else {}
?
имхо это было бы удобнее и читабельнее всех обсуждаемых вариантов
при этом изменение не ломает существующий код и семантики
e
Ну вот для when похожий запрос есть: https://youtrack.jetbrains.com/issue/KT-4895
Упаковывать много всего в один if вроде не планируется. Есть ощущение, что это не помогает улучшать читаемость кода
e
@elizarov если в одном if не давать возможность объявления сразу нескольких локальных значений, то смысл этого изменения теряется. в свифте одновременно объявляются алиасы и происходит уход от нулабилити в теле if-а. это как раз идеально ложится на мой и многие подобные запросы: синтаксис остается максимально похож на традиционный с if - else при этом нет проблем со смарт кастами. и что самое главное это неломающее изменение и в каких-то более сложных случаях чем просто проверка нескольких свойств на null все будет прекрасно работать и без применения такой новой конструкции
e
Это не ложится идеологически в DRY (Do not repeat yourself) идеологию, а так же создает множественные присвания на одной стороке, что тоже bad style в Котлине. Что делать с вашим и подобными вопросами не понятно. Было бы интересно посмотреть на какой-нибудь реальный код где вам приходится такое делать. Что-нибудь открытое есть?
m
Copy code
val x = x
val y = y
if (x != null && y != null) {
вроде тоже противоречит DRY. 🙃
e
@elizarov, @miha-x64 прав. именно такой код и приходится писать каждый раз когда есть проверка 2 и более свойств. и я согласен с ним, что в данном случае лаконичное и удобное объявление в одной строке выглядит меньшим злом, чем тот код, что он привел. по поводу примеров, я уверен, что их огромное множество у любого кто пишет на котлине по крайней мере под андроид. если нужно, я могу накидать со временем много таких примеров. у меня проект только начал переводиться на котлин, поэтому пока их не много, но они появляются со стабильной регулярностью по мере продвижения рефакторинга.
m
Но конструкция типа
Copy code
if (val x != null && val y != null) {
кажется мне категорически нелогичной. 1) Ускоренное вычисление. Если x == null, то y проверяться не будет… Но локальная переменная должна быть присвоена? 2) Должны ли быть эти переменные видны в последующих else if … else? Если да, то почему? Если нет, то почему? Иногда мне кажется более логичным делать какую-то пометку, чтобы свойство автоматически однократно считавалось и на чтение вело себя как локальная переменная. Но там возникнет не меньше вопросов…
e
я завел issue с данным предложением в трекер, чтобы оно было доступно большему числу людей для обсуждения
надеюсь, это не дубликат
приглашаю всех заинтересованных лиц внести свои правки и присоединиться к обсуждению )
m
it also keep ability to access source property in any way (read/write)
Если let ведёт себя как val, то записывать как раз никто не позволит, только читать.
e
там же имя можно дать другое у алиаса отличное от исходного
m
а, ок
e
Собирайте примеры, когда на них натыкаетесь. Мы наверное разный код пишем, но я вот реально не припомню за последние полгода чтобы я наталкивался на необходимость иметь что-то такое в языке. Как-то просто не возникает вот такого кода by design
e
@elizarov т.е. не возникает необходимость сделать более одной null проверки в одном блоке?
примеры буду скидывать в issue по мере их появления
👍 1
e
Неа. Может у меня так state по объектам очень хорошо инкапсулирован или просто другого рода задачи решаю, но в том коде который пишу я — не возникает
Вот конструкции вида
variable?.let { doSomethingWithIt }
возникают время от времени, а чтобы несколько — нет
e
@elizarov предлагаю добавить из моего issue линк на KT-4895, это немного похожие задачи и как минимум по синтаксису, если делать, они должны будут совпадать
(как related)