Pull to refresh

Comments 35

философия Kotlin заключается в доверии большего количества инструментов программисту (по крайней мере, нам так показалось)

Вам показалось. Kotlin создавался как удобный, прагматичный язык, и описанные вами возможности авторы языка посчитали ненужными и отвлекающими от разработки.


Собственно, почему вам не хватает internal? Да, это область видимости чуть больше, чем package-private, но и проблем с ним меньше.


А о исключениях можно спорить вечно… Кто-то считает, что обязательно должны быть проверяемые исключения и компилятор должен насиловать мозг на каждый чих, кто-то считает, что исключения — это зло (как минимум, в том виде, какие они в Java). Правда как всегда где-то посередине.


Как мне показалось из статьи, у Вас мозг "отформатирован" под Java и ещё не до конца осознал Kotlin, это всё-таки не просто Java-с-плюшками, это другой язык, хоть у него и хороший интероп с экосистемой Java.

Kotlin создавался как удобный, прагматичный язык
А есть серьёзные языки, которые создаются как неудобные, что ли? Проблема в том, что принцип доверия-недоверия разработчику объективен, а удобство — это уже понятие субъективное. Можно либо руководствоваться какими-то принципами при принятие решений при разработке языка, либо нет. Удобство — это не принцип.

область видимости чуть больше
Если в каждом модуле пара пакетов, тогда «чуть». А если пакетов больше, то тогда уже не «чуть».

это другой язык
В этом другом языке есть проблема, которую я чётко обозначил: язык не позволяет мне понять, где нештатные ситуации могут возникнуть, а где нет. Если авторы придумают, как решить этот вопрос, например, через алгебраические типы данных, тем более что в Kotlin они есть, я ничего против не имею. Например, в Rust это очень хорошо сделано. В Haskell чуть менее в силу того, что язык чисто функциональный.

А вообще скатываться на личные аргументы некрасиво.
А есть серьёзные языки, которые создаются как неудобные, что ли?

Rust и C++ считаются? :)
Дело не в том, что создаются как "неудобные", а в том, что "удобство" это одна из первоочерёдных задач.


А если пакетов больше, то тогда уже не «чуть».

По сравнению с public частью — всё-таки "чуть".


язык не позволяет мне понять, где нештатные ситуации могут возникнуть, а где нет.

Да OOM может вылететь от каждого оператора new, SOE может вылететь от каждого вызова функции — теперь что, оборачивать всю программу в try-catch? Kotlin не отбирает возможность определения throws, как и отлова исключений.


А вообще скатываться на личные аргументы некрасиво.

Вы меня не поняли. Я не скатывался в стиле "ниасилил", я сам через это проходил. После нескольких лет Java Kotlin (особенно до версии 1.0 и в некоторых моментах до 1.1) выглядел… мягко говоря непривычно. Я плевался чуть ли не от каждой фичи, которая была сделана не так, как в Java просто потому, что всё не Java, кроме Java. Я не понимал, почему авторы сделали то-то и то-то, от того отказались, заменили на то-то. Мне понадобилось некоторое время для изучения stdlib и других библиотек чтобы осознать, как стоит писать на Kotlin и почему не надо бездумно копировать практики с Java просто потому, что это тоже JVM язык.

Я же уже объяснил, почему удобство не может быть принципом. Для меня лично, например, Rust — намного более удобный язык для тех задач, для которых он предназначен, чем его альтернативы. В том-то и проблема, лаконичность может быть принципом, явность может быть принципом. Удобство — нет.


По сравнению с public частью — всё-таки "чуть".

А если у меня всего один модуль в проекте в силу каких-то причин? Тогда public и internal вообще никак отличаться не будут.


Да OOM может вылететь от каждого оператора new

Это всё ситуации, которые программа не должна обрабатывать. Я же говорю не про них.


я сам через это проходил

Если бы мне было просто непривычно, я бы ругался на гораздо большее, чем эти две особенности. Мне-то как раз Kotlin понравился сразу тем, что можно всё очень лаконично записать, и с функциональными возможностями мне очень комфортно, в частности, благодаря опыту с Rust и Haskell. И пишу я на нём уже давно. Но вот эти две вещи мешали всегда.

