Обновить
27
0
Paul Popoff@ppopoff

Software engineering manager

Отправить сообщение

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


  • проблемы с платформами (такими как JVM)
  • недостаток производительности (упираемся в кремний)
  • высокая сложность текущих языков
  • проблемы с эволюцией текущий языков (неудачная модель развития Python и неудачная модель развития Java).
  • параллельность на уровне языка
  • возможность составлять dsl, при максимальной простоте грамматики языка.

Спасибо за уточнение! Добавил ссылку на ваш комментарий!

Спасибо! Исправил.

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

А еще, меня постоянно мучает вопрос: почему Скала не поддерживает именование элементов кортежа? Это ведь так удобно! Было бы гораздо читабельней видеть такое:

Я так понимаю что Мартин хотел бы чтобы мы использовали для этого case classы.


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

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

Большое спасибо за комментарии.


Про Path-dependent типы я забыл, в первую очередь потому что я их очень и очень редко встречаю в коде. Не видел у новичков попытки использовать CanBuildFrom. Скажу честно, мне никогда это в голову не приходило. Хотя, возможно я и не сталкивался с ситуациями когда это имеет смысл. Если такие ситуации есть. Рад выслушать и получить ценный опыт.


Сопоставление с образцом не обязано разбирать какую-то структуру данных, case class или tuple, например, на составлящие. Оно может взять обычную строчку и разбить её на группы с помощью регэкспов.

Технически, строчку можно рассматривать как compound тип, и Scala притворяется :)


Если вам не нравятся встроенные кортежи — возьмите их из shapeless, там они достаточно прокаченные.

Можно использовать кортежи из Shapeless, а можно подключить HListы. Если я правильно понимаю, то что первые что вторые равнозначны (при наличии имплисита в области видимости). Эти структуры данных, на мой взгляд вполне оправданы при написании каких-нибудь универсальных алгоритмов, или как они (HList) используются в Parboiled2: для представления ValueStack. В остальных случаях case classы нахожу боле применимыми: Тип именуется, поля именуются. Понятно-читаемо.


И много, много других ньюансов. Если честно, я с трудом представляю какой должен быть формат у хабра статей, чтобы последовательно изложить язык программирования scala и сложившиеся best practise для него.

Мне нравится то, что попытались сделать ребята из Twitter в их Effective Scala. И я во многом буду ссылаться на нее. Но, объять необъятное достаточно сложно.

Промотайте пожалуйста статью в самый верх, там будет заголовок "структура цикла". Это ссылки, они кликабельны. Так сделано для каждой статьи серии. Последних двух нет, потому что они пока еще не написаны :)

Паша, полностью тебя поддерживаю. И я также недоволен оригинальным термином. Generator-driven testing более соответствует действительности нежели property-based. Но, к сожалению вопрос по оригинальной терминологии следует задавать John Hughes. Я перевел данный термин как точную кальку для того, чтобы не вводить в заблуждение читателей. Есть ли те кто считает, что оригинальный термин подобран не корректно? Я бы хотел услышать ваше мнение.

Статья как-то внезапно обрывается…

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

Не знаю, у меня было совершенно наоборот. Когда меня бросили в скалу, я ее сначала возненавидел, зато потом полюбил. И не за синтаксис, и не за вывод типов, и не за лямбды. А за мелочи, которые делают жизнь проще: Правильным образом перегружаемый == инвариантные массивы, ADT (которые позволяют делать исчерпывающую проверку при паттерн-матчинге), Кейс-классы знатно экономят время. А потом уже стандатный набор всего и вся.

… есть такой язык, Ruby называется, его пользователи так не считают

Согласен. Но оставлены ли уже попытки создать такой язык?

А смысл есть? Код могут воспринимать только люди способные алгоритмизировать. Это дано не всем. Маму научил решать элементарные задачи на питоне в ее 58 лет (аналог с поваренной книгой работает на ура). Приятелю 19 объясняю ему основы Pascal (который вижу более простым чем питон). Вроде бы все понимает, задачу алгоритмизировать не может. Так же не может восстановить ход мыслей. Делать языки "доступные" не-специалистам бессмысленно.


Там фактически был отбор из дюжины языков.

И выбор был сделан намеренный. В пользу SQL. Но в настоящее время мы видим — выбор был не угадан

Ну а где сейчас прородитель то? Почил в бозе. Аналогичная ситуация была и с javascript если помните, который изначально был вполне себе scheme, но в виду маркетинговых соображений его переименовали из livescript (емнип) в javascript и добавили синтаксис отдаленно напоминающий Java. Кобол выбирали не потому что он понятный, а потому что в то время он был в тренде. Вы уверенны что точная причина именно псевдопонятность кобола? Я в этом глубоко сомневаюсь.

Все что вы только что написали, доказывает вторичность синтаксиса. Дело в том что да, был язык который разрабатывался для того чтобы быть понятным для бухгалтеров, экономистов и кладовщиков. Появился этот язык в 1959 году и назывался далеко не SQL. И как показала практика, код на COBOL не программистами вообще не читался. Да это по прежнему был код, как бы читабельно он не выглядел. Более того. Существует ряд исследований касательно читаемости кода на COBOL, результаты которых не утешительны. Да, нормальные люди не в состоянии читать код, на каком бы языке он не был написан. И дело тут исключительно в людях, а не в языке. И где сейчас COBOL, c его предложениями, достойными Шекспира?


