Is it a bug how the compiler treats fun params?

Hi! Here’s a simple function that’s goal is to find certain tuples in a List, based on the param Attr:

find_items(List, Attr) ->
  lists:filter(
    fun
      ({_, Attr, _}) -> true;
      (_) -> false
    end,
    List
  ).

Unfortunately the compiler says Warning: variable ‘Attr’ is unused for both lines where the variable appears (1st and 4th in the example above). It seems like the inner fun is shadowing the Attr variable even when it is already bound in the outer scope, and so it is not used in the pattern matching.

The way around it is simple. When I introduce a case statement in the fun, and try to do the pattern match in it, all of a sudden everything’s just fine:

find_items(List, Attr) ->
  lists:filter(
    fun
      (X) ->
        case X of
          {_, Attr, _} -> true;
          _ -> false
        end
    end,
    List
  ).

Is this deliberate? If so, what is the explanation of this strange behavior? Why are params of a fun handled differently?

3 Likes

Hi!

This is deliberate, function parameters shadow variables defined in outer scopes, and you should have gotten a warning saying that. I personally wish that shadowing wasn’t a thing at all, but that ship sailed long ago.

Here’s a proposal that touches on the subject, introducing a new operator ^ that can disable shadowing:

4 Likes

Thanks for the answer. Do you think EEP-55 is gonna be implemented in mainstream Erlang/OTP ever?

If not, do you think that the pin operator could be part of Erlang just to solve the problem I mentioned in this question? (What I mean by that is, fun ({_, ^Attr, _}) -> ... end could mean that I want to use the outer Attr value in the pattern, and I don’t want a new Attr variable inside, but without the pin operator things work just like they did before.)

2 Likes

It’s not up to me, but I’m personally in favor of trying it out through the experimental features framework in OTP 26 or 27. :slight_smile:

3 Likes