Addition of a compact_map/2 function to the Enum module

I also brought up the example of min_max. Is that something that is needed so often that calling {Enum.min(list), Enum.max(list)} became cumbersome? I’d say I need to remove nils from a list more often than I need min_max, and to implement min_max with the existing min and max functions is absurdly easy. Also I wasn’t suggesting there’s no need for uniq, merely that if the issue is bloat, uniq_by(list, & &1) is identical to uniq.

I’m not suggesting that anything needs to be removed from the language, but if the arguments against adding anything is bloat, it’s hard to say there’s not things in Enum already that are arguably bloat, yet they got approved.

The reason for needing compact, is because I would say there’s probably no other single value more frequently returned from an Elixir function than nil(true, and false might be the only other contenders). nil also happens to be a value that is quite often not needed when it’s in a list of other, non-nil values, hence the need to compact. Also I would agree that a compact function is likely bloat because it’s no different than reject(&is_nil/1). My proposal is only for a compact_map function that maps keeping only non-nils.

My argument for codifying it is because it more closely aligns with the way I logically think about that operation, and maybe others do too. If I’m mapping over a list of numbers, adding some value, then keeping anything greater than 5, that’s two clear logical steps in my head, a map, then a filter. But to me “for each item in the list, fetch the result of calling some function that’s not nil” is more how I think of it, than “fetch the result of the function for each item, then filter out the nils”. Surely a lot of the functions in Enum that can be implemented with other functions are there because they more closely align with how we think of something. random is probably how people think of fetching a random element, even if list |> shuffle() |> List.first() is functionally the same. Most people don’t think of a random item as being the first item of a shuffled list, they just think get a random element.

I agree with your sentiment, but not with adding a new function.
You want to filter out nil? I want to filter out empty strings too.
Now I have to rewrite it or add an additional Enum.reject.

1 Like

now what you are saying sounds to me a bit like “if any bloat was added in the past, surely you can add more bloat”, no?

In the end it all boils down to what the core team deems bloat and what – a useful wrapper on top of the primitives. It’s subjective semantics really, though in their case I’d bet it’s more like based on a number of requests and plain old observation of feedback en masse.

I agree the most with @Hermanverschooten here – why is nil special? On a number of occasions I needed to remove empty strings or even empty maps as well. nil is not at all special in the group of “I want to remove a value I can’t act on” scenarios.

Ya, I’m not trying to say anything definitive here, just theorizing.

Again I can just say that it comes down to expressiveness and utility—and that I’ve just never liked the name compact :sweat_smile: I don’t actually agree that stuff like sum and uniq are bloat since they give a clear name to common reductions, even if not used all the time in certain types of problems. Sure sum can be written as reduce(list, &1 + &2) but the problem with that is that the word reduce on its own doesn’t tell very much at all—you have to read the body with very little context as to what’s going to happen. Code would be exhausting to read if everything was reduce, especially when reading quickly! I know you aren’t arguing for that, my point is just that reject is already very expressive and gives you a lot of context as to what will be in the body. reject(&is_nil/1) is really easy to read and IMO even more expressive than compact.

In any event, I’m just bikeshedding since my stance here is indifference. Ultimately, I wouldn’t care very much if this made it into the language!

2 Likes