Comments 8
В последнем паззлере ошибка: вместо
Function<*>(){}()
должно быть Function<*>.(){}()
иначе не компилируется.0
antonkeks, в 13 объяснение какое-то совсем неверное. Какой еще компилятор? Какое еще «почему-то»? Какое еще «постарался, но не получилось»? Здесь нет вообще никакой неопределенности и работают исключительно стандартный джавовый механизм загрузки классов.
Котлиновский object — это статический INSTANCE филд в одноименном классе. Инициализация статических филдов происходит в момент инициализации класса, а инициализация классов в джаве отложенная и происходит при первом использовании. Соответственно, в момент первого «println(B.x)» начинает инициализироваться класс B. Ему, для того, чтобы создать этот INSTANCE, нужен класс C. Но в процессе инициализации C при попытке доступа к B.INSTANCE инициализация B не начинается повторно (сама jvm так работает). Соответственно, идет просто чтение еще не инициализированного поля B.INSTANCE (==null) и создание и запись нового объекта в C.INSTANCE. После чего мы выходим из инициализации класса C и спокойно уже обращаемся к его филду (INSTANCE) и создаем красивый, заполненный, B.INSTANCE.
А если заменить Any? на просто Any, то там тоже компилятор ничего дополнительно «пытаться» не начинает. Он просто в конструктор A вставляет проверку на аргумент т.к. он может прийти из джавы и не быть проверенным на стороне вызова. И именно эта проверка и падает. Банальное добавление -Xno-param-assertions в опции компилятора приводит к результату «C null» и с Any тоже.
p.s. По поводу инициализации классов. Вот простой пример, демонстрирующий, что ни бесконечной рекурсии, ни каких-либо ошибок не происходит.
Котлиновский object — это статический INSTANCE филд в одноименном классе. Инициализация статических филдов происходит в момент инициализации класса, а инициализация классов в джаве отложенная и происходит при первом использовании. Соответственно, в момент первого «println(B.x)» начинает инициализироваться класс B. Ему, для того, чтобы создать этот INSTANCE, нужен класс C. Но в процессе инициализации C при попытке доступа к B.INSTANCE инициализация B не начинается повторно (сама jvm так работает). Соответственно, идет просто чтение еще не инициализированного поля B.INSTANCE (==null) и создание и запись нового объекта в C.INSTANCE. После чего мы выходим из инициализации класса C и спокойно уже обращаемся к его филду (INSTANCE) и создаем красивый, заполненный, B.INSTANCE.
А если заменить Any? на просто Any, то там тоже компилятор ничего дополнительно «пытаться» не начинает. Он просто в конструктор A вставляет проверку на аргумент т.к. он может прийти из джавы и не быть проверенным на стороне вызова. И именно эта проверка и падает. Банальное добавление -Xno-param-assertions в опции компилятора приводит к результату «C null» и с Any тоже.
p.s. По поводу инициализации классов. Вот простой пример, демонстрирующий, что ни бесконечной рекурсии, ни каких-либо ошибок не происходит.
+3
github.com/fractalwrench/iokk — International Obfuscated Kotlin Contest
+1
Отлично поломал голову с данными головоломками!
0
Пожалуйста, объясните что происходит в 15 паззлере? Я спать нормально не могу после него.
0
Мне потребовалось около получаса чтобы понять, но, кажется, я смог!
Попытаюсь объяснить…
Есть вот такой код:
Тут вроде всё понятно, вызываем экстеншн-функцию, она возвращает kotlin.Unit, печатаем kotlin.Unit
Теперь магия! Берем и объявление someExtension подставляем прямо в место вызова, но название экстеншн-функции после «String.» убираем, она становится анонимной:
Эффект тот же — kotlin.Unit
Теперь осталось String заменить на Function<*> из паззлера и смысл паззлера станет понятен.
Попытаюсь объяснить…
Есть вот такой код:
fun String.someExtension() {}
val string = "some string".someExtension()
println(string)
Тут вроде всё понятно, вызываем экстеншн-функцию, она возвращает kotlin.Unit, печатаем kotlin.Unit
Теперь магия! Берем и объявление someExtension подставляем прямо в место вызова, но название экстеншн-функции после «String.» убираем, она становится анонимной:
val string = "some string".fun String.() {}()
println(string)
Эффект тот же — kotlin.Unit
Теперь осталось String заменить на Function<*> из паззлера и смысл паззлера станет понятен.
0
Sign up to leave a comment.
Kotlin puzzlers, Vol. 2: новая порция головоломок