How to code these conditional statements in more elegant & scalable manner

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












7















In my software, I need to decide the version of a feature based on 2 parameters. Eg.



Render version 1 -> if (param1 && param2) == true;
Render version 2 -> if (!param1 && !param2) == true;
Render version 3 -> if only param1 == true;
Render version 4 -> if only param2 == true;


So, to meet this requirement, I wrote a code which looks like this -



if(param1 && param2) //both are true 
version = 1;

else if(!param1 && !param2) //both are false
version = 2;

else if(!param2) //Means param1 is true
version = 3;

else //Means param2 is true
version = 4;



There are definitely multiple ways to code this but I finalised this approach after trying out different approaches because this is the most readable code I could come up with.

But this piece of code is definitely not scalable because -



  1. Let say tomorrow we want to introduce new param called param3. Then
    the no. of checks will increase because of multiple possible
    combinations.

  2. For this software, I am pretty much sure that we
    will have to accommodate new parameters in future.

Can there be any scalable & readable way to code these requirements?










share|improve this question
























  • Are yo usure that the if/else if cascade is correct ? Because if some test returns true, the next won't be evaluated at all.

    – Yves Daoust
    Feb 16 at 16:11











  • @YvesDaoust Seems correct, doesn't it? I think it is desired that only one if body is visited

    – Lino
    Feb 16 at 16:18











  • @Lino: mutual exclusiveness of the expressions must be guaranteed then.

    – Yves Daoust
    Feb 16 at 16:22











  • What is the expected result with param3? Can you describe the pattern change generally as we add params?

    – גלעד ברקן
    Feb 16 at 16:28











  • Do you plan to increase versions as well?

    – Nitin
    Feb 16 at 19:53















7















In my software, I need to decide the version of a feature based on 2 parameters. Eg.



Render version 1 -> if (param1 && param2) == true;
Render version 2 -> if (!param1 && !param2) == true;
Render version 3 -> if only param1 == true;
Render version 4 -> if only param2 == true;


So, to meet this requirement, I wrote a code which looks like this -



if(param1 && param2) //both are true 
version = 1;

else if(!param1 && !param2) //both are false
version = 2;

else if(!param2) //Means param1 is true
version = 3;

else //Means param2 is true
version = 4;



There are definitely multiple ways to code this but I finalised this approach after trying out different approaches because this is the most readable code I could come up with.

But this piece of code is definitely not scalable because -



  1. Let say tomorrow we want to introduce new param called param3. Then
    the no. of checks will increase because of multiple possible
    combinations.

  2. For this software, I am pretty much sure that we
    will have to accommodate new parameters in future.

Can there be any scalable & readable way to code these requirements?










share|improve this question
























  • Are yo usure that the if/else if cascade is correct ? Because if some test returns true, the next won't be evaluated at all.

    – Yves Daoust
    Feb 16 at 16:11











  • @YvesDaoust Seems correct, doesn't it? I think it is desired that only one if body is visited

    – Lino
    Feb 16 at 16:18











  • @Lino: mutual exclusiveness of the expressions must be guaranteed then.

    – Yves Daoust
    Feb 16 at 16:22











  • What is the expected result with param3? Can you describe the pattern change generally as we add params?

    – גלעד ברקן
    Feb 16 at 16:28











  • Do you plan to increase versions as well?

    – Nitin
    Feb 16 at 19:53













7












7








7


2






In my software, I need to decide the version of a feature based on 2 parameters. Eg.



Render version 1 -> if (param1 && param2) == true;
Render version 2 -> if (!param1 && !param2) == true;
Render version 3 -> if only param1 == true;
Render version 4 -> if only param2 == true;


So, to meet this requirement, I wrote a code which looks like this -



if(param1 && param2) //both are true 
version = 1;

else if(!param1 && !param2) //both are false
version = 2;

else if(!param2) //Means param1 is true
version = 3;

else //Means param2 is true
version = 4;



There are definitely multiple ways to code this but I finalised this approach after trying out different approaches because this is the most readable code I could come up with.

But this piece of code is definitely not scalable because -



  1. Let say tomorrow we want to introduce new param called param3. Then
    the no. of checks will increase because of multiple possible
    combinations.

  2. For this software, I am pretty much sure that we
    will have to accommodate new parameters in future.

Can there be any scalable & readable way to code these requirements?










share|improve this question
















In my software, I need to decide the version of a feature based on 2 parameters. Eg.



Render version 1 -> if (param1 && param2) == true;
Render version 2 -> if (!param1 && !param2) == true;
Render version 3 -> if only param1 == true;
Render version 4 -> if only param2 == true;


So, to meet this requirement, I wrote a code which looks like this -



if(param1 && param2) //both are true 
version = 1;

else if(!param1 && !param2) //both are false
version = 2;

else if(!param2) //Means param1 is true
version = 3;

else //Means param2 is true
version = 4;



There are definitely multiple ways to code this but I finalised this approach after trying out different approaches because this is the most readable code I could come up with.

But this piece of code is definitely not scalable because -



  1. Let say tomorrow we want to introduce new param called param3. Then
    the no. of checks will increase because of multiple possible
    combinations.

  2. For this software, I am pretty much sure that we
    will have to accommodate new parameters in future.

Can there be any scalable & readable way to code these requirements?







java algorithm if-statement






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 16 at 20:16









Alexis Wilke

10.1k34180




10.1k34180










asked Feb 16 at 13:08









Ryan GustoRyan Gusto

593




