Возможно/полезно ли транспилировать Scala в golang?

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

Поэтому мне интересно: почему бы просто не транспилировать Scala в Go (а-ля Scala.js)? Это будет быстрая переносимая среда выполнения. И их ГК становится все лучше и лучше. Не говоря уже о наследовании отличной модели параллелизма: каналов и горутин.

  • Так почему же scala-native решили использовать LLVM на таком низком уровне?
  • В чем была бы загвоздка с транспайлером golang?

person sscarduzio    schedule 26.05.2016    source источник
comment
Это довольно ранние дни для scala-native, и очевидно, что они немного избалованы сборщиком мусора JVM, наверняка потребуется некоторая оптимизация. Но главная причина в том, что llvm — безумно хороший язык для написания языков. IIUC llvm будет поставляться с некоторыми встроенными опциями gc в будущих версиях.   -  person Andy Hayden    schedule 27.05.2016
comment
О полезности: java уже является быстрой переносимой средой выполнения, ориентированной на Scala, проверенной десятилетиями в критически важных приложениях. Так в чем будет польза?   -  person adrobisch    schedule 27.05.2016
comment
Время запуска и объем памяти для небольших приложений. Другими словами: системное программирование.   -  person sscarduzio    schedule 27.05.2016


Ответы (1)


Есть два типа языков, которые являются хорошими целями для компиляторов:

  1. Языки, семантика которых близко соответствует семантике исходного языка.
  2. Языки, которые имеют очень низкоуровневую и, следовательно, очень общую семантику (или можно возразить: семантики вообще нет).

Примеры для № 1 включают: компиляцию ECMAScript 2015 в ECMAScript 5 (большинство языковых дополнений были специально разработаны как синтаксический сахар для существующих функций, вам просто нужно их), компиляция CoffeeScript в ECMAScript, компиляция TypeScript в ECMAScript (в основном, после проверки типов просто сотрите типы, и все готово), компиляция байт-код Java в JVM, компиляция C♯ в байт-код CLI CIL, компиляция Python в байт-код CPython, компиляция Python в байт-код PyPy, компиляция Ruby в байт-код YARV, компиляция Ruby в байт-код Rubinius, компиляция ECMAScript в SpiderMonkey байт-код.

Примеры для № 2 включают: машинный код для ЦП общего назначения (RISC тем более), C--, LLVM.

Компиляция Scala to Go не подходит ни для того, ни для другого. Их семантика очень отличается.

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

На самом деле, даже байт-код JVM уже слишком высокоуровневый! У него есть такие конструкции, как классы, которые не соответствуют таким конструкциям, как трейты Scala, поэтому должно быть довольно сложное кодирование трейтов в классы и интерфейсы. Точно так же до invokedynamic было практически невозможно представить динамическую диспетчеризацию структурных типов в байт-коде JVM. Компилятору Scala пришлось прибегнуть к отражению или, другими словами, преднамеренно выйти за пределы семантики байт-кода JVM (что привело к ужасным потерям производительности при диспетчеризации методов для структурных типов по сравнению с диспетчеризацией методов для других типов). типы классов, хотя оба они одно и то же).

Другим примером являются правильные хвостовые вызовы: мы хотели бы иметь их в Scala, но поскольку байт-код JVM недостаточно мощен, чтобы выражать их без очень сложного сопоставления (по сути, вы должны отказаться от использования вызова JVM стек и управлять своим собственным стеком, что разрушает как производительность, так и совместимость с Java), было решено не иметь их в языке.

У Go есть некоторые из тех же проблем: чтобы реализовать выразительные нелокальные конструкции потока управления Scala, такие как исключения или потоки, нам нужна столь же выразительная нелокальная конструкция потока управления для сопоставления. Для типичных целевых языков эта "выразительная нелокальная конструкция потока управления" является либо продолжением, либо почтенным GOTO. Go имеет GOTO, но намеренно ограничивает свою "нелокальность". Для написания кода людьми ограничение выразительных возможностей GOTO — это хорошо, но для целевого языка компилятора не так уж и много.

Очень вероятно, что можно создать мощный поток управления с помощью горутин и каналов, но сейчас мы уже покидаем удобные рамки простого сопоставления семантики Scala с семантикой Go и начинаем строить высокоуровневую семантику Scala поверх высокоуровневой семантики Go. семантика, не предназначенная для такого использования. Горутины не были разработаны как общая конструкция потока управления для создания других видов потока управления поверх него. Это не то, в чем они хороши!

Так почему же scala-native решили использовать LLVM на таком низком уровне?

Потому что это именно то, для чего LLVM был разработан и в чем он хорош.

В чем была бы загвоздка с транспайлером golang?

Семантика двух языков слишком различна для прямого сопоставления, а семантика Go не предназначена для построения поверх семантики разных языков.

их ГК становится все лучше и лучше

То же самое можно сказать и о Scala-native. Насколько я понимаю, выбор для текущего использования Бёма-Демерса-Вайзера в основном связан с ленью: он есть, он работает, вы можете добавить его в свой код, и он просто сделает свое дело.

Обратите внимание, что изменение GC обсуждается. Существуют и другие GC, разработанные как встраиваемые, а не тесно связанные с макетом объекта виртуальной машины хоста. Например. IBM в настоящее время находится в процессе реструктуризации J9, своей высокопроизводительной JVM, в набор слабо связанных, независимо повторно используемых компонентов «строительных блоков среды выполнения» и выпускает их под разрешительной лицензией с открытым исходным кодом.

Проект называется "Eclipse OMR" (исходный код на GitHub), и он уже готов к работе: реализация IBM J9 на Java 8 была полностью построена из компонентов OMR. Существует проект Ruby + OMR, который демонстрирует, как легко интегрировать компоненты в существующую языковую среду выполнения, поскольку сами компоненты предполагают нет языковой семантики и нет конкретной памяти или расположения объектов. коммит, который заменяет сборщик мусора и добавляет JIT, а профилировщик обрабатывает чуть более 10 000 строк. Он не готов к производству, но загружает и запускает Rails. У них также есть аналогичный проект для CPython (пока не общедоступный).

почему бы просто не транспилировать Scala to Go (а-ля Scala.js)?

Обратите внимание, что у Scala.JS много тех проблем, о которых я упоминал выше. Но они все равно это делают, потому что выгода огромная: вы получаете доступ ко всем веб-браузерам на планете. Для гипотетического Scala.go нет сопоставимого выигрыша.

Есть причина, по которой существуют инициативы по добавлению низкоуровневой семантики в браузер, такие как asm.js и WebAssembly именно потому, что при компиляции языка высокого уровня в другой язык высокого уровня всегда возникает этот "семантический разрыв", который необходимо преодолеть.

На самом деле обратите внимание, что даже для низкоуровневых языков, которые были специально разработаны как цели компиляции для определенного языка, вы все равно можете столкнуться с проблемами. Например. У Java есть дженерики, у байт-кода JVM нет. В Java есть внутренние классы, а в байт-коде JVM — нет. В Java есть анонимные классы, а в байт-коде JVM — нет. Все это должно быть как-то закодировано, и конкретно кодирование (или, скорее, некодирование) дженериков вызвало все виды боли.

person Jörg W Mittag    schedule 27.05.2016
comment
Это идеальное объяснение, почему Scala Native компилируется в LLVM, а не в Go. - person Denys Shabalin; 29.05.2016
comment
Я думаю, что тот факт, что байт-код JVM не имеет дженериков, также позволил Scala иметь более богатую систему типов, чем Java. - person Jasper-M; 28.02.2017
comment
@Jasper-M: Существовала (теперь заброшенная) реализация Scala для .NET. .NET овеществляет дженерики в виртуальной машине. Насколько я знаю, это не создало проблем для Scala, поскольку в Спецификации языка Scala говорится, что дженерики все равно стираются. Я не думаю, что это ограничение. Это может затруднить интеграцию со сторонними библиотеками .NET, что является основной целью Scala, но не ограничивает основную семантику Scala. Обратите внимание, однако, что Scala.NET был заброшен довольно давно, и система типов с тех пор изменилась, поэтому, возможно, вы правы, и сегодня это было бы проблемой. - person Jörg W Mittag; 01.03.2017
comment
Я думал, что материализованные дженерики были одной из причин, по которой от него отказались. Но я могу ошибаться. - person Jasper-M; 01.03.2017