@kotlin_lang

Страница 474 из 982
Евгений
02.01.2018
21:03:23
не подкажете что не так?

вроде и потокобезопасно, и значение инициализируется

Quantum Harmonizer
02.01.2018
21:04:12
https://t.me/horsecups/194129
Локальная переменная нуллабельного типа M?, а нужно вернуть M.

Евгений
02.01.2018
21:04:58
так если она null то метод transformMetadata(dataStream.getMetadata()) её инициализирует

Google
Евгений
02.01.2018
21:05:11
вроде слышал что анализатор кода котлина должен такое понимать

точнее компилятор

Quantum Harmonizer
02.01.2018
21:06:19
Мда, интересно. Можно попробовать лапшу вроде return metadata ?: transform...(...).also { metadata = it }

Евгений
02.01.2018
21:06:58
сама конструкция

если написать так: if (metadata == null) { metadata = transformMetadata(dataStream.getMetadata()) } return metadata

Quantum Harmonizer
02.01.2018
21:07:54
А вообще, видится мне, что вместо всей этой констркции можно использовать lazy. Там и потокобезопасная публикация будет.

Евгений
02.01.2018
21:08:29
то после инициализации, но перед возвратом, значение могут обнулить в теории из другого потока

а с локальной переменной такой проблемы нет

Quantum Harmonizer
02.01.2018
21:09:34
Есть другая: несколько потоков могут запустить transformMetadata и обновлять поле metadata под гонкой.

Поэтому если там реально многопоточка, лучше использовать AtomicReference или AtomicFieldUpdater.

Евгений
02.01.2018
21:10:07
это может быть, но к NPE это привести не сможет

нене, пока на многопоточность можно забить

Google
Quantum Harmonizer
02.01.2018
21:10:44
Повторюсь, видится мне, что тут можно взять lazy

Евгений
02.01.2018
21:11:02
тут просто странно, очевидно корректный код - а компилятор не может понять что все ОК

Жабра
02.01.2018
21:13:37
Джун — это человек, который хорошо знает язык+стдлиб. Мид может разработать что-то годное. Сениор — спроектировать и разработать что-то большое, шустрое, надёжное.
Почти согласен, но этого реально многовато для Джуна. В основном, понимание многих тонкостей приходит со временем и опытом.

А у Джуна, обычно, опыта не так много

Quantum Harmonizer
02.01.2018
21:13:59
Евгений
02.01.2018
21:15:13
кто-то заведет багу, или мне завести?

Quantum Harmonizer
02.01.2018
21:16:19
ха-ха. Если поставить M : Any, то смарт-каст происходит.

Но, тем не менее, это баг.

Alexander
02.01.2018
21:31:20


Всё кастуется нормально

Может kotlin надо обновить?

Евгений
02.01.2018
21:34:47
<kotlin.version>1.2.10</kotlin.version>

Quantum Harmonizer
02.01.2018
21:35:48
Может kotlin надо обновить?
Нет, это прокатывает только с нуллабельным type-параметром

Евгений
02.01.2018
21:37:34
хм. проверил, у меня со String та же фигня

Alexander
02.01.2018
21:37:54
А, да, действительно, попробовал с T, не кастится

Kirill
02.01.2018
21:39:59
кажется, понятно почему такое может быть

Евгений
02.01.2018
21:40:00
а не. со String норм

Alexander
02.01.2018
21:40:38
abstract class SomeClass<out T : Any>

вот так всё нормально

кастуется

Google
Kirill
02.01.2018
21:41:22
иначе T (в примере M) может быть nullable типом

Alexander
02.01.2018
21:41:52
в kotlin out T по умолчанию будет унаследовано от Any?

Kirill
02.01.2018
21:43:10
в kotlin out T по умолчанию будет унаследовано от Any?
тут не очень понятно. это вопрос или утверждение :)

Alexander
02.01.2018
21:43:35
кажется, таки от Any?
да, именно так и написал, хз почему телеграмм неправильно подсветил)

вот, хотя бы на такое исправил

Kirill
02.01.2018
21:45:21
и подсветка сразу починилась )

Евгений
02.01.2018
21:51:53
не совсем понял. это таки баг или нет?

Alexander
02.01.2018
21:52:37
нет. просто в твоём случае класс M был унаследован от nullable Any

abstract class SomeClass<out T : Any>
? при таком объявлении смарткаст происходит правильно



Евгений
02.01.2018
21:58:35
а можно на пальцах сценарий когда словим NPE, если не указывать out M

Quantum Harmonizer
02.01.2018
22:10:23
не совсем понял. это таки баг или нет?
Это баг. В последней строке res гарантировано M, вне зависимости от того, нуллабельно M или нет.

Alexander
02.01.2018
22:10:37
Указать надо не out M, а : Any весь фокус именно здесь. Твой тип M допускал Any?, поэтому даже в результате смарткаста всё равно мог получиться nullable тип; в моём варианте nullabillity не допускается что и позволяет сделать смарт-каст правильно;

Евгений
02.01.2018
22:14:45
хотя да. если M нулабельно, то какая разница это M или "M?" ?

чет я запутался

Google
Евгений
02.01.2018
22:17:05
если переменная M может принимать значение null, то пропадает смысл разделять "M" и "M?"

