Use of logical "not" in `case`

6 messages
Open this post in threaded view
|

Use of logical "not" in `case`

 Someone asked me an interesting question about readability of case statements, and I'd like some alternative opinions (because I can't decide myself). When writing a case statement based on a boolean expression, like whether or not to take an action depending on whether or not a given value is a key in a map, I tend to put the value that causes something to happen first assuming that this will be the most interesting path. For example: foo(Status, Thingy, Assignments) ->     case maps:is_key(Thingy, Assignment) of         false ->             Assignment = fomulate_assignment(Thingy),             NewAssignments = maps:put(Thingy, Assignment, Assignments),             {assigned, NewAssignments};         true ->             {Status, Assignments}     end. This isn't the best example case, but you get the idea. We care about the case where Thingy was not already assigned and have to do something there, and we just pass the values back in the case it already was. Here the false case came first -- it could have come second, that doesn't *really* matter to me, but I tend to put the interesting stuff up front. Now compare: foo(Status, Thingy, Assignments) ->     case not maps:is_key(Thingy, Assignment) of         true ->             Assignment = fomulate_assignment(Thingy),             NewAssignments = maps:put(Thingy, Assignment, Assignments),             {assigned, NewAssignments};         false ->             {Status, Assignments}     end. The argument was that 'true' should always be the more interesting case (whenever there is a more interesting case) because that reads closer to the semantics of the check being done were we to describe it in conversation "If A is *not* a member of B, then [stuff]". That makes sense to me. It sounds like a reasonable argument. This isn't a big deal either way of course (I find them both equally readable), but I am curious if anyone has a strong opinion on the issue and why. Which would you prefer to encounter when reading a project to understand how it works on github? -Craig _______________________________________________ erlang-questions mailing list [hidden email] http://erlang.org/mailman/listinfo/erlang-questions
Open this post in threaded view
|

Re: Use of logical "not" in `case`

 On 02/09/2018 10:31 AM, [hidden email] wrote: [...] > foo(Status, Thingy, Assignments) -> >      case not maps:is_key(Thingy, Assignment) of >          true -> >              Assignment = fomulate_assignment(Thingy), >              NewAssignments = maps:put(Thingy, Assignment, Assignments), >              {assigned, NewAssignments}; >          false -> >              {Status, Assignments} >      end. [...] > This isn't a big deal either way of course (I find them both equally readable), but I am curious if anyone has a strong opinion on the issue and why. Which would you prefer to encounter when reading a project to understand how it works on github? Oh boy. I would definitely get tripped by this. Or at the very least have some eyebrow action. I have no problem with it in something like C because there's usually no 'else' clause in these cases and it's therefore very easy to read the intent. But in Erlang's case what you effectively do is invert the boolean value below and that requires a little more gymnastic. And I don't think it matches what one would say in a conversation because why would you mention the case where nothing happens at all? -- Loïc Hoguin https://ninenines.eu_______________________________________________ erlang-questions mailing list [hidden email] http://erlang.org/mailman/listinfo/erlang-questions
Open this post in threaded view
|

Re: Use of logical "not" in `case`

 In reply to this post by zxq9-2 The `not maps:is_key` makes it NOT less confusing. `true` or `false` don’t carry meaning per se, thus cannot be used to form an argument. The question gives meaning. Are you hungry? Are you not hungry? Simpler questions are better. Michael > On Feb 9, 2018, at 10:31 AM, [hidden email] wrote: > > foo(Status, Thingy, Assignments) -> >    case not maps:is_key(Thingy, Assignment) of >        true -> >            Assignment = fomulate_assignment(Thingy), >            NewAssignments = maps:put(Thingy, Assignment, Assignments), >            {assigned, NewAssignments}; >        false -> >            {Status, Assignments} >    end. _______________________________________________ erlang-questions mailing list [hidden email] http://erlang.org/mailman/listinfo/erlang-questions
Open this post in threaded view
|