UFO just landed and posted this here
Есть языки, которые создаются без особого учёта удобства разработчика. Оно приносится в жертву академичности, безопасности, скорости выполнения или компиляции, универсальности и т. д., да и просто гонке за количеством фич. Да, удобство очень субъективно, особенно в мелочах, сильно зависит от конкретных сценариев использования, но «инструмент должен быть удобным в основных целевых сценариях использования» — это полноценный принцип разработки чего угодно, в том числе языка. По мнению разработчиков языка, конечно, которое может не совпадать с мнением большинства пользователей. Зато, когда удобство один из основных принципов, никогда не услышишь критики «это слишком удобно, сделайте что-нибудь» :) Можно удивляться, что кто-то считает неудобным то, что ты считаешь удобным и наоборот, но требования «сделайте неудобным» вряд ли услышишь. :)
«инструмент должен быть удобным в основных целевых сценариях использования» — это полноценный принцип разработки чего угодно, в том числе языка

Это утверждение верно, но оно примерно как теория, которая может описать что угодно. То есть формально теория верна, но предсказательная сила у неё в итоге нулевая. Так и тут: поскольку это верно в отношении всего, то и знание об этом ничего не даёт относительно какого-то конкретного языка.

При разработке одних инструментов этот принцип если не самый основной, то один из них, а при разработке других — об удобстве думают в последнюю очередь, например жертвуя им в пользу экономической эффективности производства.

Мы же говорим не об инструментах вообще, а о языках программирования. Говорили бы мы о таких инструментах, как молоток — я бы всецело согласился.

UFO just landed and posted this here
Минимизация бойлерплейта пойдет как критерий удобства?

Для кого-то да. А кому-то удобнее видеть всё прописанным явно.


В яве эксепшены надо обкладывать бойлерплэйтом

В Java тоже есть выбор: либо обрабатывать, либо объявлять, что твой метод тоже бросает определённые исключения. Другое дело, что бывают кривые API, которые проверяемыми исключениями делают ошибки программиста.


Котлин этого не запрещает делать, и вот ни разу не вынуждает

Верно. Проблема в другом. Я её уже и в статье, и в других комментариях подробно описал.

UFO just landed and posted this here
Да это не важно, как описанное называется. Смысл в том, что иногда люди предпочитают делать это, чем, например, запоминать больше ключевых слов.
А можно изучать и использовать Kotlin как первый JVM-язык, не попадая постоянно в ситуации, когда нужно лезть в документацию Java?

Я бы ни за один JVM-язык не стал браться без знания Java, а за Kotlin тем более, потому что стандартная библиотека там призвана дополнять стандартную Java, а не заменять её. Но пересесть на Kotlin со знанием Java, мне кажется, нет никакого труда. Правда, если предыдущий опыт был основан на Java 7 и раньше, к функциональным конструкциям придётся какое-то время привыкать.

То есть на практике это всё-таки какая-то надстройка над Java, а не полноценный язык, в котором JVM лишь деталь реализации конкретной. :(
Это вполне полноценный язык. Просто с учетом его особенностей переписывать стандартную библиотеку Java на Kotlin- бессмысленно. Во-первых она уже есть. Во-вторых отлажена и оптимизирована. В третьих Kotlin c Java стыкуется бесшовно. Что можно получить при ее переписывании на Kotlin кроме потери времени?

На самом деле можно учить и Kotlin как первый язык. Но тут встает вопрос как сильно вы готовы абстрагироваться от выполнения самой программы. Скажем когда мы начинаем учить язык программирования нам начинают постепенно вводить понятия: переменные, циклы, классы. И даже если вы их используете как заклинание, без глубокого понимания, программа все-равно работает. Здесь ситуация будет примерно такая-же. Вы будете знать «как», но не будете знать «почему». Если вас это устраивает, то почему-бы и нет.

Но тут есть еще один подводный камень. Язык молодой и призван облегчить жизнь Java-программистов. Поэтому большая часть авторов будет предполагать, что вы пишите на Java и переходите на Kotlin. Если предполагается, что этот так, то большую часть понятий будут не объяснять и обсасывать, а декларировать. Вы знаете как работает try-catch в Java. В Kotlin это работает вот так. Но вы-то не знаете. Готовы через это продираться с учетом того, что в результате все-равно не будете понимать половину кода или таки пойдете коротким путем по изучению сначала Java? Решать вам.

PS: А еще хорошо перед изучением Kotlin почитать Haskell. Хотя это сейчас к большей части языков применимо ;)
Как первый язык вообще вряд-ли, а вот как первый jvm язык вполне. Я например именно так его и изучал. У меня нет опыта разработки на Java и при этом я вполне спокойно пишу на Kotlin. Да иногда приходится смотреть в исходники библиотек написанных на Java, но для меня это не особо страшно, видимо опыт работы сперва с С++, а потом с php помог в этом деле.
В принципе Java-код в различных книгах по паттернам и т. п. мне понятен, больше беспокоит именно стандартные и популярные библиотеки, фреймворки и т. п. Грубо, буду часами гуглить как вывести запись в лог в Kotlin, а окажется что надо было гуглить сразу Java. И непонятно как определять что гуглить.

