В смысле время? Последних 6 лет недостаточно что ли? Примерно все добавленные синтаксические фичи джавы, имеющие аналог в скале, во-первых сделаны более убого по сравнению со скалой, во-вторых, неслабо корежат исходный синтаксис джавы, делая его все менее консистентным и более мозаичным.
Хорошая иллюстрация, как дизайнерам джавы приходится идти на компромиссы и выбирать из нескольких зол — спич Тагира Валеева про паттерн-матчинг https://www.youtube.com/watch?v=qurG_J81_Cs
Справедливости ради, популярные Java-стеки тоже сложно назвать простыми и очевидными. Программирование на аннотациях и на classpath в спринг-буте имхо гораздо большая магия, чем имплиситы, или макросы, или что угодно еще в скале. Взять какой-нибудь хибернейт или тот же ломбок — в них реально проще разобраться, изменить поведение или найти баг, чем в скала-либах?
Если у меня не работает какая-нибудь связка макросов и имплиситов для десеарилизации какого-то хитрого типа из json, я всегда могу посмотреть дешугареный код, разобраться, что откуда берется, написать нужные куски сам. Я по-прежнему остаюсь в пространстве языка, могу пользоваться всеми его богатыми средствами, и компилятор скажет, если что-то не так.
Но вот когда в спринг-буте что-то ломается на ровном месте из-за неправильного порядка загрузки конфигов, а птичьего языка аннотаций не хватает, чтобы запрограммировать нужное поведение — вот тут я ощущаю нешуточную фрустрацию. Правильность аннотаций не проверяется компилятором. Все это добро работает в рантайме через рефлексию. Весь современный java стек программируется не на уровне языка джава, а мета-уровнях, будь то имена методов (как в JPA), аннотации, classpath, генерация кода, генерация байткода.
Может код джава-проектов и выглядит таким простым, потому что вся основная работа неявно делается где-то еще, и девелоперы могут просто верить в магию, данную свыше, вместо того, чтобы разбираться в ней и кастомизировать под себя средствами языка.
А я как раз хотел показать пример где instanceof не используется и компилятор нуждается в подсказке.
Хмм, а зачем это нужно? Пусть компилятор под капотом проверяет типы как хочет. Обычно все-таки люди стремятся писать код, который решает задачи, а не подсказки для компилятора, которые выглядят гораздо страшнее, чем обычный каст, который они заменяют.
Код на котлине эквивалентеый вашему коду на Scala
Он не совсем эквивалентный.
Во-первых, в котлиновской версии одна и та же переменная figure имеет сначала один тип, а потом уже другой. Это облегчает написание кода (не надо самому писать каст), но усложняет чтение. Даже в джаве, которая гораздо сильнее ограничена в плане синтаксиса, это сделали по-нормальному.
Во-вторых, насколько такой подход масштабируется на чуть более сложные случаи типа:
case Vacancy(id, _, Some(Salary(from, to, Some(currency))), Nil) => ...
Ну да, вы изобрели паттерн-матчинг на костылях контрактах. Осталось подождать, пока его таки изобретут авторы языка. После этого можно будет спокойно выкинуть все эти неявные конвертации.
Чисто для сравнения аналогичный вашему код на Scala:
sealed trait Figure
case class Circle(x: Int, y: Int, radius: Int) extends Figure
case class Rectangle(x0: Int, y0: Int, x1: Int, y1: Int) extends Figure
val test: Figure => Unit = _ match {
case Circle(x, y, radius) => println(s"$x, $y, $radius")
case Rectangle(x0, y0, x1, y1) => println(s"$x0, $y0, $x1, $y1")
}
Я имел ввиду, что можно было бы сделать полноценный паттерн-матчинг как синтаксическую конструкцию. Да, для компилятора это было бы чуть более напряжно. Но пусть уж лучше компилятор напрягается, чем программист, которому теперь надо держать в голове все неявные преобразования, которые делают смарткасты и контракты. Целых два разных механизма, решающих довольно узкую задачу, которая по идее должна достаточно редко возникать в языке с type-safety и null-safety.
Спасибо! Интересная вещь, хотя и не совсем понятно, в чем профит программиста от такого описания контракта? Мы добавляем какую-то метаинфу для компилятора, чтобы он лучше понимал основной код, и, видимо, не выдавал ворнинги. Не проще ли сразу задизайнить язык так, чтобы компилятор понимал код без подсказок?
Я конечно очень люблю скалу, но все-таки. По умолчанию в кейс классах свойства val, но можно явно написать var и будет сгенерирован сеттер. А вот в рекордах, насколько я понял JEP, все поля как раз таки генерируются как final.
Что-то не припомню в скале такого оператора. Там конечно можно для коллекции написать что-то типа .reduce(_ + _) или .map(_._1), но ни в том, ни в другом случае это конечно никакой не оператор.
На мой взгляд, некоторые практики из XP, такие как TDD, парное программирование или рефакторинг, невероятно полезны для обучения новичков основам профессионального (промышленного) программирования. Люди приходят после ВУЗов, где обычно критерий правильности решения в том, что программа выдает правильный результат в каком-то очень узком диапазоне входных значений. Качество кода мало кого волнует.
То, что код должен быть в первую очередь корректным и простым, каждому видимо надо понимать на собственном опыте, и игры в TDD и рефакторинг (под присмотром старших товарищей) ускоряют этот процесс.
В любом тесте невозможно перебрать все комбинации исходных данных, а значит такое тестирование ничего не гарантирует.
Мне кажется, тут будет в тему упомянуть property-based testing, который конечно не поможет перебрать бесконечное количество комбинаций, но попробовать рандомные значения из конечного набора ограничений (например, 1/x и все остальные) и отловить связанные с этим косяки вполне позволяет.
Вот мне интересно, а чем питон быстрее той же скалы для маленьких программ?
Единственное, что приходит в голову: питон предустановлен во многих линукс-дистрибутивах, а jvm и sbt — нет. Но с другой стороны, если я владею скалой, скорее всего, окружение у меня уже давно готово и настроено, и нет никаких причин не писать даже маленькую программу на скале.
Опыт — это конечно хорошо, но у каждого он свой. Можно ли узнать, какие конкретно фичи питона позволяют писать быстрее и более поддерживаемый код, чем в случае C#?
Да, джаве прямо сильно не хватает extention-методов, можно было бы много острых углов стандартной библиотеки срезать.
Странно, что не упомянуты Prometheus + Grafana.
Статья в Коммерсанте:
Статья на хабре, после "творческой обработки":
Например squants:
В смысле время? Последних 6 лет недостаточно что ли? Примерно все добавленные синтаксические фичи джавы, имеющие аналог в скале, во-первых сделаны более убого по сравнению со скалой, во-вторых, неслабо корежат исходный синтаксис джавы, делая его все менее консистентным и более мозаичным.
Хорошая иллюстрация, как дизайнерам джавы приходится идти на компромиссы и выбирать из нескольких зол — спич Тагира Валеева про паттерн-матчинг https://www.youtube.com/watch?v=qurG_J81_Cs
Справедливости ради, популярные Java-стеки тоже сложно назвать простыми и очевидными. Программирование на аннотациях и на classpath в спринг-буте имхо гораздо большая магия, чем имплиситы, или макросы, или что угодно еще в скале. Взять какой-нибудь хибернейт или тот же ломбок — в них реально проще разобраться, изменить поведение или найти баг, чем в скала-либах?
Если у меня не работает какая-нибудь связка макросов и имплиситов для десеарилизации какого-то хитрого типа из json, я всегда могу посмотреть дешугареный код, разобраться, что откуда берется, написать нужные куски сам. Я по-прежнему остаюсь в пространстве языка, могу пользоваться всеми его богатыми средствами, и компилятор скажет, если что-то не так.
Но вот когда в спринг-буте что-то ломается на ровном месте из-за неправильного порядка загрузки конфигов, а птичьего языка аннотаций не хватает, чтобы запрограммировать нужное поведение — вот тут я ощущаю нешуточную фрустрацию. Правильность аннотаций не проверяется компилятором. Все это добро работает в рантайме через рефлексию. Весь современный java стек программируется не на уровне языка джава, а мета-уровнях, будь то имена методов (как в JPA), аннотации, classpath, генерация кода, генерация байткода.
Может код джава-проектов и выглядит таким простым, потому что вся основная работа неявно делается где-то еще, и девелоперы могут просто верить в магию, данную свыше, вместо того, чтобы разбираться в ней и кастомизировать под себя средствами языка.
Ну имхо, котлиновский синтаксис
when
весьма далек от джавы, точно не ближе скаловскогоmatch/case
.Хмм, а зачем это нужно? Пусть компилятор под капотом проверяет типы как хочет. Обычно все-таки люди стремятся писать код, который решает задачи, а не подсказки для компилятора, которые выглядят гораздо страшнее, чем обычный каст, который они заменяют.
Он не совсем эквивалентный.
Во-первых, в котлиновской версии одна и та же переменная
figure
имеет сначала один тип, а потом уже другой. Это облегчает написание кода (не надо самому писать каст), но усложняет чтение. Даже в джаве, которая гораздо сильнее ограничена в плане синтаксиса, это сделали по-нормальному.Во-вторых, насколько такой подход масштабируется на чуть более сложные случаи типа:
Ну да, вы изобрели паттерн-матчинг на
костыляхконтрактах. Осталось подождать, пока его таки изобретут авторы языка. После этого можно будет спокойно выкинуть все эти неявные конвертации.Чисто для сравнения аналогичный вашему код на Scala:
Я имел ввиду, что можно было бы сделать полноценный паттерн-матчинг как синтаксическую конструкцию. Да, для компилятора это было бы чуть более напряжно. Но пусть уж лучше компилятор напрягается, чем программист, которому теперь надо держать в голове все неявные преобразования, которые делают смарткасты и контракты. Целых два разных механизма, решающих довольно узкую задачу, которая по идее должна достаточно редко возникать в языке с type-safety и null-safety.
Спасибо! Интересная вещь, хотя и не совсем понятно, в чем профит программиста от такого описания контракта? Мы добавляем какую-то метаинфу для компилятора, чтобы он лучше понимал основной код, и, видимо, не выдавал ворнинги. Не проще ли сразу задизайнить язык так, чтобы компилятор понимал код без подсказок?
А если
obj is String
вынести в функцию и вставить ее вызов вif
— сработает?Странно, что обойден стороной такой немаловажный вопрос как стоимость всех этих решений.
Может имелся в виду HDFS? Сформулировано не очень корректно, да.
Я конечно очень люблю скалу, но все-таки. По умолчанию в кейс классах свойства val, но можно явно написать var и будет сгенерирован сеттер. А вот в рекордах, насколько я понял JEP, все поля как раз таки генерируются как final.
Что-то не припомню в скале такого оператора. Там конечно можно для коллекции написать что-то типа
.reduce(_ + _)
или.map(_._1)
, но ни в том, ни в другом случае это конечно никакой не оператор.На мой взгляд, некоторые практики из XP, такие как TDD, парное программирование или рефакторинг, невероятно полезны для обучения новичков основам профессионального (промышленного) программирования. Люди приходят после ВУЗов, где обычно критерий правильности решения в том, что программа выдает правильный результат в каком-то очень узком диапазоне входных значений. Качество кода мало кого волнует.
То, что код должен быть в первую очередь корректным и простым, каждому видимо надо понимать на собственном опыте, и игры в TDD и рефакторинг (под присмотром старших товарищей) ускоряют этот процесс.
Мне кажется, тут будет в тему упомянуть property-based testing, который конечно не поможет перебрать бесконечное количество комбинаций, но попробовать рандомные значения из конечного набора ограничений (например, 1/x и все остальные) и отловить связанные с этим косяки вполне позволяет.
Вот мне интересно, а чем питон быстрее той же скалы для маленьких программ?
Единственное, что приходит в голову: питон предустановлен во многих линукс-дистрибутивах, а jvm и sbt — нет. Но с другой стороны, если я владею скалой, скорее всего, окружение у меня уже давно готово и настроено, и нет никаких причин не писать даже маленькую программу на скале.
Опыт — это конечно хорошо, но у каждого он свой. Можно ли узнать, какие конкретно фичи питона позволяют писать быстрее и более поддерживаемый код, чем в случае C#?