593












  • Are yo usure that the if/else if cascade is correct ? Because if some test returns true, the next won't be evaluated at all.

    – Yves Daoust
    Feb 16 at 16:11











  • @YvesDaoust Seems correct, doesn't it? I think it is desired that only one if body is visited

    – Lino
    Feb 16 at 16:18











  • @Lino: mutual exclusiveness of the expressions must be guaranteed then.

    – Yves Daoust
    Feb 16 at 16:22











  • What is the expected result with param3? Can you describe the pattern change generally as we add params?

    – גלעד ברקן
    Feb 16 at 16:28











  • Do you plan to increase versions as well?

    – Nitin
    Feb 16 at 19:53

















  • Are yo usure that the if/else if cascade is correct ? Because if some test returns true, the next won't be evaluated at all.

    – Yves Daoust
    Feb 16 at 16:11











  • @YvesDaoust Seems correct, doesn't it? I think it is desired that only one if body is visited

    – Lino
    Feb 16 at 16:18











  • @Lino: mutual exclusiveness of the expressions must be guaranteed then.

    – Yves Daoust
    Feb 16 at 16:22











  • What is the expected result with param3? Can you describe the pattern change generally as we add params?

    – גלעד ברקן
    Feb 16 at 16:28











  • Do you plan to increase versions as well?

    – Nitin
    Feb 16 at 19:53
















Are yo usure that the if/else if cascade is correct ? Because if some test returns true, the next won't be evaluated at all.

– Yves Daoust
Feb 16 at 16:11





Are yo usure that the if/else if cascade is correct ? Because if some test returns true, the next won't be evaluated at all.

– Yves Daoust
Feb 16 at 16:11













@YvesDaoust Seems correct, doesn't it? I think it is desired that only one if body is visited

– Lino
Feb 16 at 16:18





@YvesDaoust Seems correct, doesn't it? I think it is desired that only one if body is visited

– Lino
Feb 16 at 16:18













@Lino: mutual exclusiveness of the expressions must be guaranteed then.

– Yves Daoust
Feb 16 at 16:22





@Lino: mutual exclusiveness of the expressions must be guaranteed then.

– Yves Daoust
Feb 16 at 16:22













What is the expected result with param3? Can you describe the pattern change generally as we add params?

– גלעד ברקן
Feb 16 at 16:28





What is the expected result with param3? Can you describe the pattern change generally as we add params?

– גלעד ברקן
Feb 16 at 16:28













Do you plan to increase versions as well?

– Nitin
Feb 16 at 19:53





Do you plan to increase versions as well?

– Nitin
Feb 16 at 19:53












5 Answers
5






active

oldest

votes


















5














EDIT:
For a scalable solution define the versions for each parameter combination through a Map:



Map<List<Boolean>, Integer> paramsToVersion = Map.of(
List.of(true, true), 1,
List.of(false, false), 2,
List.of(true, false), 3,
List.of(false, true), 4);


Now finding the right version is a simple map lookup:



 version = paramsToVersion.get(List.of(param1, param2));


The way I initialized the map works since Java 9. In older Java versions it’s a little more wordy, but probably still worth doing. Even in Java 9 you need to use Map.ofEntries if you have 4 or more parameters (for 16 combinations), which is a little more wordy too.



Original answer:
My taste would be for nested if/else statements and only testing each parameter once:



 if (param1) 
if (param2)
version = 1;
else
version = 3;

else
if (param2)
version = 4;
else
version = 2;




But it scales poorly to many parameters.






share|improve this answer

























  • I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

    – Yves Daoust
    Feb 16 at 16:36












  • @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

    – Ole V.V.
    Feb 16 at 16:41






  • 1





    This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

    – Yves Daoust
    Feb 16 at 16:43












  • @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

    – Ryan Gusto
    Feb 17 at 2:34


















5














If you have to enumerate all the possible combinations of Booleans, it's often simplest to convert them into a number:



// param1: F T F T
// param2; F F T T
static final int VERSIONS = new int2, 3, 4, 1;

...
version = VERSIONS[(param1 ? 1:0) + (param2 ? 2:0)];





share|improve this answer

























  • @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

    – Ralf Kleberhoff
    Feb 16 at 14:12






  • 7





    This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

    – Federico Peralta Schaffner
    Feb 16 at 16:32











  • @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

    – Matt Timmermans
    Feb 16 at 17:56











  • I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

    – Filip Milovanović
    Feb 16 at 18:29











  • I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

    – גלעד ברקן
    Feb 17 at 12:02


















4














I doubt that there is a way that would be more compact, readable and scalable at the same time.



