
Евгений
02.01.2018
21:03:23
не подкажете что не так?
вроде и потокобезопасно, и значение инициализируется

Quantum Harmonizer
02.01.2018
21:04:12

Евгений
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

Евгений
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

Alexander
02.01.2018
21:43:35
вот, хотя бы на такое исправил

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

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

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

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

Quantum Harmonizer
02.01.2018
22:10:23

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

Евгений
02.01.2018
22:13:18
не вижу принципиальной разницы.

Quantum Harmonizer
02.01.2018
22:14:11

Евгений
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

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

Alexander
02.01.2018
22:32:35

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

Alexander
02.01.2018
22:32:49

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.