А вот с SQL произошла другая история. Глубоко в недрах IBM, Э. Коддом разрабатывался язык, подкрепляющий теорию реляционных баз данных. Он был основан на исчислении кортежей, а так же на реляционной алгебре. Задачей языка было лечь на реляционную модель и служить средством ее описания (DDL), а так же выполнения манипуляций с данными (DML), а потом уже управление пользователями и их привелегиями (см DCL).


Тот синтаксис, который мы видим сейчас в SQL, обязан лишь популярности COBOLа в момент своего создания (а это были семедисятые годы). И своей успешностью SQL, обязан исключительно своей семантике, но не синтаксису.


К большому сожалению, сейчас SQL уже не отражает реляционную модель так как он это делал раньше (что например отмеченно в работе Дейта). Однако он по прежнему успешен, в виду того что стал стандартом де-факто для RDMS). Sql мог бы иметь и другой синтаксис. И это бы никак не повлияло на его успешность. К тому же для запросов выбран вполне себе функциональный подход. берем выборку фильтруем и трансформируем ее. Это уже простите не совсем синтаксис :)

Согласен. Самолично видел "перегрузку" "операторов" на Java. Безумца ничто не остановит.

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


Язык LISP знаменит своим синтаксисом, который основан на S-expressionах. Так вот. S-выражения изначально задумывались как… промежуточное представление. Изначально планировалось реализовать M-expressionы в качестве фасада. Потом уже S-выражения прижились. Синтаксис прилагается к ядру языка, а не наборот.

Если обещают, было бы не плохо.

Люди сравнивают синтиаксис: Вот тут у меня def, а тут у меня fun… А вот смотрите я тут пишу фигурные скобочки а тут могу не писать. А еще тут у меня есть сахарок. Кому-то не нравятся угловые скобки в котлине потому-что они отдают джавой. "Ой, а вот я не знаю что лучше it в груви, или нижнее подчеркивание в scala", — произносит молоденькая девочка поправляя очки. Смотрю я на подобные статьи и умиляюсь, ибо люди которые их пишут не понимают главного: Синтаксис вторичен. Я, кстати ожидал увидеть сравнение HelloWorld программ. Рад что хотя бы этого здесь нет
Еще раз, я не говорю что синтакс не важен, я говорю что он вторичен.
Если вы выбираете язык исключительно потому что вам нравится синтаксис/сахарки. Вы недостаточно взрослый инженер чтобы принимать решения архитектурного уровня. Я видел инжинеров принмавших следующее решение: "Языком для нашей команды будет scala потому что у ней есть var и val". Знаете где сейчас этот инженер? Он живет себе спокойненько и пишет на Java. Потому что в скале разочаровался. Сложная она ему.


Язык это инструмент который позволяет решать задачи, для кого-то бизнес-задачи. И требования которые предъявляются к языку? Как он эти задачи решает верно? Поэтому первым пунктом рассматриваются библиотеки доступные для языка, потом рассматривается сама платформа, как она работает, где проседает по производительности и тд. Это требование называется "экосистемой". В случае с java, kotlin и scala, спорить бесмысленно, хотя… нам тут обещают scala.native, scala.js (у котлина тоже есть возможность собираться в js). Почему бы при сравнении не обыграть этот факт? наличие возможности собираться в нативный код может стать судьбоносным при выборе языка программирования.
Потом идут возможности языка/платформы. Почему бы не сравнить работу рефлексии в scala/kotlin. А есть ли в котлине макросы? А как они работают? В Scala второе поколение макро решений сменяется.


Одна из лучших особенностей Kotlin для меня даже не в том функционале что есть, а больше в том функционале которого нет в Kotlin из Scala.

Вот собственно то что должно было быть в статье про kotlin и scala. А именно, мощь, средства выразительности языка которые скрываются за синтаксом.
Ну что, пройдемся по списку написанного автором? Поехали


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

Call-by-name это вообще стратегия вычисления (evaluation strategy). Тут о читаемости вообще никакой речи не идет. Это мощь в чистом виде. И это та мощь которая лежит за синтаксом.


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

Вы хотите особого вида операторы для Float, как в Ocaml? В скале это не только преобразования :). Есть например implicit parameters. Которые могут красиво просовываться туда где для них есть место. Разве у вас не было случаев когда вам нужно было постоянно проносить некоторый контекст везде где только можно? Думаю что было. Есть implicit классы, которые реализуют extension методы. Функционал сопоставимый. Однако, я нахожу implicit классыы более абстрактным и выразительным средством. Есть еще одно выразительное средство, которого в Котлин (я могу ошибаться) точго нет. Знаете какое? Type classes (или ad-hoc полиморфизм). И тут, scala достает из кармашка свои имплиситы и вытряхивает их перед вами, а затем с их помощью позволяет реализовать классы типов. Вы пробовали классы типов когда-нибудь?). Попробуйте. Рекламировать их не буду.


