169 похожих чатов

А может есть какой-то вариант описания в котлине, что бы

не нужно было ничего возвращать?

21 ответов

18 просмотров

Я предположу, что для Джавы вы можете просто сделать перегрузку setOnRequest(Runnable) (на стороне джавы вроде так и не завезли хороший аналог () - > Unit среди функциональных интерфейсов, поэтому там Runnable) или какой-то свой fun interface сделать, если не хочется брать Runnable

Alex Levin
Я предположу, что для Джавы вы можете просто сдела...

Вот, кстати, если сделать fun interface, то оно и в Kotlin и в Java хорошо будет выглядеть.

Roman-De Автор вопроса
Alex Levin
Я предположу, что для Джавы вы можете просто сдела...

Ну тут больше было просто интересно. Примерно разобрался в причинах и механизме. Понял как и что именно гуглить. Почитаю сам дальше. Всем спасибо :)

Roman De
Ну тут больше было просто интересно. Примерно разо...

Ну общая идея скорее в том, что () -> Unit будет чем-то вроде KFunction0<Unit>. Unit это generic параметр, поэтому у нас нету лёгкой возможности сказать, что в этой ситуации Unit это просто void (собственно в Джаве самой по себе такая же проблема, из-за чего есть куча функциональных интерфейсов вроде Supplier, Consumer, BiConsumer, Function, BiFunction и тд). Как выше сказано, можно обойти с помощью более удобного метода для Джавы, либо с помощью fun interface, где просто будет возвращаемый тип у функции Unit (поскольку это не generic, то сможет понять, что это можно в void выставить)

Alex Levin
Ну общая идея скорее в том, что () -> Unit будет ч...

Похоже, это в объяснение в точку. Теперь я склоняюсь, что делать DSL на основе «fun interface» это «best practice»: https://t.me/kotlin_jvm/29912 Ну, понятно, что в Gradle есть Action<…> к которому прикручен «sam-with-receiver». Но во всех остальных случаях fun interface звучит интересно. Было бы интересно послушать «почему делать DSL на основе fun interface это плохая практика».

Vladimir Sitnikov
Похоже, это в объяснение в точку. Теперь я склоняю...

Ну например потому что не всем нужно чтобы это выглядело адекватно из джавы. А вообще для DSL, кажется достаточно ровно одного fun interface (собственно Action с ресивером, написанный на котлине).

Aλex Sokol
из котлина оно тоже выглядит хорошо

С этим не спорю, но в котлине при отсутствии готового fun interface проще написать T.() -> Unit

Vladimir Petraković
С этим не спорю, но в котлине при отсутствии готов...

Да, всё так. Понятно, что «если Java API неважно», то в fun interface смысла немного. А пока для меня звучит, что fun interface это и несложно, и Java будет неплохо выглядеть. Попробую действительно ли так получится.

Vladimir Sitnikov
Да, всё так. Понятно, что «если Java API неважно»,...

Имеет, если наследовать. В JS по-моему до сих пор наследовать от функции нельзя.

Vladimir Sitnikov
Да, всё так. Понятно, что «если Java API неважно»,...

Попробовал, для DSL работает вот такое, и обязательно -Xjvm-default=all (иначе в JVM lambda не работают и весь смысл теряется) fun interface Action<T>: (T) -> Unit { fun T.execute() override operator fun invoke(receiver: T) { receiver.execute() } } При таком Action работает и DSL в Kotlin, и вызовы в Java без return UNIT.Instance. Но есть. минус: стектрейсы получаются раза в 2 длиннее, чем при обычном T.() -> Unit DSL. Проблема в том, что fun invoke получае Вот стектрейс на простом DSL: at com.acme.test.realtime.ExampleTest$TestMapping$init$2$1$1$1$1.invoke(ExampleTest.kt:102) at com.acme.test.realtime.ExampleTest$TestMapping$init$2$1$1$1$1.invoke(ExampleTest.kt:44) at com.acme.mapping.scopes.PlainTablesScope.table(PlainTablesScope.kt:18) at com.acme.test.realtime.ExampleTest$TestMapping$init$2$1$1$1.invoke(ExampleTest.kt:44) at com.acme.test.realtime.ExampleTest$TestMapping$init$2$1$1$1.invoke(ExampleTest.kt:43) at com.acme.mapping.scopes.InstanceMappingScope.tables(InstanceMappingScope.kt:23) at com.acme.test.realtime.ExampleTest$TestMapping$init$2$1$1.invoke(ExampleTest.kt:43) at com.acme.test.realtime.ExampleTest$TestMapping$init$2$1$1.invoke(ExampleTest.kt:42) at com.acme.mapping.scopes.RdblConfigFileScope.instance(RdblConfigFileScope.kt:31) А вот стектрейс на Action<T> DSL: at com.acme.test.realtime.ExampleTest$TestMapping.init$lambda-8$lambda-7$lambda-6$lambda-5$lambda-4(ExampleTest.kt:102) at com.acme.Action.invoke(Action.kt:7) at com.acme.Action.invoke(Action.kt:3) at com.acme.mapping.scopes.PlainTablesScope.table(PlainTablesScope.kt:19) at com.acme.test.realtime.ExampleTest$TestMapping.init$lambda-8$lambda-7$lambda-6$lambda-5(ExampleTest.kt:44) at com.acme.Action.invoke(Action.kt:7) at com.acme.Action.invoke(Action.kt:3) at com.acme.mapping.scopes.InstanceMappingScope.tables(InstanceMappingScope.kt:24) at com.acme.test.realtime.ExampleTest$TestMapping.init$lambda-8$lambda-7$lambda-6(ExampleTest.kt:43) at com.acme.Action.invoke(Action.kt:7) at com.acme.Action.invoke(Action.kt:3) at com.acme.mapping.scopes.RdblConfigFileScope$sam$com_acme_Action$0.execute(RdblConfigFileScope.kt) at com.acme.Action.invoke(Action.kt:7) at com.acme.Action.invoke(Action.kt:3) at com.acme.mapping.scopes.RdblConfigFileScope.instance(RdblConfigFileScope.kt:32) — Если добавить @Suppress("NOTHING_TO_INLINE") inline fun<T> Action<T>.invokeInline(receiver: T) { receiver.execute() } И заменить .apply(configure) на .also { configure.invokeInline(it) }, то из стектрейсов пропадают почти все Action.invoke.

