Anything, from syntax to the core library.
Swap def
and defp
to encourage people to keep the public interface as small as possible. Alternatively keep the export lists.
Merge for
and with
to have do
-notation-like semantic where I could do āmonadishā expansion of error tuples.
I never remember the sigil syntax for regexp, would gladly use something that is hard-wired to my brain from Ruby or JavaScript :).
I would glady get rid of keyword lists in favour for just using maps everywhere (but I guess this canāt happen).
I would get rid of all global functions and require developer to explictly call them on Kernel module etc.
I would think of including a decent HTTP client into core library, so the same thing does not get re-implemented dozen of times, in incomplete fashion (as it is now). This is not happening as is a big job, but one can have dreams :).
I would like to Erlang Distributed applications usable in modern multi-server deployment environments http://erlang.org/doc/design_principles/distributed_applications.html , where network interruptions are more likely than node failures. I like the concept and I think it can work well for many of us as a simple clustering solution.
I always remember it as ~r
as from regexp.
Erlang still uses prop lists and it would be hard to replace one with another, as many libraries depend on it, notably Ecto would be much less idiomatic with maps instead of kw lists.
You have simple HTTP library in core - httpc
. It is simple, without any bells and whistles, but for simple requests it does proper job.
Predictably I want static types.
Could you give an example? Not sure what you mean
I would like to see something like where
from Haskell (private functions for function). This helps to group functionality in the module. But I canāt imagine syntax for this.
Imagine that I want to iterate through list in form of list = [{:ok, list1}, :error, {:ok, list2}]
, with current Elixir I need to do:
for outer <- list do
case outer do
{:ok, inner} -> {:ok, for item <- inner, do: foo(item)}
:error -> :error
end
end
In Haskell I can do something like:
do
outer <- list,
inner <- outer, -- we assume that `list` has type `Monad m => [m [a]]`
item <- inner,
foo item
Similar syntax was supported by @OvermindDL1ās ex_core
comprehensions(I believe so) in form of:
comp do
outer <- list list
{:ok, inner} <- outer
item <- list inner
foo(item)
end
Itās your lucky day! Thatās how list comprehensions work today.
iex(1)> list = [{:ok, [1, 2]}, :error, {:ok, [3, 4]}]
[{:ok, [1, 2]}, :error, {:ok, [3, 4]}]
iex(2)> for {:ok, xs} <- list, x <- xs, do: x
[1, 2, 3, 4]
I find it interesting how fully hiding the fact that some items will never be called with foo(item)
is something actually desirable. Like the haskell code you wrote doesnāt communicate in any form that thereās actually a conditional in the code. I could see how a pattern match could convey the conditional, but the problem is that the semantic of <-
in elixir is to abort for the current input (and go to the next one in case of for
and go to the else clause in case of with
) and not to simply return the input.
If your really want to hide it why not do it properly in a function?
Enum.map(list, &apply(&1, &foo/1)
def apply({:ok, items}, callback), do: {:ok, Enum.map(items, callback)}
def apply(:error, _), do: :error
Thatās not how monads work though. Monadic operartions wouldāve retained the nested structure and not got rid of the error elements.
And this is impossible as well, as def
, defp
, defmodule
, if
, etc. are all macros in the Kernel
module, so you would need to import them in almost all files. That would be a little bit irritating.
Oh I see! Thanks.
Lots of languages work this way (Haskell, Elm, Purescript, Rust, etc), and itās not too bad. They tend to have a module that is imported by default, for Elixir that would be Prelude.
Thatās exactly what happens with Kernel
right now.
Dialyzer error messages
Having to repeat def and the function name when defining a function with multiple clauses. I find it troublesome for several reasons:
- Order of clauses is important; having them free floating and independent means that isnāt syntactically represented in the source.
- When reading code I find I have to flip back and forward between clause definitions just to make sure that the names are exactly the same.
- When writing code it is easy to misprunt a name and end up with a separate function.
- It leads me to want to use ācaseā as it makes explicit the ordering, but then you lose the communication benefits of expressing patterns in function signatures.
We have a compiler warning suggesting we at least group them together, which is a start. Having a form of def that combines all of the clauses into a single construct would lead people to code in a style that avoids the problem altogether.
I wonāt lie, the extra verbosity bothers me too, but thatās a style thing, which is less important than the correctness and comprehensibility issues that I experience.
keyed maps support in syntax / guards
OLD:
def verify(%{user_id: user_id, user_balance: user_balance}), do: user_id
NEW:
def verify(%{user_id, user_balance}) when user_balance > 0, do: user_id
Basically writing a map like %{user_id} implies to the compiler to expand it to %{user_id: user_id}
user_id = 5
new_map = %{user_id}
insert support too
There was a proposal for thisā¦
https://elixirforum.com/t/proposal-add-field-puns-map-shorthand-to-elixir/15452
I would also enjoy to see this, because some function signatures are very long, and that would help reducing them.
I wish Elixir didnāt allow circular dependencies between modules as Iāve found these resulted in harder to follow code and slower (sometimes by a big factor) (re-)compilation speeds. Some programs with cycles that are working now might be harder to re-write without them, so Iād be curious to see patterns emerge around that (some form of āAll problems in computer science can be solved by another level of indirectionā I assume)
If I could choose only āone thingā in Elixir the ālanguageā (not the platform) as per the title, then an enhanced HM inference static typing system, like @lpil as well.
Other things Iād want in no particular order:
- @wojtekmachās thing of not allowing cycles would be great during compilation, that is usually native with strong static type systems though.
- Minimize special syntax, like
case
should be a minimal thing, and things likefor
/with
should usedo
blocks like everything else for consistency rather than super-weird multi-arity function-like things, like @hauleth suggested. - Want Elixir to use proplists full and proper, not just itās simplified keyword lists.
- Few other minor things but the big things were already posted well here.
Also @vanc163, there are libraries for that like:
But what is simplified in kw lists in comparison to proplists? Ok, proplists have special handling for pure atoms and treats them as {atom(), true}
, but such simplification was needed in Erlang, which do not have sugar for such structure as writing {atom(), true}
when you need just simple boolean switch is troublesome. In Elixir there is no such shortcoming, so I do not see much problem there.
How could case
become more minimal?
How would that work syntax wise for when the do-block today is made of multiple expressions and has filters? Just as an example:
for x <- list, y <- another_list, x < y do
IO,puts x
IO.puts y
x + y
end