Перегруженный for — Проблема с несколькими монадами, показанная выше.
Беспорядок с опциональным синтаксисом infix и postfix операторов — Kotlin чуть более формализованный. В результате код в нем менее двухсмысленный, его проще читать и не так легко простой опечатке стать неочевидной ошибкой.

Про for, возможно соглашусь, а вот по поводу postfix операторов усомнюсь. Да, postfix синтаксис способен снести парсеру крышу. Опять таки postfix операторы создавались для возможности делать внятные DSL. DSL это один шаг к Language Oriented programming. За свое время я реализовывал несколько DSL для разных предметных областей. Тот выигрыш, который они дают в продуктивности описать трудно. Но он значительный.
Опять таки, если вы хотите использовать фичи языка включите их:


  import scala.language.implicitConversions
  import scala.language.postfixOps

Не хотите, не включайте. Смысл ругать язык за наличие более глубокой функциональности? Кто-то может воспользоваться? Следите за персоналом. Для других языков вполне нормальная пратика иметь codestyle, с которым знакомятся все разработчики когда попадают в команду. добавить туда 7 слов особой проблемы не составит: "не использовать имплиситы и постфиксные операторы".


Ну, беспорядок с опциональным синтаксисом помоему как раз царит в котлине. У меня порой создается впечатление, что язык разрабатывался ради великой цели: обойти косяк платформы в виде NullPointerException. Конечно же NPE это проблема, и решение для нее вполне очевидно, использовать опшны. Да в том виде в каком они есть. Да синтаксис можно было бы для них взять котлиновский. Но оставить Optionами. Андрей Бреслав в одном своем докладе сказал что они не выбрали Option потому что это лишний объект в памяти. в JDK 9 нам обещают проевт valhala. Уверен что есть возможность сжульничать на этапе кодогенерации временно генерировать Option.None в null. Если таковой возможности нет, буду рад если меня кто-то просветит. Про Optionы скажу лишь одно: все мы там будем. Это будщее, это эволюция.


Переопределением операторов по максимуму — Kotlin разрешает переопределение только основных операторов (+, — и т.п.). Scala разрешает использовать любую последовательности символов. Действительно ли мне нужно знать разницу между "~%#>" и "~+#>"?

Да, порой перегрузка операторов (в некоторых библиотеках) она просто ужасна. Да, можно пойти по стопам C++, где >> обозначает не совсем очевидные вещи. А вы задавались вопросом для чего это сделано? Для построения DSL. Посмотрите например на Parboiled. Перегруженна вообще тильда. Как выглядит код? Как вполне себе BNF. А как выглядят роутинги в Spray? Этого всего бы не было если бы не перегрузка операторов. И да в том виде в каком она есть. А знаете ли вы что хорошей практикой считается дублировать символьные имена методов, текстовыми? Если такой возможжности нет, пинайте разработчиков библиотеки. Это они плохие люди, а не Мартин Одерски.


Медленное время компиляции.

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


Да, я люблю scala. Она дает ту мощь, которую врядли даст какой-нибудь из известных языков. Ибо по сложности (как мне видится) она вполне себе переплевывает Haskell. Я хорошо отношусь к Kotlin. Да, я вижу его как обрезанную scala, и не вижу в этом ничего плохого. К сожалению, или к счастью, я считаю котлин более перспективным нежели scala.
Конечно же, время покажет.


Уважаемые хабравчане, пожалуйста, не сравнивайте языки по синтаксису. Победителем всегда будет LISP :)

А ешё вы не упомянули скаловскую фичу View Bound, без которой достаточно кисло в некоторых случаях, когда хочется типобезопасно выразить полиморфизм. И она тоже работает через implicit.

их уже поместили в deprecated. Так что scala скоро останется без них.

При всей моей любви к scala, композиция в ней сделана отвратно. Поэтому, в своей библиотечке я добавил следующий синтаксис для композиции:


implicit class EnrichedFunction[-A,+B](f: A => B) {

  /**
    * Shortcut for function composition
    * @return a composition of functions
    */
  def o [R] (g: R => A): R => B = x => f(g(x))
  def ∘ [R] (g: R => A): R => B = x => f(g(x))
}

Собственно, делает то же самое что и compose (можете сравнить код), однако, по моему-мнению выглядит более юзабельно.

Аналогия с реальным миром такая.

Императивщик.
Берет пустую комнату и размещает на ней предметы, в цикле, наполняя комнату мебелью и изменяя ее состояние. Проверяя, стоит ли в желаемом месте что-то. На выходе имеем комнату с расставленной мебелью.

Функциональщик
Берет пустую комнату, добавляет единицу мебели и… возвращает новую комнату но уже с мебелью. И делает он это рекурсивно: каждый раз откусывая головушку списка имеющейся мебели, пока мебель не иссякнет.

Информация

В рейтинге
Не участвует
Дата рождения
Зарегистрирован
Активность

Специализация

Десктоп разработчик, Software Engineering Manager
Ведущий
От 1 000 000 ₽
Linux
Python
PostgreSQL
Docker
Java
Java Spring Framework
Hibernate
Spring Boot
Scala
Английский язык