berry-lang, attempt #2. New language for BEAM with static typing

Just this weekend, I wrote an article about wanting to make a new language for BEAM with static typing. Having received a lot of feedback (most of it was, as usual, between the lines), I want to present to your attention the 2nd edition – completely revised. So – to both yours and ours.

The new plan is to use the Elixir syntax as it is (yes!) Well, except to add types to it. Make the correspondence of modules and physical files 1:1. Make the syntax for imports similar to the one in python.

There will be no macros in berry. But macros from the elixir libraries can be used! This is necessary so that you can use libraries like Ecto and Phoenix. You can import a macro in the same way as a normal function. In this case, under the hood everything will happen the same as in the elixir.

So if you want to use macros, go to your elixir, write them there. And we don’t like that. In short, the new plan is to fix Elixir. Are you asking if I would like to share this idea with the wider community? I already did it! But what was the reaction – read about it under the cut.

* * * * * * * * * * * * * * * *

I think the first question you have when you read the preface is whether it is possible to add types to Elixir. If you read the previous article, you should guess that – you can:

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

If you use pattern matching inside a function, annotations can be written outside the parentheses:

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

A common use of guards is through parenthesized conditions after the type:

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

Usage in case:

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

In erlang (and elixir) it is impossible to get the type of the current value in the usual ways, therefore, if the type is there, it means that it was explicitly indicated there.

As you can see, adding types to the elixir is quite feasible. Having reasoned the same way and not bothering to think about further details, I decided to immediately share the idea with the community by writing a text on the forum with the following content:

For those who do not want to read the fine print, I retell the content: “Everyone knows that elixir has 2 minuses – these are macros and the absence of types. Popular wisdom says that a minus times a minus gives a plus. In this regard, why not make a version Elixir 2.0, which adds types and removes the ability to write macros at the same time. Given the hype that will cause the addition of static typing, everyone is migrating to Elixir 2.0 very quickly.” At the end, I added soothing phrases that it is not necessary to cut out macros in their entirety, you can leave a part – the most necessary ones.

I think readers roughly understand that, in response to this proposal, I received a lot of bright remarks. Here, for example, is one of them:

“At this stage, I’m sure it’s an April Fool’s joke, but it doesn’t fit the season right now.” In general, the moderators realized it only when there were already under 30 messages in the topic – so this is a success. I did not even expect that he would pass the initial moderation. The main idea of ​​the speakers was that macros are one of the most important features of the language, and that no one will cut it out even at gunpoint.

Thus, in front of the item “communication with the community” it was possible to safely put a tick. But back to the berry-lang implementation plan.

Since we started talking about macros, I have a very simple idea how to deal with them. Macros written in Elixir can be used in berry – they can be imported from the package like regular functions. At the same time, it is impossible to write macros on berry: in the end, the elixir does not go anywhere, if you want, write your own macro on it and use its library as a dependency. Thus, we get the opportunity to use Ecto, Phoenix and other libraries that are so rich in keywords.

Regarding modules: having got rid of macros and the need for the “use” construct, we can now have a transparent system of modules and imports. Each module corresponds to the file where its source code is located and is named the same way. The “defmodule” construct, it turns out, is not needed, and everything that was under this construct gets into the berry module.

By the way, what extension to choose for modules, *.be?

For imports, I was going to take the syntax from python:

from pak.more_pak import something

But then I remembered that Ecto has a macro from. Better to be able to use it without renaming. Therefore, you can take a more modest version, for example, from gleam:

import pak/more_pak {something}

Of course, the import of macros will only look like a regular import, under the hood, the same thing will happen during compilation as in the elixir.

What do you think about it, dear reader?

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *