Наткнулся тут на такую особенность Kotlin: return из функционального литерала выполняет выход из функции, в которой этот литерал объявлен. Например:
fun hasZeros(ints: List<Int>): Boolean {
ints.forEach {
if (it == 0)
return true // returns from hasZeros
}
return false
}
Если же нужно выйти только из этого блока кода, то используется return с квалификатором:
fun foo() {
ints.forEach lit@ {
if (it == 0)
return@lit // явная метка
//return@forEach // неявная метка – имя функции
print(it)
}
}
Меня интересует два вопроса:
— есть ли еще какой-то язык(-и) с таким же извращением?
— что вообще может твориться в голове, чтобы так сломать распространенное поведение?
P.S. Если тут есть кто-то из команды разрабатывающей Kotlin, то у вас в трансляции в javascript есть ошибка как раз в этом гулпом поведении.
JS-код который генерируется
hasZeroes_9mvhws$: function (arr) {
var tmp$0, tmp$1, tmp$2;
tmp$0 = arr, tmp$1 = tmp$0.length;
for (var tmp$2 = 0; tmp$2 !== tmp$1; ++tmp$2) {
var element = tmp$0[tmp$2];
hasZeroes_9mvhws$f$break: {
if (element === 0)
break hasZeroes_9mvhws$f$break;
}
}
return false;
}
Здравствуйте, std.denis, Вы писали:
SD> — есть ли еще какой-то язык(-и) с таким же извращением?
unix shell
там exit в скриптах замечательно работает ровно до тех пор, пока ты не позовешь оный скрипт через точку (ну там во время дебага посмотреть, какие он навыставлял переменные окружения, скажем), и у тебя вдруг опа — и консоль закрылась
Здравствуйте, std.denis, Вы писали:
SD>Наткнулся тут на такую особенность Kotlin: return из функционального литерала выполняет выход из функции, в которой этот литерал объявлен. Например: SD>
fun hasZeros(ints: List<Int>): Boolean {
SD> ints.forEach {
SD> if (it == 0)
SD> return true // returns from hasZeros
SD> }
SD> return false
SD>}
SD>Меня интересует два вопроса: SD> — есть ли еще какой-то язык(-и) с таким же извращением?
может немерле? в нем же тоже вроде некоторые statements сделаны через макросы
SD> — что вообще может твориться в голове, чтобы так сломать распространенное поведение?
ну начать надо с того, что это не функциональный литерал (aka лямбда-функция).
впринципе этим бы можно было бы и закончить, но я добавлю что если
forEach ints {
if (it == 0)
return true // returns from hasZeros
}
}
сильного удивления не вызывает, то что меняется от того, что мы напишем ints.forEach ?
Здравствуйте, std.denis, Вы писали:
SD>Меня интересует два вопроса: SD> — есть ли еще какой-то язык(-и) с таким же извращением?
Именно return? Потому что break с меткой встречается несколько чаще.
Здравствуйте, std.denis, Вы писали:
SD>Меня интересует два вопроса: SD> — что вообще может твориться в голове, чтобы так сломать распространенное поведение?
Мне оно кажется логичным. Почему для if () {} return возвращает из функции, а для myIf () {} return возвращает из блока? Вот это как раз нелогично. В Kotlin-е это поведение позволяет делать "свои" операторы вроде foreach и др., ведущие себя подобно встроенным в язык конструкциям.
fun hasZeros(ints: List<Int>): Boolean {
SD> ints.forEach {
SD> if (it == 0)
SD> return true // returns from hasZeros
SD> }
SD> return false
SD>}
SD>Если же нужно выйти только из этого блока кода, то используется return с квалификатором: SD>
fun foo() {
SD> ints.forEach lit@ {
SD> if (it == 0)
SD> return@lit // явная метка
SD> //return@forEach // неявная метка – имя функции
SD> print(it)
SD> }
SD>}
SD>Меня интересует два вопроса: SD> — есть ли еще какой-то язык(-и) с таким же извращением?
RETURN n был еще в Фортране 4. Правда, в приведенном коде поведение return-а больше похоже на break label из Java. А в Фортране выполнялся возврат из подпрограммы на помеченный оператор.
Сам я подобным никогда не пользовался.
Здравствуйте, vsb, Вы писали:
SD>>Меня интересует два вопроса: SD>> — что вообще может твориться в голове, чтобы так сломать распространенное поведение?
vsb>Мне оно кажется логичным. Почему для if () {} return возвращает из функции, а для myIf () {} return возвращает из блока? Вот это как раз нелогично. В Kotlin-е это поведение позволяет делать "свои" операторы вроде foreach и др., ведущие себя подобно встроенным в язык конструкциям.
Оно может и логично, но привычного здесь мало, собтсвенно ошибка в жэес коде об том и говорит — товарищи обманули сами себя.
A>ну начать надо с того, что это не функциональный литерал (aka лямбда-функция).
А что это как не лямбда-функция? Мне видится это лямбдой, которая передана методу расширения fun <T> Iterable<T>.forEach(action: (T) -> Unit) . Соответственно и return выглядит как return из лямбды.
vsb>Мне оно кажется логичным. Почему для if () {} return возвращает из функции, а для myIf () {} return возвращает из блока? vsb>Вот это как раз нелогично. В Kotlin-е это поведение позволяет делать "свои" операторы вроде foreach и др.
Да, хорошая точка зрения.
Видимо после Swift непривычно, ведь в свифте doSomething { () -> Void in ... } (запись, похожая на анонимную функцию в Kotlin) и doSomething { ... } (похожая на лямбда-выражение в Kotlin) – одно и то же, разной степени сокращенности
P>RETURN n был еще в Фортране 4. Правда, в приведенном коде поведение return-а больше похоже на break label из Java. А в Фортране выполнялся возврат из подпрограммы на помеченный оператор. P>Сам я подобным никогда не пользовался.
Да, return с квалификатором вполне понятен. Меня удивило именно поведение без квалификатора, которое разное для лямбда-функции и анонимной функции.
Здравствуйте, Abyx, Вы писали:
A>может немерле? в нем же тоже вроде некоторые statements сделаны через макросы
В Немерле нет return-а. В Немерле есть макра return. Реализована она на базе оператора выхода из именованного блока.
При этом этот макрос внутри функций ведет себя обычным образом. Посему написать функцию которая похоже на оператор нельзя. Но можно написать макрос который ведет себя как как хочет его автор.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.