Or try Rust. ^.^
109 karma · joined April 11, 2015
[ my public key: https://keybase.io/overminddl1; my proof: https://keybase.io/overminddl1/sigs/_yjDPOb-btS5kW2IkjXrNSAZBKTST1Uxo6O9Y8F__VQ ]
Or try Rust. ^.^
Not at all. The traditional BEAM way of debugging is the tracing modules. For little things an `IEx.pry()` is often good enough though.
Things like a function call is language syntax. You cannot replace language syntax with anything else. Special forms are things like `for` and `with`, and you can replace these with syntax (though that's going the wrong direction in my opinion). Kernel are the standard library bits that are auto-imported into every module (unless explicitly told not to via `except:` or so), these cannot replace special forms or syntax. Etc...
The Pipe operator is just a normal macro in the Kernel, it is redefinable and in fact there are a surprisingly large amount of libraries that do (to make it more monadic interestingly, which makes me think Elixir needs a binding operator in kernel, perhaps `~>` or so).
Things like `fn`/`end` are language constructs, just no way around that at all.
The match operator `=`, interestingly enough, is a special form and not a language construct, so there are times that you can override it as well.
> except of course for Scheme, which is perfect :D
Take a look at Racket, it is scheme refined into bliss. ^.^
> Elixir has some inconsistencies, but I don't think they make the language "hard-to-read" in any realistic way.
Not overall 'hard-to-read' (not like Java for example), but definitely harder than Erlang I'd state.
In addition, naming variables like that in Erlang is a mis-design, the names should be more descriptive.
It is based on Elm so it has a severely limited type system but it is the most complete on Elixir so far. :-)
It's not compiling to elixir, but the `alpaca` language compiles to the BEAM (via erlang core I think) so it gets you close, although they are not black boxing messages sadly.
If you know of someone else doing typing experiments on top of elixir, please link me (my playground code is on my github repo somewhere)!!!
However what you show is not focusing on syntax differences but rather function differences, even `|>` is an (macro) operator. By syntax I'm talking about things like the `do`/`end` and `fn`/`end` and `,do:`/`do...end` mismatches, things like atom key short-form of `someatom: ...` (being short for `:someatom => ...`) only being useful at the end of it's list/map context instead of everywhere (which is not ambiguous nor have any other reason not to do it that I can see), having functions be callable with or without parenthesis (of which thankfully the formatter default puts parenthesis) when functions really should be defined with or without parenthesis and their usage enforced as such, mis-matches in the AST (when creating macro's) by special casing things like 2-tuples among others, and the really weird multi-arity functions of `for` and `with` that really should have been done via body expressions instead of `,` separated expressions (and thus would not need to be special forms but could then just be normal macros, but they seem extremely out of place for the rest of the language syntax), etc.... etc... etc..
It's just a lot of little inconsistencies like that.
Also, if you want pipes for erlang look at the https://github.com/rabbitmq/erlando parse transform (there are others as well, but I like this one), and if you want a shorter erlang form then look at erl2 (just a layer on top of erlang to shorten constructs like module definitions), and of course nothing beats `lfe` on the beam for succinctness and defineability (being a lisp after all).
Also, your Elixir and Erlang codes do not do the same thing. Your Elixir code is being run at compile-time where your Erlang code is not executed at all, only compiled, and thus will only be run if something calls the `tok:start/0` function. The equivalent elixir would be (formatted by the Elixir formatter):
```elixir
defmodule :tok do
def start() do
"Hello,How,Are,You,Today"
|> String.split(",")
|> Enum.join(".")
|> IO.puts()
end
end
```
And you can leave off the final `:ok` on both as both `IO.puts/1` and `io:fwrite/2` both return the atom `ok` in the end. And even then these are not equal as you are working with charlists with one and binaries with the other, so a more direct translation of the Erlang code to Elixir would probably actually be: ```elixir
defmodule :tok do
def start() do
'Hello,How,Are,You,Today'
|> :string.tokens(',')
|> :string.join('.')
|> (&:io.fwrite('~s~n', [&1])).()
end
end
```
That would make the functions equal.As an aside, a few other bits, Elixir defines if a function is public/private via `def`/`defp`, meaning you have to search through a file to see what is exposed, where in Erlang you can see exactly what is and everything that is exposed by just looking at the top.
And yes, `do`/`end` may be longer by one line than Erlang's sequence operator `,` usage, but I don't mind it to be honest, and you can replicate it in Elixir anyway kind of like:
```elixir
def start(), do: (
lst = :string.tokens('Hello,How,Are,You,Today', ',');
:io.fwrite('~s~n', [:string.join(lst,',')]);
:ok)
```
Essentially just replace erlang's `->` with `,do: (`, replace erlang's `,` with `;`, and finally replace erlang's `.` with `)`.Comparing 'function' differences between them is useless of course, they can call each other functions (though macro's are another issue, erlang cannot 'usefully' call elixir macro's, but then again elixir may not soon be able to use erlang's parse transforms either), the differences are the syntax, and Elixir just has a whole ton of oddities.
Overall I find the Erlang syntax (which is similar to SML/OCaml/etc...) far more uniform, sensible, readable, and that it has far less surprising syntactical cases (like why can't I do something like `%{some_atom: 42, "string key" => 6.28}` in Elixir, blah... you have to do `%{"string key" => 6.28, some_atom: 42}` instead for who knows why reasons...).
I do of course use Elixir for my day job, have for over 2 years now, and these are just a few constant things that bug me on a day-to-day basis. However the tooling, macro's, and community (come join us on the Elixir Forums!!!) are top-notch!
If I had my 'choice' of mythical language though, I'd pick something like OCaml with Rust-style ownership semantics with a full staged macro system (Elixir's is a staged macro system) if it were not otherwise possible to safely add in a full Lisp-style macro system (I really don't think so in a full setup like these though, you need a staged system for various corner-case reasons).
> let a = [1,2,3]
undefined
> [x,y,z] = a
Array(3) [ 1, 2, 3 ]
> x
1
> y
2
> z
3Also, the Erlang VM is older than the JVM, initially created in the late 1980's. The JVM, according to wikipedia, was introduced in 1994. Also the BEAM has significantly better GC handling that both the JVM and .NET both since it has a segmented memory model (each actor has segmented memory) unlike the JVM and .NET's monolithic Heap's, this allows it to perform vast optimizations that ensure that the GC is almost never called yet memory is properly and fully reclaimed due to the bounds of the individual Actor heaps, and even when the GC is called it does not stop-the-world or anything of the sort and has multiple layers of GC's that run for specific cases, the system stays running even as the GC's (rarely) runs. The average GC run time even when it does run is measured in the single-digit 'micro'seconds. If anything the BEAM VM is not only just much older than the JVM and .NET VM's, but also more advanced.
There is an ElixirScript project in current dev, still early but usable, that compiles Elixir code to javascript too.
To some Go web api frameworks perhaps.
To the JVM, not really. The frameworks I used with it in the past (spring/play/coupleOtherSmallOnes) are throttled to the number of threads for concurrent connections. The BEAM (Erlang/Elixir) has no such limitation and it blew away my old Java servers handily just due to its concurrency alone.
And not to nodejs at all. Running a single BEAM vs a single node there is no comparison, the BEAM runs circles around it. With nodejs you can shard it out to multiple running instances to get concurrency better but you run into OS limits far before the workload that the BEAM can handle.
However, the BEAM is not very fast on executing actual code, it is like Python in that way where it is good to slave out CPU-heavy work; the BEAM is built for async IO, and yes, running a JVM (or C++) system as a node on a BEAM mesh is fantastic for that (or a port, or NIF for small work).
Consequently I had many of the same complaints, though not quite to the extent or wording he does, so I made my own TEA-like library on Bucklescript/OCaml and ported many of the Elm examples to it, most were basic copy/pastes with the most minor of syntactical differences (`with` instead of `|` and so forth, basically Elm->OCaml differences), I have it up (with code link) at http://overminddl1.com/bucklescript/ if anyone is curious. Not production worthy by any stretch but I do clean it up and add more and more to it over time, already can do near all that Elm's libraries can do, in addition to some of the community libraries.
Continuing on the article, he basically re-implemented OCaml's Witness style (done via OCaml's modules), it was fascinating watching someone build it in Elm I must admit.
He does focus too much on typeclasses, the witnesses he wrote is the way OCaml does it (although with a bit less syntax, and much more an upcoming update), which is not a typeclass form, but something similar.
An aside, where he mentions 'If you don’t want to read the essay, SYTC essentially says “hey, why don’t we pass around an object that describes the implementation of the contract that we care about, rather than having the compiler infer it for us?”. If you’re familiar with Scala, this is how they implement typeclasses in terms of implicit parameters. If you’re not, SYTC is equivalent to passing around a vtable whenever you want to invoke code on a dynamic target.', that is just what OCaml is doing in a soon-coming version with its implicit modules. Definitely looking forward to that, even if they are just fluff. They are basically like Scala's implicit parameters but with type lookup based on module definitions, still explicit, but significantly reduces the code required to be written.