Alexander
02.01.2018
22:20:18


? мой вариант не позволяет вернуть null из класса наследника



Евгений
02.01.2018
22:21:34
а если без out?

Alexander
02.01.2018
22:21:39
? твой вариант позвоялет вернуть null, хотя transform и объявлен как T

out здесь не при чём

Евгений
02.01.2018
22:22:25
кинь код пожалуйста не картинкой

Alexander
02.01.2018
22:22:52
abstract class SomeClass<T> { private var metadata: T? = null fun getSmth(): T { var res = metadata if (res == null) { res = transform() metadata = res } return res } abstract fun transform(): T } class Abv : SomeClass<String?>() { override fun transform(): String? { return null } }

Евгений
02.01.2018
22:22:56
спасибо

Admin
ERROR: S client not available

Alexander
02.01.2018
22:23:20
это твой вариант. у тебя может случиться NPE после transform()

Евгений
02.01.2018
22:25:39
тоесть компилятор "Бдит" чтобы getSmth() не вернул null, но в то же время спокойно разрешает вернуть null из transform()

хотя оба возвращают T

и кстати если у меня у наследника T = String? то null это корректное значение для getSmth()

Kirill
02.01.2018
22:31:04
тоесть компилятор "Бдит" чтобы getSmth() не вернул null, но в то же время спокойно разрешает вернуть null из transform()
если ты скажешь, что class Abv : SomeClass<String>, то из transform нельзя будет вернуть null

Евгений
02.01.2018
22:32:08
да, но мы же сейчас о случае с "String?"

Alexander
02.01.2018
22:32:35
тоесть компилятор "Бдит" чтобы getSmth() не вернул null, но в то же время спокойно разрешает вернуть null из transform()
ну отслеживать все теоретические переопределения компилятору уже не под силу))

Kirill
02.01.2018
22:32:41
тогда можно, да. ибо null — допустимое значение типа String?

Google
Евгений
02.01.2018
22:33:20
почему?

Alexander
02.01.2018
22:34:07
У тебя же возвращаемый тип T, а не T?. А типы в котлине устроены так что T? это предок T. Поэтому кастовать от nullable к non-nullable можно, а вот в обратную сторону уже нельзя

как можно скастовать собаку к животному, но не животное к собаке

Евгений
02.01.2018
22:36:28
а как сюда в чат вставить форматированный код?

Alexander
02.01.2018
22:36:44
три `

Kirill
02.01.2018
22:36:44
три символа '`'

Евгений
02.01.2018
22:36:58
спс

abstract class SomeClass<T> { private var metadata: T? = null open fun getSmth(): T { var res = metadata if (res == null) { res = transform() metadata = res } return res } abstract fun transform(): T } class Abv : SomeClass<String?>() { override fun getSmth(): String? { return null } override fun transform(): String? { return null } }

вот так вполне легально , в переопределенном методе возвращаем null

Alexander
02.01.2018
22:38:44
нет

для компилятора open не гарантия того что его кто-то переопределит

тип T может быть nullable

Евгений
02.01.2018
22:40:11
он позволил так переопределить. значит и в базовом легален null

Alexander
02.01.2018
22:40:13
поэтому в теории возможна ситуация в которой я просто не переопределю метод getSmth но параметром у меня будет nullable

и система типов поломается

в базовом классе всё равно же есть место для ошибки

Евгений
02.01.2018
22:41:05
abstract class SomeClass<T> { private var metadata: T? = null open fun getSmth(): T { var res = metadata if (res == null) { res = transform() metadata = res } return res as T } abstract fun transform(): T } class Abv : SomeClass<String?>() { override fun getSmth(): String? { return null } override fun transform(): String? { return null } }

вот так компилируется. а на самом переопределении - не ругается

Alexander
02.01.2018
22:42:10
только пишет Unchecked cast: T? to T

типа может поломаться в рантайме и сам себе злой буратино будешь)

Евгений
02.01.2018
22:48:16
логика такая. есть 2 варианта развития событий: 1) если T - не nullable, то transform() не может вернуть null, значит и getSmth() Тоже не может вернуть null 2) если T - nullable , то transfrom() тоже может вернуть null, но тогда и getSmth() должен тоже "мочь" вернуть null , т.к. в обоих методах возвращаемое значение T - nullable, и всякое различие между "T" и "T?" стирается и не имеет смысла. вот допутстим далее идет такой код abstract class SomeClass<T> { private var metadata: T? = null open fun getSmth(): T { var res = metadata if (res == null) { res = transform() metadata = res } return res as T } abstract fun transform(): T } class Abv : SomeClass<String?>() { override fun getSmth(): String? { return null } override fun transform(): String? { return null } } class C { init { val a = Abv() println(a.getSmth().length); // <-- ошибка! } } все равно тут нужно проверять на null, а значит не важно что реализация getSmth() пытается "защитить" от возврата null - от этой защиты все равно нет толку

Alexander
02.01.2018
22:52:55
Ну так подожди. В последнем примере ты явно создаёшь объект класса с дженериком nullable типа. Конечно же он сможет вернуть null, о чём тебе ide и говорит когда ты вызываешь length.

Страница 474 из 982