You express the conditions as minimized expressions, which are compact and may have meaning (in particular, the irrelevant variables don't clutter them). But there is no systematism that you could exploit.



A quite systematic alternative could be truth tables, i.e. the explicit expansion of all combinations and the associated truth value (or version number), which can be very efficient in terms of running-time. But these have a size exponential in the number of variables and are not especially readable.



I am afraid there is no free lunch. Your current solution is excellent.




If you are after efficiency (i.e. avoiding the need to evaluate all expressions sequentially), then you can think of the truth table approach, but in the following way:



  • declare an array of version numbers, with 2^n entries;


  • use the code just like you wrote to initialize all table entries; to achieve that, enumerate all integers in [0, 2^n) and use their binary representation;


  • now for a query, form an integer index from the n input booleans and lookup the array.


Using the answer by Olevv, the table would be [2, 4, 3, 1]. A lookup would be like (false, true) => T[01b] = 4.



What matters is that the original set of expressions is still there in the code, for human reading. You can use it in an initialization function that will fill the array at run-time, and you can also use it to hard-code the table (and leave the code in comments; even better, leave the code that generates the hard-coded table).






share|improve this answer
































    4














    Your combinations of parameters is nothing more than a binary number (like 01100) where the 0 indicates a false and the 1 a true.



    So your version can be easily calculated by using all the combinations of ones and zeroes. Possible combinations with 2 input parameters are:




    1. 11 -> both are true


    2. 10 -> first is true, second is false


    3. 01 -> first is false, second is true


    4. 00 -> both are false

    So with this knowledge I've come up with a quite scalable solution using a "bit mask" (nothing more than a number) and "bit operations":



    public static int getVersion(boolean... params) 
    int length = params.length;
    int mask = (1 << length) - 1;
    for(int i = 0; i < length; i++)
    if(!params[i])
    mask &= ~(1 << length - i - 1);


    return mask + 1;



    The most interesting line is probably this:



    mask &= ~(1 << length - i - 1);


    It does many things at once, I split it up. The part length - i - 1 calculates the position of the "bit" inside the bit mask from the right (0 based, like in arrays).



    The next part: 1 << (length - i - 1) shifts the number 1 the amount of positions to the left. So lets say we have a position of 3, then the result of the operation 1 << 2 (2 is the third position) would be a binary number of the value 100.



    The ~ sign is a binary inverse, so all the bits are inverted, all 0 are turned to 1 and all 1 are turned to 0. With the previous example the inverse of 100 would be 011.



    The last part: mask &= n is the same as mask = mask & n where n is the previously computed value 011. This is nothing more than a binary AND, so all the same bits which are in mask and in n are kept, where as all others are discarded.



    All in all, does this single line nothing more than remove the "bit" at a given position of the mask if the input parameter is false.




    If the version numbers are not sequential from 1 to 4 then a version lookup table, like this one may help you.



    The whole code would need just a single adjustment in the last line:



    return VERSIONS[mask];


    Where your VERSIONS array consists of all the versions in order, but reversed. (index 0 of VERSIONS is where both parameters are false)






    share|improve this answer




















    • 2





      I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

      – Lino
      Feb 16 at 17:27






    • 2





      Very solid approach.

      – user58697
      Feb 16 at 17:46











    • I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

      – ilkkachu
      Feb 16 at 22:52











    • Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

      – ilkkachu
      Feb 16 at 22:54











    • How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

      – גלעד ברקן
      Feb 17 at 15:23



















    2














    I would have just gone with:



    if (param1) 
    if (param2)
    else

    else
    if (param2)
    else




    Kind of repetitive, but each condition is evaluated only once, and you can easily find the code that executes for any particular combination. Adding a 3rd parameter will, of course, double the code. But if there are any invalid combinations, you can leave those out which shortens the code. Or, if you want to throw an exception for them, it becomes fairly easy to see which combination you have missed. When the IF's become too long, you can bring the actual code out in methods:



    if (param1) 
    if (param2)
    method_12();
    else
    method_1();

    else
    if (param2)
    method_2();
    else
    method_none();




    Thus your whole switching logic takes up a function of itself and the actual code for any combination is in another method. When you need to work with the code for a particular combination, you just look up the appropriate method. The big IF maze is then rarely looked at, and when it is, it contains only the IFs themselves and nothing else potentially distracting.






    share|improve this answer






















      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54723382%2fhow-to-code-these-conditional-statements-in-more-elegant-scalable-manner%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      5














      EDIT:
      For a scalable solution define the versions for each parameter combination through a Map:



      Map<List<Boolean>, Integer> paramsToVersion = Map.of(
      List.of(true, true), 1,
      List.of(false, false), 2,
      List.of(true, false), 3,
      List.of(false, true), 4);


      Now finding the right version is a simple map lookup:



       version = paramsToVersion.get(List.of(param1, param2));


      The way I initialized the map works since Java 9. In older Java versions it’s a little more wordy, but probably still worth doing. Even in Java 9 you need to use Map.ofEntries if you have 4 or more parameters (for 16 combinations), which is a little more wordy too.



      Original answer:
      My taste would be for nested if/else statements and only testing each parameter once:



       if (param1) 
      if (param2)
      version = 1;
      else
      version = 3;

      else
      if (param2)
      version = 4;
      else
      version = 2;




      But it scales poorly to many parameters.






      share|improve this answer

























      • I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

        – Yves Daoust
        Feb 16 at 16:36












      • @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

        – Ole V.V.
        Feb 16 at 16:41






      • 1





        This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

        – Yves Daoust
        Feb 16 at 16:43












      • @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

        – Ryan Gusto
        Feb 17 at 2:34















      5














      EDIT:
      For a scalable solution define the versions for each parameter combination through a Map:



      Map<List<Boolean>, Integer> paramsToVersion = Map.of(
      List.of(true, true), 1,
      List.of(false, false), 2,
      List.of(true, false), 3,
      List.of(false, true), 4);


      Now finding the right version is a simple map lookup:



       version = paramsToVersion.get(List.of(param1, param2));


      The way I initialized the map works since Java 9. In older Java versions it’s a little more wordy, but probably still worth doing. Even in Java 9 you need to use Map.ofEntries if you have 4 or more parameters (for 16 combinations), which is a little more wordy too.



      Original answer:
      My taste would be for nested if/else statements and only testing each parameter once:



       if (param1) 
      if (param2)
      version = 1;
      else
      version = 3;

      else
      if (param2)
      version = 4;
      else
      version = 2;




      But it scales poorly to many parameters.






      share|improve this answer

























      • I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

        – Yves Daoust
        Feb 16 at 16:36












      • @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

        – Ole V.V.
        Feb 16 at 16:41






      • 1





        This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

        – Yves Daoust
        Feb 16 at 16:43












      • @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

        – Ryan Gusto
        Feb 17 at 2:34













      5












      5








      5







      EDIT:
      For a scalable solution define the versions for each parameter combination through a Map:



      Map<List<Boolean>, Integer> paramsToVersion = Map.of(
      List.of(true, true), 1,
      List.of(false, false), 2,
      List.of(true, false), 3,
      List.of(false, true), 4);


      Now finding the right version is a simple map lookup:



       version = paramsToVersion.get(List.of(param1, param2));


      The way I initialized the map works since Java 9. In older Java versions it’s a little more wordy, but probably still worth doing. Even in Java 9 you need to use Map.ofEntries if you have 4 or more parameters (for 16 combinations), which is a little more wordy too.



      Original answer:
      My taste would be for nested if/else statements and only testing each parameter once:



       if (param1) 
      if (param2)
      version = 1;
      else
      version = 3;

      else
      if (param2)
      version = 4;
      else
      version = 2;




      But it scales poorly to many parameters.






      share|improve this answer















      EDIT:
      For a scalable solution define the versions for each parameter combination through a Map:



      Map<List<Boolean>, Integer> paramsToVersion = Map.of(
      List.of(true, true), 1,
      List.of(false, false), 2,
      List.of(true, false), 3,
      List.of(false, true), 4);


      Now finding the right version is a simple map lookup:



       version = paramsToVersion.get(List.of(param1, param2));


      The way I initialized the map works since Java 9. In older Java versions it’s a little more wordy, but probably still worth doing. Even in Java 9 you need to use Map.ofEntries if you have 4 or more parameters (for 16 combinations), which is a little more wordy too.



      Original answer:
      My taste would be for nested if/else statements and only testing each parameter once:



       if (param1) 
      if (param2)
      version = 1;
      else
      version = 3;

      else
      if (param2)
      version = 4;
      else
      version = 2;




      But it scales poorly to many parameters.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Feb 16 at 14:23

























      answered Feb 16 at 14:15









      Ole V.V.Ole V.V.

      30.5k63856




      30.5k63856












      • I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

        – Yves Daoust
        Feb 16 at 16:36












      • @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

        – Ole V.V.
        Feb 16 at 16:41






      • 1





        This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

        – Yves Daoust
        Feb 16 at 16:43












      • @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

        – Ryan Gusto
        Feb 17 at 2:34

















      • I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

        – Yves Daoust
        Feb 16 at 16:36












      • @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

        – Ole V.V.
        Feb 16 at 16:41






      • 1





        This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

        – Yves Daoust
        Feb 16 at 16:43












      • @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

        – Ryan Gusto
        Feb 17 at 2:34
















      I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

      – Yves Daoust
      Feb 16 at 16:36






      I don't like the new solution because you will have to generate up to 2^k lists for k parameters. This is unreadable, and the expansion of the lists is error prone.

      – Yves Daoust
      Feb 16 at 16:36














      @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

      – Ole V.V.
      Feb 16 at 16:41





      @YvesDaoust Then I’m glad that I let my old solution stand here too. I suppose each has its place depending on requirements and circumstances. At least if you add 2^k lists and get a param value wrong, in Java 9 Map.of or Map.ofEntries will complain about the resulting duplicate kay so you know there’s an error and you need to fix it.

      – Ole V.V.
      Feb 16 at 16:41




      1




      1





      This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

      – Yves Daoust
      Feb 16 at 16:43






      This kind of error can be spotted at a glance as the values appear explicitly. What I am referring to is how you expand "(tall and not fat) or old and green" without a mistake, and how you can read that back from the truth table.

      – Yves Daoust
      Feb 16 at 16:43














      @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

      – Ryan Gusto
      Feb 17 at 2:34





      @Ole V.V. Yes these are better solutions than mine but scalability concern is still there.

      – Ryan Gusto
      Feb 17 at 2:34













      5














      If you have to enumerate all the possible combinations of Booleans, it's often simplest to convert them into a number:



      // param1: F T F T
      // param2; F F T T
      static final int VERSIONS = new int2, 3, 4, 1;

      ...
      version = VERSIONS[(param1 ? 1:0) + (param2 ? 2:0)];





      share|improve this answer

























      • @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

        – Ralf Kleberhoff
        Feb 16 at 14:12






      • 7





        This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

        – Federico Peralta Schaffner
        Feb 16 at 16:32











      • @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

        – Matt Timmermans
        Feb 16 at 17:56











      • I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

        – Filip Milovanović
        Feb 16 at 18:29











      • I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

        – גלעד ברקן
        Feb 17 at 12:02















      5














      If you have to enumerate all the possible combinations of Booleans, it's often simplest to convert them into a number:



      // param1: F T F T
      // param2; F F T T
      static final int VERSIONS = new int2, 3, 4, 1;

      ...
      version = VERSIONS[(param1 ? 1:0) + (param2 ? 2:0)];





      share|improve this answer

























      • @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

        – Ralf Kleberhoff
        Feb 16 at 14:12






      • 7





        This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

        – Federico Peralta Schaffner
        Feb 16 at 16:32











      • @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

        – Matt Timmermans
        Feb 16 at 17:56











      • I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

        – Filip Milovanović
        Feb 16 at 18:29











      • I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

        – גלעד ברקן
        Feb 17 at 12:02













      5












      5








      5







      If you have to enumerate all the possible combinations of Booleans, it's often simplest to convert them into a number:



      // param1: F T F T
      // param2; F F T T
      static final int VERSIONS = new int2, 3, 4, 1;

      ...
      version = VERSIONS[(param1 ? 1:0) + (param2 ? 2:0)];





      share|improve this answer















      If you have to enumerate all the possible combinations of Booleans, it's often simplest to convert them into a number:



      // param1: F T F T
      // param2; F F T T
      static final int VERSIONS = new int2, 3, 4, 1;

      ...
      version = VERSIONS[(param1 ? 1:0) + (param2 ? 2:0)];






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Feb 17 at 4:22

























      answered Feb 16 at 13:29









      Matt TimmermansMatt Timmermans

      20.6k11733




      20.6k11733












      • @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

        – Ralf Kleberhoff
        Feb 16 at 14:12






      • 7





        This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

        – Federico Peralta Schaffner
        Feb 16 at 16:32











      • @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

        – Matt Timmermans
        Feb 16 at 17:56











      • I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

        – Filip Milovanović
        Feb 16 at 18:29











      • I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

        – גלעד ברקן
        Feb 17 at 12:02

















      • @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

        – Ralf Kleberhoff
        Feb 16 at 14:12






      • 7





        This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

        – Federico Peralta Schaffner
        Feb 16 at 16:32











      • @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

        – Matt Timmermans
        Feb 16 at 17:56











      • I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

        – Filip Milovanović
        Feb 16 at 18:29











      • I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

        – גלעד ברקן
        Feb 17 at 12:02
















      @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

      – Ralf Kleberhoff
      Feb 16 at 14:12





      @Lino: that won't work, i will always stay 0, no matter how often you shift it left.

      – Ralf Kleberhoff
      Feb 16 at 14:12




      7




      7





      This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

      – Federico Peralta Schaffner
      Feb 16 at 16:32





      This is really clever, but far from being readable and expressive. For a developer that is new to this code, it might even result cryptic.

      – Federico Peralta Schaffner
      Feb 16 at 16:32













      @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

      – Matt Timmermans
      Feb 16 at 17:56





      @FedericoPeraltaSchaffner agreed, but there are readable variants and/or ways to comment it. I'm just leaving that to the OP, since I would like a more concrete example before suggesting a best way.

      – Matt Timmermans
      Feb 16 at 17:56













      I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

      – Filip Milovanović
      Feb 16 at 18:29





      I think the answer would benefit from including a comment or an example showing how to extend this beyond two parameters; e.g. (param3 ? 4:0) + (param4 ? 8:0) + ..., as it may not be clear to some that you are treating the bool sequence as a bit string.

      – Filip Milovanović
      Feb 16 at 18:29













      I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

      – גלעד ברקן
      Feb 17 at 12:02





      I'm not sure this passes either the scalable or readable stated requirements. Ok, it might be technically scalable but as we'd add to the list of ternary ifs, the expression evaluating the index will very quickly get unreadable (to me it already is, which doesn't say much about me I guess :)

      – גלעד ברקן
      Feb 17 at 12:02











      4














      I doubt that there is a way that would be more compact, readable and scalable at the same time.



      You express the conditions as minimized expressions, which are compact and may have meaning (in particular, the irrelevant variables don't clutter them). But there is no systematism that you could exploit.



      A quite systematic alternative could be truth tables, i.e. the explicit expansion of all combinations and the associated truth value (or version number), which can be very efficient in terms of running-time. But these have a size exponential in the number of variables and are not especially readable.



      I am afraid there is no free lunch. Your current solution is excellent.




      If you are after efficiency (i.e. avoiding the need to evaluate all expressions sequentially), then you can think of the truth table approach, but in the following way:



      • declare an array of version numbers, with 2^n entries;


      • use the code just like you wrote to initialize all table entries; to achieve that, enumerate all integers in [0, 2^n) and use their binary representation;


      • now for a query, form an integer index from the n input booleans and lookup the array.


      Using the answer by Olevv, the table would be [2, 4, 3, 1]. A lookup would be like (false, true) => T[01b] = 4.



      What matters is that the original set of expressions is still there in the code, for human reading. You can use it in an initialization function that will fill the array at run-time, and you can also use it to hard-code the table (and leave the code in comments; even better, leave the code that generates the hard-coded table).






      share|improve this answer





























        4














        I doubt that there is a way that would be more compact, readable and scalable at the same time.



        You express the conditions as minimized expressions, which are compact and may have meaning (in particular, the irrelevant variables don't clutter them). But there is no systematism that you could exploit.



        A quite systematic alternative could be truth tables, i.e. the explicit expansion of all combinations and the associated truth value (or version number), which can be very efficient in terms of running-time. But these have a size exponential in the number of variables and are not especially readable.



        I am afraid there is no free lunch. Your current solution is excellent.




        If you are after efficiency (i.e. avoiding the need to evaluate all expressions sequentially), then you can think of the truth table approach, but in the following way:



        • declare an array of version numbers, with 2^n entries;


        • use the code just like you wrote to initialize all table entries; to achieve that, enumerate all integers in [0, 2^n) and use their binary representation;


        • now for a query, form an integer index from the n input booleans and lookup the array.


        Using the answer by Olevv, the table would be [2, 4, 3, 1]. A lookup would be like (false, true) => T[01b] = 4.



        What matters is that the original set of expressions is still there in the code, for human reading. You can use it in an initialization function that will fill the array at run-time, and you can also use it to hard-code the table (and leave the code in comments; even better, leave the code that generates the hard-coded table).






        share|improve this answer



























          4












          4








          4







          I doubt that there is a way that would be more compact, readable and scalable at the same time.



          You express the conditions as minimized expressions, which are compact and may have meaning (in particular, the irrelevant variables don't clutter them). But there is no systematism that you could exploit.



          A quite systematic alternative could be truth tables, i.e. the explicit expansion of all combinations and the associated truth value (or version number), which can be very efficient in terms of running-time. But these have a size exponential in the number of variables and are not especially readable.



          I am afraid there is no free lunch. Your current solution is excellent.




          If you are after efficiency (i.e. avoiding the need to evaluate all expressions sequentially), then you can think of the truth table approach, but in the following way:



          • declare an array of version numbers, with 2^n entries;


          • use the code just like you wrote to initialize all table entries; to achieve that, enumerate all integers in [0, 2^n) and use their binary representation;


          • now for a query, form an integer index from the n input booleans and lookup the array.


          Using the answer by Olevv, the table would be [2, 4, 3, 1]. A lookup would be like (false, true) => T[01b] = 4.



          What matters is that the original set of expressions is still there in the code, for human reading. You can use it in an initialization function that will fill the array at run-time, and you can also use it to hard-code the table (and leave the code in comments; even better, leave the code that generates the hard-coded table).






          share|improve this answer















          I doubt that there is a way that would be more compact, readable and scalable at the same time.



          You express the conditions as minimized expressions, which are compact and may have meaning (in particular, the irrelevant variables don't clutter them). But there is no systematism that you could exploit.



          A quite systematic alternative could be truth tables, i.e. the explicit expansion of all combinations and the associated truth value (or version number), which can be very efficient in terms of running-time. But these have a size exponential in the number of variables and are not especially readable.



          I am afraid there is no free lunch. Your current solution is excellent.




          If you are after efficiency (i.e. avoiding the need to evaluate all expressions sequentially), then you can think of the truth table approach, but in the following way:



          • declare an array of version numbers, with 2^n entries;


          • use the code just like you wrote to initialize all table entries; to achieve that, enumerate all integers in [0, 2^n) and use their binary representation;


          • now for a query, form an integer index from the n input booleans and lookup the array.


          Using the answer by Olevv, the table would be [2, 4, 3, 1]. A lookup would be like (false, true) => T[01b] = 4.



          What matters is that the original set of expressions is still there in the code, for human reading. You can use it in an initialization function that will fill the array at run-time, and you can also use it to hard-code the table (and leave the code in comments; even better, leave the code that generates the hard-coded table).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 16 at 16:55

























          answered Feb 16 at 16:18









          Yves DaoustYves Daoust

          38.1k72759




          38.1k72759





















              4














              Your combinations of parameters is nothing more than a binary number (like 01100) where the 0 indicates a false and the 1 a true.



              So your version can be easily calculated by using all the combinations of ones and zeroes. Possible combinations with 2 input parameters are:




              1. 11 -> both are true


              2. 10 -> first is true, second is false


              3. 01 -> first is false, second is true


              4. 00 -> both are false

              So with this knowledge I've come up with a quite scalable solution using a "bit mask" (nothing more than a number) and "bit operations":



              public static int getVersion(boolean... params) 
              int length = params.length;
              int mask = (1 << length) - 1;
              for(int i = 0; i < length; i++)
              if(!params[i])
              mask &= ~(1 << length - i - 1);


              return mask + 1;



              The most interesting line is probably this:



              mask &= ~(1 << length - i - 1);


              It does many things at once, I split it up. The part length - i - 1 calculates the position of the "bit" inside the bit mask from the right (0 based, like in arrays).



              The next part: 1 << (length - i - 1) shifts the number 1 the amount of positions to the left. So lets say we have a position of 3, then the result of the operation 1 << 2 (2 is the third position) would be a binary number of the value 100.



              The ~ sign is a binary inverse, so all the bits are inverted, all 0 are turned to 1 and all 1 are turned to 0. With the previous example the inverse of 100 would be 011.



              The last part: mask &= n is the same as mask = mask & n where n is the previously computed value 011. This is nothing more than a binary AND, so all the same bits which are in mask and in n are kept, where as all others are discarded.



              All in all, does this single line nothing more than remove the "bit" at a given position of the mask if the input parameter is false.




              If the version numbers are not sequential from 1 to 4 then a version lookup table, like this one may help you.



              The whole code would need just a single adjustment in the last line:



              return VERSIONS[mask];


              Where your VERSIONS array consists of all the versions in order, but reversed. (index 0 of VERSIONS is where both parameters are false)






              share|improve this answer




















              • 2





                I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

                – Lino
                Feb 16 at 17:27






              • 2





                Very solid approach.

                – user58697
                Feb 16 at 17:46











              • I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

                – ilkkachu
                Feb 16 at 22:52











              • Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

                – ilkkachu
                Feb 16 at 22:54











              • How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

                – גלעד ברקן
                Feb 17 at 15:23
















              4














              Your combinations of parameters is nothing more than a binary number (like 01100) where the 0 indicates a false and the 1 a true.



              So your version can be easily calculated by using all the combinations of ones and zeroes. Possible combinations with 2 input parameters are:




              1. 11 -> both are true


              2. 10 -> first is true, second is false


              3. 01 -> first is false, second is true


              4. 00 -> both are false

              So with this knowledge I've come up with a quite scalable solution using a "bit mask" (nothing more than a number) and "bit operations":



              public static int getVersion(boolean... params) 
              int length = params.length;
              int mask = (1 << length) - 1;
              for(int i = 0; i < length; i++)
              if(!params[i])
              mask &= ~(1 << length - i - 1);


              return mask + 1;



              The most interesting line is probably this:



              mask &= ~(1 << length - i - 1);


              It does many things at once, I split it up. The part length - i - 1 calculates the position of the "bit" inside the bit mask from the right (0 based, like in arrays).



              The next part: 1 << (length - i - 1) shifts the number 1 the amount of positions to the left. So lets say we have a position of 3, then the result of the operation 1 << 2 (2 is the third position) would be a binary number of the value 100.



              The ~ sign is a binary inverse, so all the bits are inverted, all 0 are turned to 1 and all 1 are turned to 0. With the previous example the inverse of 100 would be 011.



              The last part: mask &= n is the same as mask = mask & n where n is the previously computed value 011. This is nothing more than a binary AND, so all the same bits which are in mask and in n are kept, where as all others are discarded.



              All in all, does this single line nothing more than remove the "bit" at a given position of the mask if the input parameter is false.




              If the version numbers are not sequential from 1 to 4 then a version lookup table, like this one may help you.



              The whole code would need just a single adjustment in the last line:



              return VERSIONS[mask];


              Where your VERSIONS array consists of all the versions in order, but reversed. (index 0 of VERSIONS is where both parameters are false)






              share|improve this answer




















              • 2





                I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

                – Lino
                Feb 16 at 17:27






              • 2





                Very solid approach.

                – user58697
                Feb 16 at 17:46











              • I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

                – ilkkachu
                Feb 16 at 22:52











              • Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

                – ilkkachu
                Feb 16 at 22:54











              • How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

                – גלעד ברקן
                Feb 17 at 15:23














              4












              4








              4







              Your combinations of parameters is nothing more than a binary number (like 01100) where the 0 indicates a false and the 1 a true.



              So your version can be easily calculated by using all the combinations of ones and zeroes. Possible combinations with 2 input parameters are:




              1. 11 -> both are true


              2. 10 -> first is true, second is false


              3. 01 -> first is false, second is true


              4. 00 -> both are false

              So with this knowledge I've come up with a quite scalable solution using a "bit mask" (nothing more than a number) and "bit operations":



              public static int getVersion(boolean... params) 
              int length = params.length;
              int mask = (1 << length) - 1;
              for(int i = 0; i < length; i++)
              if(!params[i])
              mask &= ~(1 << length - i - 1);


              return mask + 1;



              The most interesting line is probably this:



              mask &= ~(1 << length - i - 1);


              It does many things at once, I split it up. The part length - i - 1 calculates the position of the "bit" inside the bit mask from the right (0 based, like in arrays).



              The next part: 1 << (length - i - 1) shifts the number 1 the amount of positions to the left. So lets say we have a position of 3, then the result of the operation 1 << 2 (2 is the third position) would be a binary number of the value 100.



              The ~ sign is a binary inverse, so all the bits are inverted, all 0 are turned to 1 and all 1 are turned to 0. With the previous example the inverse of 100 would be 011.



              The last part: mask &= n is the same as mask = mask & n where n is the previously computed value 011. This is nothing more than a binary AND, so all the same bits which are in mask and in n are kept, where as all others are discarded.



              All in all, does this single line nothing more than remove the "bit" at a given position of the mask if the input parameter is false.




              If the version numbers are not sequential from 1 to 4 then a version lookup table, like this one may help you.



              The whole code would need just a single adjustment in the last line:



              return VERSIONS[mask];


              Where your VERSIONS array consists of all the versions in order, but reversed. (index 0 of VERSIONS is where both parameters are false)






              share|improve this answer















              Your combinations of parameters is nothing more than a binary number (like 01100) where the 0 indicates a false and the 1 a true.



              So your version can be easily calculated by using all the combinations of ones and zeroes. Possible combinations with 2 input parameters are:




              1. 11 -> both are true


              2. 10 -> first is true, second is false


              3. 01 -> first is false, second is true


              4. 00 -> both are false

              So with this knowledge I've come up with a quite scalable solution using a "bit mask" (nothing more than a number) and "bit operations":



              public static int getVersion(boolean... params) 
              int length = params.length;
              int mask = (1 << length) - 1;
              for(int i = 0; i < length; i++)
              if(!params[i])
              mask &= ~(1 << length - i - 1);


              return mask + 1;



              The most interesting line is probably this:



              mask &= ~(1 << length - i - 1);


              It does many things at once, I split it up. The part length - i - 1 calculates the position of the "bit" inside the bit mask from the right (0 based, like in arrays).



              The next part: 1 << (length - i - 1) shifts the number 1 the amount of positions to the left. So lets say we have a position of 3, then the result of the operation 1 << 2 (2 is the third position) would be a binary number of the value 100.



              The ~ sign is a binary inverse, so all the bits are inverted, all 0 are turned to 1 and all 1 are turned to 0. With the previous example the inverse of 100 would be 011.



              The last part: mask &= n is the same as mask = mask & n where n is the previously computed value 011. This is nothing more than a binary AND, so all the same bits which are in mask and in n are kept, where as all others are discarded.



              All in all, does this single line nothing more than remove the "bit" at a given position of the mask if the input parameter is false.




              If the version numbers are not sequential from 1 to 4 then a version lookup table, like this one may help you.



              The whole code would need just a single adjustment in the last line:



              return VERSIONS[mask];


              Where your VERSIONS array consists of all the versions in order, but reversed. (index 0 of VERSIONS is where both parameters are false)







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Feb 17 at 13:21

























              answered Feb 16 at 16:53









              LinoLino

              9,92722043




              9,92722043







              • 2





                I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

                – Lino
                Feb 16 at 17:27






              • 2





                Very solid approach.

                – user58697
                Feb 16 at 17:46











              • I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

                – ilkkachu
                Feb 16 at 22:52











              • Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

                – ilkkachu
                Feb 16 at 22:54











              • How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

                – גלעד ברקן
                Feb 17 at 15:23













              • 2





                I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

                – Lino
                Feb 16 at 17:27






              • 2





                Very solid approach.

                – user58697
                Feb 16 at 17:46











              • I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

                – ilkkachu
                Feb 16 at 22:52











              • Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

                – ilkkachu
                Feb 16 at 22:54











              • How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

                – גלעד ברקן
                Feb 17 at 15:23








              2




              2





              I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

              – Lino
              Feb 16 at 17:27





              I don't really care about downvotes, but may the downvoter mention why? So I could improve the answer if needed

              – Lino
              Feb 16 at 17:27




              2




              2





              Very solid approach.

              – user58697
              Feb 16 at 17:46





              Very solid approach.

              – user58697
              Feb 16 at 17:46













              I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

              – ilkkachu
              Feb 16 at 22:52





              I didn't downvote this, but this does look a bit convoluted so I wouldn't be surprised that someone thought it downvote-worthy. Part of it might be the negative logic; it might feel more natural to just set the value to zero to start with, and then set the bits as necessary. Also, I think you could make the (1 << length - i - 1) clearer by running the loop downwards, not up and then just have (1 << i).

              – ilkkachu
              Feb 16 at 22:52













              Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

              – ilkkachu
              Feb 16 at 22:54





              Even more so, does int mask = length * 2 - 1; work? If there are three items in the list, this gives mask = 5, and 5 is 0101 and I'm not sure how that's useful?

              – ilkkachu
              Feb 16 at 22:54













              How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

              – גלעד ברקן
              Feb 17 at 15:23






              How is this readable (a stated requirement by the OP)? "Readable" to me would mean being able to easily follow how the set of params, and each individual one, contributes to the expression evaluating the version. I can't find a place like that in the code snippet. (I did not downvote.)

              – גלעד ברקן
              Feb 17 at 15:23












              2














              I would have just gone with:



              if (param1) 
              if (param2)
              else

              else
              if (param2)
              else




              Kind of repetitive, but each condition is evaluated only once, and you can easily find the code that executes for any particular combination. Adding a 3rd parameter will, of course, double the code. But if there are any invalid combinations, you can leave those out which shortens the code. Or, if you want to throw an exception for them, it becomes fairly easy to see which combination you have missed. When the IF's become too long, you can bring the actual code out in methods:



              if (param1) 
              if (param2)
              method_12();
              else
              method_1();

              else
              if (param2)
              method_2();
              else
              method_none();




              Thus your whole switching logic takes up a function of itself and the actual code for any combination is in another method. When you need to work with the code for a particular combination, you just look up the appropriate method. The big IF maze is then rarely looked at, and when it is, it contains only the IFs themselves and nothing else potentially distracting.






              share|improve this answer



























                2














                I would have just gone with:



                if (param1) 
                if (param2)
                else

                else
                if (param2)
                else




                Kind of repetitive, but each condition is evaluated only once, and you can easily find the code that executes for any particular combination. Adding a 3rd parameter will, of course, double the code. But if there are any invalid combinations, you can leave those out which shortens the code. Or, if you want to throw an exception for them, it becomes fairly easy to see which combination you have missed. When the IF's become too long, you can bring the actual code out in methods:



                if (param1) 
                if (param2)
                method_12();
                else
                method_1();

                else
                if (param2)
                method_2();
                else
                method_none();




                Thus your whole switching logic takes up a function of itself and the actual code for any combination is in another method. When you need to work with the code for a particular combination, you just look up the appropriate method. The big IF maze is then rarely looked at, and when it is, it contains only the IFs themselves and nothing else potentially distracting.






                share|improve this answer

























                  2












                  2








                  2







                  I would have just gone with:



                  if (param1) 
                  if (param2)
                  else

                  else
                  if (param2)
                  else




                  Kind of repetitive, but each condition is evaluated only once, and you can easily find the code that executes for any particular combination. Adding a 3rd parameter will, of course, double the code. But if there are any invalid combinations, you can leave those out which shortens the code. Or, if you want to throw an exception for them, it becomes fairly easy to see which combination you have missed. When the IF's become too long, you can bring the actual code out in methods:



                  if (param1) 
                  if (param2)
                  method_12();
                  else
                  method_1();

                  else
                  if (param2)
                  method_2();
                  else
                  method_none();




                  Thus your whole switching logic takes up a function of itself and the actual code for any combination is in another method. When you need to work with the code for a particular combination, you just look up the appropriate method. The big IF maze is then rarely looked at, and when it is, it contains only the IFs themselves and nothing else potentially distracting.






                  share|improve this answer













                  I would have just gone with:



                  if (param1) 
                  if (param2)
                  else

                  else
                  if (param2)
                  else




                  Kind of repetitive, but each condition is evaluated only once, and you can easily find the code that executes for any particular combination. Adding a 3rd parameter will, of course, double the code. But if there are any invalid combinations, you can leave those out which shortens the code. Or, if you want to throw an exception for them, it becomes fairly easy to see which combination you have missed. When the IF's become too long, you can bring the actual code out in methods:



                  if (param1) 
                  if (param2)
                  method_12();
                  else
                  method_1();

                  else
                  if (param2)
                  method_2();
                  else
                  method_none();




                  Thus your whole switching logic takes up a function of itself and the actual code for any combination is in another method. When you need to work with the code for a particular combination, you just look up the appropriate method. The big IF maze is then rarely looked at, and when it is, it contains only the IFs themselves and nothing else potentially distracting.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Feb 16 at 19:36









                  Vilx-Vilx-

                  61.5k71234377




                  61.5k71234377



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54723382%2fhow-to-code-these-conditional-statements-in-more-elegant-scalable-manner%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown






                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Bahrain

                      Postfix configuration issue with fips on centos 7; mailgun relay