
Show HN: Rhine – A typed Elixir-inspired language on LLVM - artagnon
https://github.com/artagnon/rhine?
======
davidw
Building any language is hard, so congrats!

That said... the big thing about Elixir is that it's got Erlang and OTP behind
it.

~~~
sdegutis
> Building any language is hard, so congrats!

Absolutely. Having tried to write a dead-simple Lua-like language [1], I can
attest that it requires the programmer have a very complex graph of semantic
requirements in their head at all times while writing the language, in order
to not mess anything up, involving the types, the GC, the compiler, the
parser, the lexer, the calling conventions, everything. I have high respect
for anyone who actually goes through with writing one to a point of it being
usable.

[1]: it did not go well, so much so that I have absolutely nothing to show for
it

------
pmontra
I gave quick look at the example. First reactions coming from OO languages and
Elixir:

I can imagine that this

    
    
        def addCandidate(A ~Int, B ~Int) do
    

means that addCandidate has two arguments of type Int, but what does the ~
mean? I'll have to read the docs.

However I have really no idea of the meaning of

    
    
        def bar(arithFn ~Function(Int -> Int -> Int)) do
    

It's a function bar taking arithFn as argument, which is a function with...
what arguments?

From the demo program it looks like a function with two int arguments
returning an int, but why the -> signs and why isn't addCandidate defined as
(Int -> Int -> Int) too? Where is it's return type. Maybe inferred?

It's quite puzzling and there are no explanations about that in the README.

Is the ~ necessary? Could it be removed and save one character that's not even
on some keyboards around the world?

Apart from that lack of explanations, it could a perfectly nice language and
it's a great project for sure.

~~~
artagnon
Thanks for the feedback. The ~ is a substitute for :, which is used in other
languages for optional type annotations. You're right about removing ~
altogether, Go style. ~Function(Int -> Int -> Int) is a function which takes
two integers, and returns one. I've mixed in some Haskell syntax there. And
yes, return type is inferred.

There are two reasons for there not being explanations in the README:

1\. I foolishly thought it would be obvious.

2\. I wanted to focus on the implementation, not the language itself.

In any case, I've added them now, thanks.

~~~
pmontra
Thanks to everybody for all these explanations! I understand the logic of the
syntax now.

A nice thing with Elixir is that it lures OO developers like me into the realm
of functional languages with a familiar syntax. Int -> Int is not familiar to
me. I could guess what it is but then I also see an Int, Int and feel a little
puzzled. If one of the goals of this language is to "convert" OO developers
maybe you should consider a syntax they are fully familiar with. You could
make long time functional developers feel not at home though. Maybe it's a
trade-off that's impossible to avoid. It's your call.

------
AsyncAwait
Nice project.

As was already mentioned, the main benefit of Elixir seems to come from BEAM,
(Erlang VM) and its associated cockroach-like properties. There's also Crystal
([https://github.com/crystal-lang/crystal](https://github.com/crystal-
lang/crystal)), if what you want is a Ruby-inspired language with static
typing and compilation to native code.

~~~
artagnon
I needed a title. I could have said Elixir-inspired or Crystal-inspired, but
few people know about Crystal. Although it's only minimally inspired by
Elixir, I decided to go with that title.

By the way, I've mentioned Crystal towards the end of the README.

------
pori
> Effort put into rhine-ml: 2 months

> Effort put into rhine: 1 year, 1 month

Props for the effort put into this! I came across rhine-ml a while ago and
thought it would have been a nice, native alternative to Clojure. Both of
these projects look very well thought out.

Curious, is this a learning project? It seems that way considering you go into
detail about the inner workings.

~~~
artagnon
Thank you. I actually made a lot of design mistakes in both rhine-ml and
rhine, which is why I shelved them as "learning projects". I do fully intend
to write a solid compiler for a well-designed language in the future. I have
to make my mistakes first.

So, for the curious, the big mistake in rhine-ml is making it untyped: it
generates terrible LLVM IR that executes super-slowly. I could try and
optimize it, or go the types route. I chose types, and I don't believe in the
optional-typing escape hatch.

The big mistake in rhine is that I wrote it in C++. It'll be a decade before
it can lift its own weight, and OCaml is a great language to build a compiler
in.

------
jupp0r
Does it have tail call elimination?

~~~
artagnon
Nope, sorry. And that was kind of the point I was making: in over a year, I've
only been able to do the most foundational work in C++. It'll need another 2~3
years to feature optimizations like that.

