What would you remove from Elixir?

language-implementation

#1

Less is more with programming languages.

To that end, what one feature would you remove from Elixir?

(Except for the optional Lisp-like syntax, because i kind of like that ; ))


#2

Tuple keyword pairs, e.g [foo: 1] and replace them with real maps. Not gonna happen though


#3

:atoms because

%{"foo" => value} = input
%{foo: value}

floating point numbers, because

1.0 != 1

#4

I would remove the restriction that keyword lists can only contain atoms as keys :laughing:.


#5

if, cond and unless. Yes they may have use case, but they are also in general a bit too much abused.


#6

The allure of atoms is their speed and memory efficiency. From a small Benchee-powered run:

Name ips average deviation median
match atoms in maps 7.59 M 0.132 μs ±110.46% 0.130 μs
match strings in maps 4.34 M 0.23 μs ±35.97% 0.23 μs

Comparison:
match atoms in maps 7.59 M
match strings in maps 4.34 M - 1.75x slower

Name ips average deviation median
lookup atoms in maps 4.48 M 0.22 μs ±2057.09% 0.20 μs
lookup keys in keyword list 3.04 M 0.33 μs ±1179.91% 0.30 μs
lookup strings in maps 1.39 M 0.72 μs ±330.99% 0.70 μs

Comparison:
lookup atoms in maps 4.48 M
lookup keys in keyword list 3.04 M - 1.47x slower
lookup strings in maps 1.39 M - 3.22x slower

Those numbers appear to be very consistent over multiple runs / changes, and they do indeed add up in real world applications.

Keyword lists and “tagged tuples” are an inheritance from Erlang where they are idiomatic and widely used, and I agree they are not as useful in Elixir on its own but … yeah… legacy is as legacy does, they aren’t going anywhere.

What would you replace them with? Or is your suggestion that all numbers should be able to represent a fractional value, or put another way to get rid of integers as a distinct thing?


#7

Do you prefer function head pattern matching, or other control flow strategies, or?


#8

I don’t think we should loose that. It just seams to me that deciding between strings and atoms is an implementation detail. A smart enough compiler should be able to turned user declared strings into atoms at the places it matters.

Keep integers, they represent a real world concept. In most cases rational numbers (fractions) are all that’s needed.


#9

I’d prefer to keep at least if and cond. if is so much nicer and easier to read than a case which does only match on true and false. As well as a cond is so much nicer to read than a deeply nested cond or an if...then..else if....

But! I’d be very happy if we could remove the implicit else: nil and either replace it with raising something or making it mandatory as in Haskell.

If this had been from the beginning, we hadn’t had any problems with what is called an “imperative assignment” nowadays.


#10

Given how atoms work, that’d be rather dangerous, esp since I’m not sure how one would measure “places it matters”. IMHO, it’s one of those things best left to the smartest, if slowest, compilers: people :wink:

I totally understand how the difference between these “tags-as-values” and strings can feel clumsy and even be confusing (as you noted in your example: the difference between user input and structures in the program itself) … it doesn’t feel super elegant. But, and perhaps this is just because I’m an old and jaded fart who is used to far more annoying baggage in my programming languages, I can forgive this because of the benefits it brings.

On the bright side, it’s nice that there aren’t too many more pressing things in the language :wink:

So you’d introduce a data type that represents rational numbers? A fixed precision decimal type? Because obviously straight up integers don’t suffice everywhere, and it’s somewhere between cumbersome and horrible to try and represent rational numbers with integers.

Is there a use case where this actually matters to you? Or is it just the fact that there are two numeric types annoying in an aesthetic sort of way?


#11

Personally I don’t mind them either and sometimes they are absolutely the best tool to express a specific idea in the code.

What I do notice is that these conditionals get used a lot in some Elixir code when there are other more … idiomatic? … ways of doing it. Some code looks very much like it’s -port-to-Elixir. I know here at work developers new to Elixir avoid things like function-head pattern matching in favor of the seemingly-familiar if even if that more familiar conditional form ends up being less clear to read.

I think we are all just so used to “create a truth value, then test against that; if it fails, create a different truth value and test that” from other languages that the (at times) more elegant pattern matching features are not used as much. I find myself falling into that trap from time to time, as well.

This is why I asked @DianaOlympos about what they meant, to see if they have a general grump about those constructs or if it is more about wishing people would use them more sparingly in lieu of the other mechanisms offered in Elixir that can be more expressive and readable in some/many cases.

I do find that with the embarrassing riches in conditional constructs that are available, it can be difficult at times to decide which to use when. I wonder if over time there will be a stronger tendency towards a given set of idioms in Elixir, or if over time it will evolve into a more Perlesque acceptance of the multitude of equal paths.


#12

if doesn’t add much imo (I prefer case) and the implicit else clause is not obvious to newcomers.

I would also remove the restriction that string keys must precede atom keys in map literals. i.e.

iex> %{"a" => 1, b: 1}
%{"a" => 1}

iex> %{a: 1, "b" => 1}
** (SyntaxError) iex:3: syntax error before: "b"

For a beginner this can be a bit of a wtf moment! :stuck_out_tongue:


#13
iex(1)> %{:a => 1, "b" => 1}
%{:a => 1, "b" => 1}

Probably just me, but I like to stay consistent in any given line and use only either the “atom: value” style or “key => value” style for any one declaration / usage … which neatly side-steps that oddity … which is, as you note … odd. heh.


#14

yes A data type for rational numbers. It would be best if in code divisions got put straight to this type. I believe clojure does this

3
# %Rational{numerator: 3, divisor:1}

2/3
# %Rational{numerator: 3, divisor:1}

Then a number protocol to get decimal values

Number.to_string(1 + 3/2, decimal_places: 2)
# 2.50
Number.to_string(1 + 2/3, decimal_places: 2)
# 1.67

As a protocol it would be extensible to other structs

Number.to_string(%SquareRoot{value: 2}, decimal_places: 2)
# 1.41
Number.to_string(%Pi{}, decimal_places: 2)
# 3.14

#15

+1 for rationals over floats. And maybe a fixed-decimal type. I remember exactly one instance where I needed floating point calculations in the last 2 decades (conversion of Dutch grid coordinates to WGS84 for a mapping application where we had postal code geocoding in the one and the map in the other), countless of times where rational or fixed-decimal type were asked for and I could start my ticket by converting the old (floating-point and thus error prone for money) code to something better fitting.

IMO floating point is the most overrated and unnecessary datatype in our industry. Unless you work in science, or maybe engineering? But that seems to me a vanishing minority, let them include specific libraries.


#16

Yep, it’s because of the legacy of who used, and therefore drove, the technology decisions in past decades.

Ok, so now that I understand the ideas you have in mind (sorry for the many questions earlier; just so many different things one might mean by “no floats”) … yeah, I bet a lot of people would find a decimal / rational number type far more useful and less surprising.

Keeping floats as a special type would certainly be enough for those who truly need them …

nice idea :slight_smile:


#17

Yes, I tend to feel that mixing atoms/strings in a map is a code smell in any case. But the ordering issue definitely contradicts the priinciple of least astonishment!


#18

No floating point , no AI
"Pile of Linear Algebra"


#19

I would think for science you would be most keen to avoid floats. scientific results would definitely want to be more specific about their errors.

I think it should be possible to implement something like this within Elixir Macro’s. I hope to find the time to try eventually. One of the best features is using elixir macro’s to test features which can eventually be a future direction for the language.

I completely forgot but I would also remove with after my macro experiments with alternatives


#20

They may be useful for newcomers so we don’t get a kneejerk “wait, no if statement?” reaction.