Ранее

В последнем эпизоде мы рассмотрим некоторые изменения в Monyet, The Crystal реализации Monkey.

Моя история со Scala

Я начал использовать Scala более десяти лет назад с версии 2.6. Все было хлипко, поддержки IDE почти не было, но было интересно, ново и весело. Концепции были свежими и сногсшибательными. Потом появились новые версии, и люди подхватили волну; все говорили о новом большом деле. Я катаюсь на волне, как могу. Я сделал хорошо, очень хорошо, на самом деле. Благодаря Scala я мигрировал не один раз, а дважды; Я оставил свою семью и свою страну и отправился в новые приключения за границей. Я очень благодарен Scala.

Но время шло, а гики любят новые блестящие штучки, так что я двинулся на более зеленые пастбища (и продолжаю двигаться). За последние три года я не написал ни строчки кода на Scala профессионально. Много Python, Kotlin, Java (немного TypeScript и Go), но не Scala.

Возвращаемся к Scala 3.

Позвольте представить вам Langur, мою реализацию языка Monkey на Scala 3.

Опыт возвращения в известное место через много лет. Знакомый, но странный.

Что-то я любил, что-то нет, а теперь я могу видеть другие вещи в другом свете благодаря времени, проведенному в других странах.

Хорошие части

Новые перечисления

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

Расширения

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

Скорость компилятора

Он чувствует себя быстрее, или теперь у меня есть лучшая машина. В любом случае

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

Given and Using выглядит как правильный способ заменить имплициты. Типы Union и Intersection отлично подходят для других языков, и я надеюсь, что реализация scala также будет образцовой.

Мех части

Новый синтаксис

*Райан Рейнольдс, но почему? мем*

В чем причина? Чтобы привлечь разработчиков Python? Это совсем не похоже на Python. И вы можете смешивать и сочетать оба синтаксиса в одном файле?

Я провел добрых 20 минут, ломая голову над кодом, который не компилировался, когда понял, что случайно нажал табуляцию… и сообщение об ошибке компилятора совсем не помогло.

Метапрограммирование

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

IntelliJ IDEA еще не готова.

С самим языком проблем нет. Лучший способ описать поддержку Scala 3 в IntelliJ — «случайно». Он случайным образом автоматически импортирует, случайным образом автоматически завершает работу, случайным образом перестает работать, случайным образом дает сбой и так далее.

Я также не виню команду плагинов Scala; изменения огромны, и надлежащая поддержка потребует много работы.

Он по-прежнему работоспособен, работает быстро, и меня не заблокировали. Но это не знакомый IntelliJ опыт помощи на этом пути.

Части, которые выглядят по-другому спустя много лет

Сопоставление шаблонов Scala — это потрясающе

Мне удалось написать очень компактный код с сопоставлением с образцом. Kotlin when + smart casts + destructuring — подходящая замена, но заметьте, как хорошая. Например.

По сравнению с:

AnyVal

В Scala 3 нет поддержки байтов без знака, но я создал разумное приближение с помощью AnyVal.

Типы Kotlin Nullable против варианта Scala

Я был большим защитником Scala Option до такой степени, что портировал его на Kotlin под своей старой библиотекой funKTionale.

Уже нет; после многих лет Kotlin типы Option выглядят неуклюжими, многословными и полными церемоний. Вместо этого типы Nullable покрывают 99% реальных вариантов использования, а для оставшегося 1% вы можете использовать Option from Arrow (я предоставил часть исходного кода).

Пытаясь избежать всех этих церемоний, я был осторожен в том, когда Option был нужен. После этого я перенес эти изменения в исходный код Kotlin, что было так же просто, как удалить один символ ? вместо удаления полной подписи Option[T] и/или Some(T)/map/foreach/for yield invocation.

И хотя легко думать, что Nullable Types и Options функционально эквивалентны, они генерируют очень разные байт-коды, что приводит к различиям в производительности/потреблении памяти.

E.g.

Этот код Scala функционально эквивалентен…

Это код Котлина.

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

Код Scala создает этот байт-код, декомпилированный с помощью декомпилятора Procyon.

Не считая двух дополнительных классов, которые я сюда не включил.

Код Kotlin создает этот байт-код, декомпилированный с помощью Procyon:

Легко, без instanceof, без кастинга, без оберток, без дополнительных вызовов.

Производительность

Давайте поговорим о производительности. Как всегда, мы запустим традиционный тест Monkey fibonacci(35) и сравним Мои реализации на Go, Kotlin и Scala, как интерпретированные(eval), так и скомпилированные/VM

Интерпретируемый режим

И Kotlin, и Scala быстрее, чем Go, что свидетельствует о том, насколько хорошо JVM выполняет JIT-оптимизацию. Но Kotlin в 1,41 раза быстрее Scala.

Если говорить о потреблении памяти:

Kotlin (с JVM) потребляет 367,76 МБ, а Scala (с JVM) — 617,45 МБ.

Скомпилированный режим/режим виртуальной машины

Неудивительно, что Go быстрее, чем Kotlin и Scala, поскольку работа с байтами — одна из сильных сторон Go. Kotlin в 1,38 раза быстрее Scala.

Если говорить о потреблении памяти.

Kotlin (с JVM) потребляет 362,98 МБ, а Scala (с JVM) — 596,64 МБ.

Я все еще поддерживаю свою теорию о том, что использование Option влияет на производительность Scala, но на данный момент это просто теория, поскольку я не могу подключить профилировщик VisualVM к коду Scala, чтобы проверить, что происходит.

Заключение

Scala 3 — хороший язык, новые дополнения сделали язык более понятным. Я по-прежнему предпочитаю Kotlin, но у меня не будет проблем с переходом на Scala на профессиональном уровне.