Oliver

Oliver

Allowing an ignored member in list construction?

One common problem we face in constructing lists is that there is (AFAIK) no support for conditionally inserting members into list declarations.

You can’t write:

allow_even? = false
[
1,
if allow_even? do 2 end,
3
]

because the result would be [1, nil, 3], though syntactically a lot of code would be easier and more readable for us if you could do that.

What if returning a very specific value, like :ignore_list_member would lead to a list being constructed like this:

[1, :ignore_list_member, 3] ==> [1, 3]

Functions could return specifically this value if there’s nothing to insert.

def foo(x), do: if rem(x, 2) != 0 do x else :ignore_list_member end
[
foo(1),
foo(2),
foo(3)
]
===> [1, 3]

Right now we typically do something like piping a whole list like this:

allow_even? = false
[
1,
if allow_even? do 2 end,
3
]
|> Enum.reject(&is_nil/1)

which is fine, but I wonder if this could be solved more conveniently and generic without the need to walk the list a second time after constructing it - just once when it’s “constructed” with the declarative syntax.

If it’s not possible with small effort, I still thank you for reading this. :slightly_smiling_face:

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Yes, but this happens rather a lot and is very well optimized. Eg an Enum.map is a 2x walk because you have to build up the result backwards and then reverse it (or use a body recursive stack, but that’s still functionally a 2x walk since you have to pop the stack).

If you have literally just one optional item btw you can:

if optional_thing do
  [a, optional_thing, b]
else
  [a, b]
end

If you are trying to construct a list that has many different items that may optional interspersed amongst items that are not, I don’t see how the compiler is supposed to do constant optimization. Definitionally you aren’t constructing a constant, you’re constructing a value who’s length varies by a bunch of different values.

Overall I think this discussion of costs is probably misplaced. Are we talking about lists that are literally a handful of items long? If so we’re in hyper optimization land and the code that performs best will rely heavily on exactly what you’re trying to do.

al2o3cr

al2o3cr

At a minimum, I think this would need some alternative syntax because this is already valid Elixir:

[
  :foo,
  if x.something? do :bar end,
  :baz
]

This is distinctly different from Dart, where the regular if is a statement with no value so putting it inside an expression would otherwise be meaningless.

That syntax would also cause headaches for referential transparency, since this should be “the same” code as the above:

extra_var = if x.something? do :bar end

[
  :foo,
  extra_var,
  :baz
]

IMO the better approach is to use a domain-appropriate “empty” element and clean it up if needed. Cleanup may not even be strictly necessary - for instance, if you’re producing a big iolist value with optional parts then [] is a perfectly fine “skip this and go to the next element” marker.

dimitarvp

dimitarvp

On the very rare occasion I’ve done this I just used a list of lists (where the conditional adding of a thing added a non-empty list, and if the condition was false then it simply added an empty list) and then just do List.flatten at the end.

I understand the appeal of having such a language construct but it’s IMO too niche.

Where Next?

Popular in Proposals: Ideas Top

marcandre
I notice that most events have bindings (e.g. phx-keyup) but not the input event. The input event is the preferred way to interact with ...
New
dkuku
This is a proposal to make the map key mismatch errors a bit better: Every time I have a typo It’s very challenging for me even when I u...
New
Aduril
Hello there, Whenever I setup a new project, there is a small function I always add: reply/1. What does it do? In a LiveView mount, han...
New
tubedude
Hey, Earlier i posted a question, but after some research I think a proposal is due. Working on a Phoenix Live View app, I needed clien...
New
PJUllrich
Hey folks, I have the unique problem that I need to ignore all “change” and “input” events for one specific input element in a LiveView F...
New
bartblast
This could resolve to {[a: 1, b: 2]}. Was it ever considered to allow such syntax? Notice this: {:abc, a: 1, b: 2} and this: my_fun(:abc,...
New
superchris
Currently there is no out of the box way to support DOM Custom Events in phoenix. I’ve created a separate library to do this, but I’d lov...
New
New
BartOtten
I’d like to propose that we refrain from using the term "DeadView" as the opposite of “LiveView” and instead choose an alternative. A new...
New
mythicalprogrammer
Hello, since the 1.8rc0 was out, DaisyUI was noted to have the benefit of light and dark mode. From the elixir subreddit, it seem a few ...
New

Other popular topics Top

grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement