На этих выходных я написал статью о том, что хочу сделать новый язык для BEAM со статической типизацией. И получил объёмный фидбэк - большая часть его содержалась, как обычно, между строк. Теперь хочу вам представить издание 2е, полностью переработанное.

Новый план состоит в том, чтобы использовать синтаксис Elixir как он есть (да!) Ну, разве что, типы в него добавить. Также, нужно сделать соответствие модулей и физических файлов 1:1.

UPDATE: berry будет поддерживать макросы, но только импортируемые - не важно, написанные на эликсире или на berry. use поддерживаться не будет.

import Ecto, macros: [from]

Таким образом, фанатам Ecto беспокоиться не о чём. Вы хотите спросить, не хочу ли я поделиться этой идеей с более широким сообществом? Я уже сделал это! А вот, какая была реакция - об этом читайте под катом.

* * *

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

def my_fun(x: Integer, m: Map) -> Bool do
end

Если вы используете внутри функции паттерн-матчинг, аннотации можно писать за скобками:

def my_fun([head | tail]) when head: Integer -> Bool do

Обычное использование guards - через условия в скобках после типа:

def my_fun(s: String(starts="-"), m: Map(size>0)) -> Nil do

Использование в case:

case m do
  %{x: x} -> ...
  Map(size>0) -> ...
end

В эрланге (и эликсире) нельзя получить тип текущего значения обычными способами, поэтому, если там стоит тип - это значит, его там явно указали.

Важная деталь: весь текущий синтаксис эликсира остаётся валидным в berry: секцию when можно писать и в обычном стиле тоже:

def my_fun([head | tail]) when is_integer(head) do

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

В целом, добавить типы в эликсир - вполне осуществимо. Рассудив таким образом и не утруждая себя обдумыванием деталей, я решил сразу поделиться идеей с сообществом, написав на форум текст такого содержания:

Для тех, кому лень читать мелкий шрифт, пересказываю содержание: "Всем известно, что в эликсире два минуса - это макросы и отсутствие типов. Народная мудрость гласит, что минус на минус даёт плюс. В связи с этим, почему бы не сделать версию Elixir 2.0, в которой одновременно добавить типы и убрать возможность писать макросы. Учитывая хайп, который вызовет добавление статической типизации, все очень быстро мигрируют на Elixir 2.0". В конце добавил успокоительную фразу о том, что не обязательно выпиливать макросы целиком, часть можно оставить - наиболее нужные.

Я думаю, читатели догадываются, что, в ответ на это предложение, я получил много ярких реплик. Вот одна из них :

"Теперь я вижу, что это первоапрельская шутка, хоть она и не подходит к сезону" (к сезону-то как раз подходит!). В общем, модераторы спохватились, только когда в топике уже было под 30 сообщений, так что это успех. Я не ожидал даже, что он первичную модерацию пройдёт. Основная мысль выступающих была, что макросы - это одна из важнейших фич языка, и что выпиливать её никто не станет даже под дулом пистолета.

Таким образом, напротив пункта "общение с сообществом" можно было смело ставить галочку. Но вернёмся к плану по внедрению berry-lang.

Раз уж начали говорить про макросы - у меня есть очень простая идея, как с ними быть. В berry будет разрешено использовать макросы, написанные на Elixir. При этом, писать макросы на berry будет нельзя: в конце концов, эликсир никуда не девается, хотите - пишите свой макрос на нём и используйте его библиотеку как зависимость. Таким образом, мы получаем возможность использовать Ecto, Phoenix и другие библиотеки, столь богатые на ключевые слова. Даже слово "use" можно разрешить для таких случаев - нам не жалко.

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

import Ecto, macros: [from]

use поддерживаться не будет. Это означает отсутствие поддержки Phoenix и ему подобных. Они с типами всё равно работать не могут, поскольку о типах не знают. А если не использовать типы, почему не писать на эликсире?

По поводу модулей: избавившись от макросов и от необходимости в конструкции "use", мы обнаружим, что совершенно не важно, в каком модуле находится функция. Поэтому естественно будет иметь прозрачную систему модулей и импортов. Где каждый модуль будет соответствовать файлу, где лежит его исходный код, и называться так же. Конструкция "defmodule" будет не нужна, а всё что было под этой конструкцией, попадёт в модуль berry.

Кстати, какое расширение выбрать для модулей, *.be?

Для импортов можно взять синтаксис эликсира, несмотря на то, что он довольно неуклюжий:

import my.mod, only: [my_func: 2]

Правда, есть проблема: import в эликсире используется только для функций и макросов, а для модулей нужно использовать require и alias. Конечно, 3 ключевых слова для импорта - это безобразие: нужно оставить только import, а остальные два сделать deprecated. И научить import импортировать модули. Кстати, импортировать также нужно будет и типы: они ведь тоже появятся. Можно сделать так:

import pak.pak2.mod,
  functions: [my_fun],
  macros: [my_macro],
  types: [MyData]

Итоговый список изменений в Elixir:

  • добавляем типы

  • 1 модуль = 1 файл, делаем единый способ импорта чего угодно по имени

  • запрещаем писать макросы

Если ещё резюмировать, berry - это диалект эликсира, который совместим с ним не только по функциям, но и по макросам. При этом, в нём самом макросы забанены.

Что скажет читатель? Должно полететь?

Комментарии (14)