Ещё рассказы о Java-инфраструктуре пугают. Вроде достаточно загрузить JDK для разработки и JRE для запуска, но что на глаза не попадётся, то всякие Ant, Maven, Gradle упоминаются вскользь но как «маст хэв», причём по ощущениям даже не в проекте, а где-то сбоку, глобально. В Kotlin с этим как?
Ну мне гуглить ррешения специально для Java не приходилось, но в ответах на SO java-решения всплываю частенько. Они будут работать, но зачастую будут не идеоматичны для Kotlin. И в большинстве случаев для котлина существуют либо свои решения, либо обертки над java-библиотеками приводящие их к стилю Kotlin. Но вообще по мере набора популярности платформ js и native все больше народу пишет библиотеки только для Kotlin без оглядки на java.

Про инфраструктуру. Так-как я пишу на котлине под адроид, то из инфраструктуры мне кроме gradle ничего больше не нужно. Gradle хватает за глаза. Ставим jdk и android studio она подтянет sdk, а gradle у нее в комплекте, и все можно писать. Манипуляций с инфраструктурой не сильно больше чем в любом другом языке.
А о исключениях можно спорить вечно… Кто-то считает, что обязательно должны быть проверяемые исключения и компилятор должен насиловать мозг на каждый чих, кто-то считает, что исключения — это зло (как минимум, в том виде, какие они в Java). Правда как всегда где-то посередине.

Вот моё мнение однозначно, что непроверяемые исключения — это плохо. Я, к слову, лучше всего знаю C# и считаю непроверяемые исключения заодно с их *censored* иерархией наследования главным недостатком C#. В Java по мне главный недостаток в отсутствии возможности объявления структур, хотя в C# есть проблема с их изменением. Последний вопрос по-человечески сделали в Swift, исключения тоже проверяемые, даже есть возможность запрета пустых указателей, но в то же время ест свои, мягко говоря, «особенности». Разве что в 5-м Swift что-то исправят, хотя б абстрактные классы добавят. К слову в Swift и варианта protected нет, вот это по мне по-настоящему неудобно.

Используя протоколы, можно со спокойной совестью забыть об использовании protected

И как они помогут сделать override, не делая метод открытым для всех? Хорошо, конечно, что в них можно объявлять и конструкторы в отличие от интерфейсов в C#, но по мне что уж они точно не заменяют — так это абстрактные классы. Точнее заменить можно, но иногда это настолько громоздко, что я предпочитаю писать такую фигню:


    var price: Int? {
        return nil;//pseudo-abstract
    }

надеясь, что в 5-м Swift или позже абстрактные классы всё ж будут. Ибо иногда получается, что едва ли не на каждое абстрактное свойство пришлось б создавать протокол.

Тем, что класс обладает функциями не благодаря наследованию(где и используют protected), а тем, что наследует протоколы.

А где в этом случай будет реализация этих функций? Мне и впрямь интересно, как это сделать, чтоб не было дублирования кода, но и количество типов данных не росло в геометрической прогрессии.