Re: Use of logical "not" in `case`

 In reply to this post by Loïc Hoguin-3 I do prefer the "true" case first, since that more closely emulates a traditional "if" statement.  However, the condition should then be written to match.  In your case, I'd prefer a helper function is_key_absent/2 (or sth like that) rather than a barely visible "not". Just my 0.02 SEK. On Fri, Feb 9, 2018 at 10:40 AM, Loïc Hoguin <[hidden email]> wrote: > On 02/09/2018 10:31 AM, [hidden email] wrote: > [...] >> >> foo(Status, Thingy, Assignments) -> >>      case not maps:is_key(Thingy, Assignment) of >>          true -> >>              Assignment = fomulate_assignment(Thingy), >>              NewAssignments = maps:put(Thingy, Assignment, Assignments), >>              {assigned, NewAssignments}; >>          false -> >>              {Status, Assignments} >>      end. > > [...] >> >> This isn't a big deal either way of course (I find them both equally >> readable), but I am curious if anyone has a strong opinion on the issue and >> why. Which would you prefer to encounter when reading a project to >> understand how it works on github? > > > Oh boy. I would definitely get tripped by this. Or at the very least have > some eyebrow action. > > I have no problem with it in something like C because there's usually no > 'else' clause in these cases and it's therefore very easy to read the > intent. > > But in Erlang's case what you effectively do is invert the boolean value > below and that requires a little more gymnastic. And I don't think it > matches what one would say in a conversation because why would you mention > the case where nothing happens at all? > > -- > Loïc Hoguin > https://ninenines.eu> > _______________________________________________ > erlang-questions mailing list > [hidden email] > http://erlang.org/mailman/listinfo/erlang-questions_______________________________________________ erlang-questions mailing list [hidden email] http://erlang.org/mailman/listinfo/erlang-questions
 In reply to this post by Loïc Hoguin-3 I am with Loïc, I'd be tripped— A flurry of thoughts · · · ` "When writing a case statement based on a boolean expression"` · As we're only working with a boolean(), why use the case at all?    That may be where the confusion is coming form.    The big thing happening here is the true or false, I believe using variables makes that clearer.      foo(Status, Thingy, Assignments)        ->                      TF = maps:is_key(Thingy, Assignments),                         if            TF =:= false -> {Status, Assignments}                                                    ; TF =:= true  ->          Assignment  = fomulate_assignment(Thingy),                                  NewAssignments = maps:put(Thingy, Assignment, Assignments),                       {assigned, NewAssignments}                       end. · I tend to put the shorter clause one near the top(see above), so the reader can get take a breath quicker. · I am have no problem, mentally, saying "otherwise" when I see a  "; true ->" because of the way Erlang treats 'if' expressions. So it can come second just as easily. · The other day I read that the brain can handle complex data types way better than it candle handle complex logic... I guess anything to does not add to the confusion, not unlike the 'not', isn't that terrible. ;) · What Dave Thomas said at last year's conference may apply here:         Programming is Nested Composable Transformation         Rules should be:            1. Work out what should be true ->                                2. Make it true  ( establishing initial conditions )             3. Keep it true   ( during transformations )                    Also, mentioned,                · Ask yourself, how does the language encourage you to think about things?                · If you make it easier to think about things in terms of reducers,                  the quality of programming will increase. Cheers, Rob Carbone scriptculture.com On 2/9/18 4:40 AM, Loïc Hoguin wrote: On 02/09/2018 10:31 AM, [hidden email] wrote: [...] foo(Status, Thingy, Assignments) ->      case not maps:is_key(Thingy, Assignment) of          true ->              Assignment = fomulate_assignment(Thingy),              NewAssignments = maps:put(Thingy, Assignment, Assignments),              {assigned, NewAssignments};          false ->              {Status, Assignments}      end. [...] This isn't a big deal either way of course (I find them both equally readable), but I am curious if anyone has a strong opinion on the issue and why. Which would you prefer to encounter when reading a project to understand how it works on github? Oh boy. I would definitely get tripped by this. Or at the very least have some eyebrow action. I have no problem with it in something like C because there's usually no 'else' clause in these cases and it's therefore very easy to read the intent. But in Erlang's case what you effectively do is invert the boolean value below and that requires a little more gymnastic. And I don't think it matches what one would say in a conversation because why would you mention the case where nothing happens at all? _______________________________________________ erlang-questions mailing list [hidden email] http://erlang.org/mailman/listinfo/erlang-questions