If you could change one thing in Elixir language, what you would change?

syntax
core
learning-elixir

#1

Anything, from syntax to the core library.


#2

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.


#3

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.


#4

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.


#5

Predictably I want static types. :slight_smile:

Could you give an example? Not sure what you mean


#6

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.


#7

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

#8

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]

#9

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.


#10

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.


#12

Oh I see! Thanks. :slight_smile:

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.


#13

That’s exactly what happens with Kernel right now.


#14

Dialyzer error messages :wink:


#15

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.


#16

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


#17

There was a proposal for this…

I would also enjoy to see this, because some function signatures are very long, and that would help reducing them.


#18

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)


#19

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 like for/with should use do 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:


:slight_smile:


#20

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.


#21

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