All streams
Search
Write a publication
Pull to refresh
-1
0
Антон Нехаев @nehaev

Архитектор, консультант

Send message

Да, джаве прямо сильно не хватает extention-методов, можно было бы много острых углов стандартной библиотеки срезать.

Статья в Коммерсанте:


В даркнете выставили на продажу около 1,1 млн номеров и серий паспортов избирателей

Статья на хабре, после "творческой обработки":


Всего в базе содержатся около 1,1 миллиона телефонных номеров и серий паспортов избирателей

Например squants:


scala> val energyUsed = 100.kilowatts * (3.hours + 45.minutes)
energyUsed: squants.energy.Energy = 375000.0 Wh

scala> val energyUsed = 100.kilowatts + 3.hours
                                          ^
       error: type mismatch;
        found   : squants.time.Time
        required: squants.energy.Power

В смысле время? Последних 6 лет недостаточно что ли? Примерно все добавленные синтаксические фичи джавы, имеющие аналог в скале, во-первых сделаны более убого по сравнению со скалой, во-вторых, неслабо корежат исходный синтаксис джавы, делая его все менее консистентным и более мозаичным.


Хорошая иллюстрация, как дизайнерам джавы приходится идти на компромиссы и выбирать из нескольких зол — спич Тагира Валеева про паттерн-матчинг https://www.youtube.com/watch?v=qurG_J81_Cs

Запутанность и неочевидность многих вещей

Справедливости ради, популярные Java-стеки тоже сложно назвать простыми и очевидными. Программирование на аннотациях и на classpath в спринг-буте имхо гораздо большая магия, чем имплиситы, или макросы, или что угодно еще в скале. Взять какой-нибудь хибернейт или тот же ломбок — в них реально проще разобраться, изменить поведение или найти баг, чем в скала-либах?


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


Но вот когда в спринг-буте что-то ломается на ровном месте из-за неправильного порядка загрузки конфигов, а птичьего языка аннотаций не хватает, чтобы запрограммировать нужное поведение — вот тут я ощущаю нешуточную фрустрацию. Правильность аннотаций не проверяется компилятором. Все это добро работает в рантайме через рефлексию. Весь современный java стек программируется не на уровне языка джава, а мета-уровнях, будь то имена методов (как в JPA), аннотации, classpath, генерация кода, генерация байткода.


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

Ну имхо, котлиновский синтаксис when весьма далек от джавы, точно не ближе скаловского match/case.

А я как раз хотел показать пример где 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.

Спасибо! Интересная вещь, хотя и не совсем понятно, в чем профит программиста от такого описания контракта? Мы добавляем какую-то метаинфу для компилятора, чтобы он лучше понимал основной код, и, видимо, не выдавал ворнинги. Не проще ли сразу задизайнить язык так, чтобы компилятор понимал код без подсказок?

А если obj is String вынести в функцию и вставить ее вызов в if — сработает?

Странно, что обойден стороной такой немаловажный вопрос как стоимость всех этих решений.

Может имелся в виду HDFS? Сформулировано не очень корректно, да.

Я конечно очень люблю скалу, но все-таки. По умолчанию в кейс классах свойства val, но можно явно написать var и будет сгенерирован сеттер. А вот в рекордах, насколько я понял JEP, все поля как раз таки генерируются как final.

Что-то не припомню в скале такого оператора. Там конечно можно для коллекции написать что-то типа .reduce(_ + _) или .map(_._1), но ни в том, ни в другом случае это конечно никакой не оператор.

На мой взгляд, некоторые практики из XP, такие как TDD, парное программирование или рефакторинг, невероятно полезны для обучения новичков основам профессионального (промышленного) программирования. Люди приходят после ВУЗов, где обычно критерий правильности решения в том, что программа выдает правильный результат в каком-то очень узком диапазоне входных значений. Качество кода мало кого волнует.


То, что код должен быть в первую очередь корректным и простым, каждому видимо надо понимать на собственном опыте, и игры в TDD и рефакторинг (под присмотром старших товарищей) ускоряют этот процесс.

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

Мне кажется, тут будет в тему упомянуть property-based testing, который конечно не поможет перебрать бесконечное количество комбинаций, но попробовать рандомные значения из конечного набора ограничений (например, 1/x и все остальные) и отловить связанные с этим косяки вполне позволяет.

Вот мне интересно, а чем питон быстрее той же скалы для маленьких программ?


Единственное, что приходит в голову: питон предустановлен во многих линукс-дистрибутивах, а jvm и sbt — нет. Но с другой стороны, если я владею скалой, скорее всего, окружение у меня уже давно готово и настроено, и нет никаких причин не писать даже маленькую программу на скале.

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

Information

Rating
Does not participate
Location
Россия
Date of birth
Registered
Activity

Specialization

Backend Developer, Software Architect
Lead
Java
Scala