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

That both your cases match is logical and consistent as there is only one type of matching irrespective of whether it is with a =, case or any place where matching occurs. It is really not illogical that it does match as a map in any a pattern means check that it is a map and has at least the key/values specified. Otherwise you would end up with

%{abc: "bert"} = %{abc: "bert", xyz: "carl"}

failing as not all the keys are specified. Which would make the matching almost useless.

8 Likes

Only solution I can think of (but I find it un-Erlangy) is to have “special” syntax for such matches, like:

%{...} = %{abc: "bert"}
%{abc: "bert", ...} = %{abc: "bert", xyz: "carl"}
2 Likes

There is one simple change that should not (in principle) break any existing code, but which can spare inexperienced developers a lot of frustration:

Let structs: false be the default option for inspect/2.

Setting ‘structs’ to either true or false is trivial. Being aware of its existence and recalling it from memory in the middle of a debugging frenzy is not. I had to automate the output of the inspect/2 function (using a keyboard shortcut) simply so that I do not, ever again, forget to set ‘structs’ to false. Opting out of unnecessary detail makes more sense than opting in to access potentially valuable information.

We could say the same about charlists: :as_lists, but on the other hand it also can become confusing in stack traces that use charlists and/or structs.

Yeah this is what I wish Erlang and Elixir both did.

I’m really curios to learn examples where this was useful to you. To me, I much prefer the compact representation but it’s subjective.

Also, worth clarifying, the issue is not just showing structs as underlying maps, its more about NOT using custom inspect implementation for structs, correct?

3 Likes

Take the example of a changeset on which Ecto.Changeset.get_field/3 is applied: the value may be taken from ‘changes’, or from the data struct. When [structs: true], the first one is visible, the second one hidden. This is not an issue at all when you are experienced. At the beginning, however, you miss the fact that there is a struct holed in there. You receive a clue, but it is not enough to guide you. Because, unlike the (also baffling) charlists mentioned by hauleth, that clue is lost amongst a heap of other information.

I hope the above sheds enough light on the issue. Basically, for experienced users, another version of inspect/2, named in a way that would relinquish all claims to in-depth inspection (say glance/1 or peek/1), could provide the compact representation most developers likely prefer.

The problem with structs: false by default is that it returns “raw” representation of struct, so if you will have:

defmodule Foo do
  @enforce_keys [:a]
  defstruct [:a]
end

%Foo{a: 1} |> inspect(structs: false)
# => %{__struct__: Foo, a: 1}

## And now is a problem

%Foo{} # This will fail as not all required keys are present
%{__struct__: Foo} # This will happily pass with invalid structure

Oh, if I wasn’t working on so many other projects, I would.

1 Like

I like that. Seems more useful

If we just want to know if something is a map we can use Kernel.is_map/1

1 Like

I don’t know if it was already said but replacing the arrow <- with in for the comprehension syntax.

This bothers me even more because of the existing of the in keyword for lists
 ¯_(ツ)_/¯

1 Like

There is problem:

primes = [2,3,5,7,9]

for a <- 1..10,
     a in primes,
     do: a * 3

Is completely valid and will filter out non-prime a. So this would make useful feature impossible.

2 Likes

I mean, this is not as if Enum.member? didn’t exist

We are used to write in for iteration in many languages

And precisely use predicate (with question mark) methods for return a boolean

Maybe using in? in the case you illustrated

I bet that currently in is a syntactic sugar anyway


You should see some Erlang code to understand arrows have a special meaning.

Although it looks like Ruby, it comes from Erlang
 Elixir has made a bridge for Ruby programmers to get into Erlang, but Erlang comprehension looks like this.

[X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3].
1 Like

You cant use Enum.member?/2 in guards, but you can use in/2

1 Like

In some yes, but in some no, ex. Scala:

for( var x <- Range ){
   statement(s);
}

But this is more list comprehension, like Erlang’s [X * 2 || X <- [1,2,3]], Haskell’s [x * 2 | x <- [1..3]], or OCaml’s [a * 2 | a <- [1,2,3]].

I would say that in functional languages <- is more popular than in for such syntax.

Yes, but for 2 different results, depending where you use it:

a in b

Will be translated to:

Enum.member?(b, a)

But

def foo(a) when a in [1,2,3]

Will be translated to:

def foo(a) when a == 1 or a == 2 or a ==3
3 Likes

Which ones do you have in mind except for python and rust?

  • Ruby
  • Lua
  • Ada
  • C#
  • C++/CLI
  • ColdFusion
  • Dart
  • Object Pascal
  • Groovy
  • Haxe
  • JavaScript
  • Obj-C
  • Swift
  • VB.NET
  • Batch
  • PowerShell
  • sh
2 Likes

Oh, yes, and half of that list are even languages I had used briefly at least


So yeah, it’s much more languages than I had remembered


few weeks ago I had this idea that it would be cool that when a function body starts with a pipe then use first function param, so instead:

def func(param) do
    param
    |> some_function()
    |> other_function()
end

have a possibility to write it like this:

def func(param) do
    |> some_function()
    |> other_function()
end

it looks clean and afaik a body starting with pipe does not have any other use

2 Likes