Vladimir Sitnikov
Попробовал, для DSL работает вот такое, и обязател...

@noraltavir ^^ вот по-моему, разумный случай для применения inline не ради пефоманса, а коротких стектрейсов для

Vladimir Sitnikov
@noraltavir ^^ вот по-моему, разумный случай для п...

Стоит ли так заморачиваться ради коротких стек-трейсов?

Vladimir Sitnikov
Попробовал, для DSL работает вот такое, и обязател...

Продолжаем историю. Нашлась ситуация, когда отдельный fun interface гораздо хуже, чем лямбда: ломается non-local return. И это печально настолько, что я подумываю выпилить этот хитроумный fun interface Action<T> И снова в копилку свидетелей inline для @noraltavir: inline fun позволяет делать non-local return, что для DSL вроде как полезно. —- Иными словами, если есть несколько уровней вложенности, то уже так просто не сделаешь return из глубины. С другой стороны, и в Java тоже невозможно так вернуть управление. Вот и получается дилемма: либо делать на простых T.()->Unit, и тогда страдает Java из-за постоянной необходимости return Unit.INSTANCE, либо на Action<T>, но тогда страдает Kotlin из-за return.

Vladimir Sitnikov
Продолжаем историю. Нашлась ситуация, когда отдел...

Полезность non-local return зависит от dsl, мне кажется

Vladimir Petraković
Полезность non-local return зависит от dsl, мне ка...

У меня вот такое в тесте возникло: override fun MappingState.isApplicable(): Boolean { mapping.run { metadata { // <— Это Action<T> if (attributes.isEmpty() || objectTypes.isEmpty()) { return@isApplicable false // <— вот тут return не работает. } } Ну и некая печаль, что у меня вложенность может быть больше, и подобный non-local может быть интереснее из более глубоких уровней. задумался над тем, чтобы добавить class ControlFlowException(val name: String, val result: Any?): Throwable(name) Заодно можно будет делать non-local в java коде 🙂

Vladimir Sitnikov
У меня вот такое в тесте возникло: override fun ...

Тут не очень понятно, почему вместо metadata { } нельзя сделать metadata.run { }

Vladimir Petraković
Тут не очень понятно, почему вместо metadata { } н...

Ну и у metadata {} receiver другой, чтобы можно было extension’ы извне навешивать (см https://t.me/KotlinMoscow/10447 ) Ну и .run на каждом уровне это печаль. И в целом у меня гораздо большая вложенность, и на каждом уровне потенциально интересно делать non-local return. Например: «если в таблице нет колонки NAME, то return false и вообще больше ничего не делаем». configFiles { // <— Action configFile(testName) { // <— Action odb { tables { // <— Action devices = table("R01_DEVICES") { // <— Action realtime() +devicesType if ("NAME" !in columns.names) { return // non-local } } }

Vladimir Sitnikov
Продолжаем историю. Нашлась ситуация, когда отдел...

А сделать двойное апи ? Или проблемы с резолвом ?

Bohdan Panchenko
А сделать двойное апи ? Или проблемы с резолвом ?

Делать отдельно API под Java — я не согласен. Если уж на то пошло, то я уж лучше не буду ничего делать, и напишу на T.() -> Unit. Но мысль-то была, что fun interface это несильно геморный вариант написания для Kotlin, и при этом получаеся красиво в Java. Вот эта красивость ломается на non-local. Следующий мой подход будет такой: добавлю default метод в Action, который будет называться nonLocalReturn (ну или как там), и кидать он будет ControlFlowException. А в DSL на каждом уровне я буду ловить это исключение, сравнивать с именем текущего метода, и, если наше, то останавливаться, а, если не наше, то пробрасывать дальше. Вроде как тогда и в Java и в Kotlin можно будет делать non-local return. Опять же, вроде, сама фича non-local далеко не всегда нужна (вон, в Gradle мне как-то не доводилось использовать), и для таких редких случав вполне можно и кастомный метод позвать.

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
Добрый день! Скажите пожалуйста, а какие программы вы бы рекомендовали написать для того, чтобы научиться управлять памятью? Можно написать динамический массив, можно связный ...
Филипп
7
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Всем привет! Имеется функция: function IsValidChar(ch: UTF8Char): Boolean; var i: Integer; ValidChars: AnsiString; begin ValidChars := 'abcdefghijklmnopqrstuvwxyzABCDE...
Евгений
44
Карта сайта