Good grief, I hope not! :D Unless there is some subtle difference in Erlang between - 13 and -13 (one - might be the negation operator and the other might be the subtraction operator for instance). Hopefully this is just a typo.
With respect to the atoms, since they are basically a bunch of constants that never get dereferenced and so cannot be garbage collected, wouldn't a better way to handle this be to create some kind of out-of-memory look up table, preferably one with good caching of commonly used values?
My understanding of one of the core reasons that erlang is valuable is because of its robustness in a multi-threaded environment. It would be a shame to undermine that robustness by having it blow up because of too many global constants.
The only sane choice here is for Elixir atoms to be Erlang atoms, in the fullest sense of "to be", so that restriction is coming from Erlang, not Elixir. Erlang does exactly what you say; the memory leak in question is when you blow out that table. The Erlang language and runtime permit dynamic atom construction, which is useful because atoms are also the way functions and modules are referenced and it's nice to be able to dynamically compute such things, but if you continuously generate new atoms, you'll run out of memory.
I'm not sure of the virtue of rewriting the Erlang atom rules. apos-quote-atom name-quote seems particular odd, since Erlang already accepts apos-atom name-apos. Though if your grammar requires it, I'd understand. (Though it would still be acceptable to just make it apos-delimited at all times, I think.)
You may actually want to consider deliberately not including head and tail methods on list, as it's usually a sign you're doing something wrong where you should be pattern matching. I'm not saying this is a totally winning argument, but you may want to think about it. (It's better to encourage good code practices than make bad ones easy, and I think when designing languages or even just APIs that's the better perspective to come from, rather than "number of features".)
I'm not sure about the wisdom of making a super-special exception for empty lists to be false. I know the functional heritage behind that, but Erlang is not as list-centric as Lisp and that seems an invitation to more problems. I actually like how strict Erlang is with its "true and false are the only booleans" and if anything think you should be strengthening that, not weakening it.
In fact, in general, while I approve of the general idea of laying objects over Erlang in a useful manner, I think you want to distinguish between extending Erlang, fixing obviously broken things about Erlang (yes, thank you, default UTF-8 strings-as-binaries!), and merely tweaking Erlang. Tweaks are very much to taste, and may be very much more expensive than you realize, both in implementation quirks and the number of people you chase away from one of the core groups you need to attract to have success, which is current Erlang users.
In the case construct, IMHO the "match" clauses ought to be on their own indentation, not matched to the case. Obviously cosmetic. You don't mention whitespace sensitivity, so I assume you aren't using it.
On try and except: You may want to consider requiring that all exceptions be objects, required to be inherited from a base class. Consider Python's experience with exceptions and how they have had to slowly and painfully deprecate strings as exceptions. Erlang exceptions would have to be marshalled into a generic class; consider Perl's Error module for examples on how that works. Also consider giving the user some control over what that automatic marshalling is, be that setting the class or monkeypatching methods in or what have you. Exceptions-as-objects are very powerful but that power dissipates very quickly when you can't count on the exception being an object. (Also that automatic Erlang error class should be a subclass of the top-level Exception, it should not itself be that top-level exception. Subclassing is an "isa" operation, so if the base-level Exception class is also the Erlang-error-marshalling class, that's a claim that all exceptions is-a exception marshalled from an Erlang-level error.)
String interpolation: String interpolation is freaking dangerous and few people treat it with the respect it deserves. String interpolation is basically an invitation to write an escaping failure of some kind every time you interpolate anything. (XSS, SQL injection, Javascript injection, all sorts of things.) Strongly consider some way to make it easy for users to add easy-to-use encoding functions as part of the interpolation specification, and consider giving them some way to actually always default to some level of encoding and requiring an override to do raw interpolation. Or rigidly require a specification of encoding function with every interpolation spec; I think it is absolutely worth an extra character per interpolation point, giving the incredible number of massive security holes interpolation causes. Actually this has nothing to do with Elixir per se, this is almost universally a problem, I can count on half-a-hand the number of times I've seen this done even remotely safely.
inlist in the list comprehension is a grammar smell. You may want to consider backing off the magic there, I'm not sure it's actually winning you anything. Anywhere a language "hides" something from you is an abstraction that can leak.
Method visibility is extremely, extremely, almost unspeakably overrated. It is not a core aspect of object orientation. If you've added that because you passionately believe in it, ok, go for it. But if you've added it merely because you think it's how OO is done, I strongly recommend ripping it back out. It will be a recurring source of pain for very dubious benefit.
One thing that was missing: I'm looking for an OO-based Erlang layer that allows me to write one thing that matches the gen_server behavior, and then allows me to subclass from there to obtain yet more things that are also gen_servers. Perhaps you have that and chose not to show an example, but for me any OO layer missing that feature is a non-starter. As a general principle, work with OTP to the extent possible, don't create a parallel implementation, which I'm just saying so I've explicitly said it.
Also, let me just be clear, this is all my opinion based on relatively rapidly reading that document, but I thought it worth sharing.
Thanks jerf for your feedback even though it was based on rapidly reading the document. I will address a few things:
1) In general I am trying my best to not change the syntax for Erlang data structures. Atoms were one of the few exceptions due to the grammar. I chose to go with the lisp syntax (and similar to Ruby :symbol). But indeed I could have chosen it to be apos-delimited at all times to be closer to Erlang, I have to think more about it.
2) head and tail: good point. The reason they are there though, is if you need to dynamically dispatch a method to retrieve the head or the tail. But in general, I don't think we should limit the language to avoid people writing bad code. We can better solve this problem with good docs (therefore I have removed such bad examples from the README).
3) Empty lists being considered false: I was not sure at the beginning if they should evaluate to false or not but after your feedback I have decided to change so just false evaluates to false. Although in some cases it if feels very weird that a proper nil is missing, for instance Object.__parent__ returning an empty list that evaluates to true feels weird. Maybe I should add nil down the road.
4) "Merely tweaking Erlang" can you give examples where we may be merely tweaking Erlang?
5) case/match: I borrowed the syntax for Ruby and yes, Elixir is not whitespace sensitive. In Ruby, people indent case/match in both ways, I am particularly fine with both.
6) try/catch: yes, I also would like exceptions to be objects (like Python and Ruby). However, the fact I cannot easily have custom guards in Erlang makes that considerably more complicated to implement. Maybe we can add it in the future if more and more people start to use Elixir enough to justify putting a lot of effort in complicated features.
7) String interpolation: I am not aware of such issues. If you could point to more references or discuss it better, I would really appreciate it!
8) The inlist is because we need to make a difference between list and binaries when there is an ambiguity. So what exactly do you propose? To always be explicit here (using inlist or inbin)? Notice that this is an Erlang limitation, the Erlang syntax uses <- and <= to make a difference between them both.
9) Method visibility: hrm, you are actually right. I could have started without this feature and have added it if I eventually needed it. We need the private methods (because they map to local not-exported methods in Erlang) but protected methods could definitely be gone.
10) The GenServer example is not missing, it is in the examples/ folder (too long for the README):
Elixir has also Code::Server (that stores your load paths) and ExUnit::Server (that stores your test cases) that could be used as examples. GenServer in Elixir is very OO'ish and I am particularly happy with the current implementation after going through a few iterations.
Writing Elixir has been an extremely rewarding experience and reading your feedback makes it even better. Thanks again for sharing and I hope you can eventually use it and help us improve it more!
"- 13 x 10 % => 130 "
Good grief, I hope not! :D Unless there is some subtle difference in Erlang between - 13 and -13 (one - might be the negation operator and the other might be the subtraction operator for instance). Hopefully this is just a typo.
With respect to the atoms, since they are basically a bunch of constants that never get dereferenced and so cannot be garbage collected, wouldn't a better way to handle this be to create some kind of out-of-memory look up table, preferably one with good caching of commonly used values?
My understanding of one of the core reasons that erlang is valuable is because of its robustness in a multi-threaded environment. It would be a shame to undermine that robustness by having it blow up because of too many global constants.