Жаль, сейчас уже не могу найти ту страницу о возможном появлении абстрактных классов в Swift, с тех пор об этом написано слишком много белиберды, а Google ещё не научился отличать дельную информацию от белиберды.
В extension для каждого protocol. Протокол не хранит состояние, но может спокойно хранить поведение функции.
Ожидал от статьи немного больше, чем жалобы на отсутствие checked exceptions и package private.
Меня ещё огорчила в паре случаев работа с вариантностью и границами переменных типа, но это слишком уж узкие случаи, чтобы писать про это в статье. А если ждали, что я буду разносить язык в пух и прах, то это я и не стану делать, в нём ведь действительно решения в основном удачные.
А мне мешает вот это
github.com/JetBrains/kotlin-native/issues/733
А просвета на самом деле нет, как и в jruby, грузится несколько тысяч классов, похоже, поэтому так медленно. Упреждаю комментарии про IDE и инкрементальную сборку — речь идет о TDD. Запускается 1 тест c нуля. Прелоадеры — тоже, со времен ruby/jruby считаю, что проблем от них больше, чем пользы.
  • Пакетов нет в во второй платформе, в которую компилируется Kotlin — это JavaScript
  • Там же нет и проверяемых исключений
  • В самой JVM исключения тоже не делятся на проверяемые и непроверяемые, это фича только языка.
  • Более того, есть "хаки", позволяющие выкинуть проверяемое исключение из метода, в котором оно не объявлено.
  • И вообще, работая с JVM надо быть готовым к тому, что исключение может выкинуться из абсолютно любой точки выполнения. Это прописано в спецификации. Поэтому try-catch-finally надо писать не "для галочки", а там где реально надо сделить за потоком выполнения.
  • Не знаю, сколько времени вы потратили на написание статьи, но разработчки Kotlin потратили на исследования и обсуждения не один год. Всем фичам языка там есть своя веская причина, правда, это далеко не всегда документировано.
Пакетов нет в во второй платформе

А чем их отсутствие в JS мешает проверять область видимости при компиляции Kotlin?


Там же нет и проверяемых исключений

Но если "это фича только языка", опять же, почему тогда они должны поддерживаться в JS?


Поэтому try-catch-finally надо писать не "для галочки", а там где реально надо сделить за потоком выполнения.

Верно, но вот как мне понять, где именно такие места находятся? И какого рода проблемы могут возникнуть, чтобы правильно написать обрабатывающий код? Иногда это очевидно, иногда нет.


Не знаю, сколько времени вы потратили на написание статьи

При чём тут написание статьи? Я использую инструмент, которым трудно решить определённые проблемы, и я их описал. А "годы исследований и обсуждений" — это, по сути, апелляция к авторитету.


Естественно, я не знаю так, как авторы языка, какие последствия повлёк бы тот или иной выбор. Но объяснение всё-таки хочется увидеть грамотное, а не основанное на избирательном цитировании известного автора и притянутом за уши примере. И хочется иметь какую-то альтернативное решение проблемы, раз авторы считают, что старое не годится.

можно сделать так, чтобы метод был виден наследникам, как в своём пакете, так и вне пакета (protected)
Не совсем так. Protected это видимость для всех внутри пакета и для наследников в других пакетах.
Я в курсе, просто там формулировка двусмысленная. Перефразировал более корректно.

Мне тоже не хватает package private.
Всё-таки мне кажется, что удобно разделять подсистемы по пакетам и скрывать детали их реализации, выставив для других частей приложения чёткий интерфейс и спрятав то, что напрямую использовать не следует.
Создавать 10-20 модулей в приложении только ради этого — не решение.
И аргумент создателей о том, что пакеты не защищены от добавления левых классов в другом модуле, не очень убедителен — это бросается в глаза и нельзя сделать случайно (и вряд ли так кто-то будет делать без веской причины). Чего не скажешь об использовании классов из соседнего пакета, которые для этого не предназначены.
Видимость внутри модуля — очень полезная вещь для библиотек. Но и видимость внутри пакета тоже нужна.

аргумент создателей о том, что пакеты не защищены от добавления левых классов в другом модуле, не очень убедителен

Да и не актуален начиная с Java 9. Один модуль не может подложить классы в те же пакеты другому модулю. Поэтому, кстати, JetBrains и заменили kotlin-stdlib-jre7 и kotlin-stdlib-jre8 на kotlin-stdlib-jdk7 и kotlin-stdlib-jdk8: в первых двух один и тот же пакет был в обеих библиотеках.

Sign up to leave a comment.