Comparing 2 iOS and Android versions Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Comparing two bubble sort algorithmsPython script to create Android/iOS strings from a .csvOOP and non-OOP versions of layout and page animation codeParse 2D matrix, 2 versionsTwo versions of SudokuSmall camera app in react-native for AndroidCustom header with React-Navigation and React-Native-PaperMultiple stacks implemented via a linked lists on top of single fixed-size arrayTwo versions of PDF-SelectorThree versions of a counting-up timer in JavaScript

What is the meaning of the simile “quick as silk”?

What is the longest distance a player character can jump in one leap?

8 Prisoners wearing hats

Should I use a zero-interest credit card for a large one-time purchase?

Maximum summed powersets with non-adjacent items

Do I really need to have a message in a novel to appeal to readers?

Can anything be seen from the center of the Boötes void? How dark would it be?

Delete nth line from bottom

How to react to hostile behavior from a senior developer?

Is it ethical to give a final exam after the professor has quit before teaching the remaining chapters of the course?

Is safe to use va_start macro with this as parameter?

Does classifying an integer as a discrete log require it be part of a multiplicative group?

What are the out-of-universe reasons for the references to Toby Maguire-era Spider-Man in ITSV

First console to have temporary backward compatibility

What causes the direction of lightning flashes?

What is homebrew?

Dating a Former Employee

What do you call a floor made of glass so you can see through the floor?

Can a new player join a group only when a new campaign starts?

What does the "x" in "x86" represent?

What do you call the main part of a joke?

How could we fake a moon landing now?

Fantasy story; one type of magic grows in power with use, but the more powerful they are, they more they are drawn to travel to their source

How do I make this wiring inside cabinet safer? (Pic)



Comparing 2 iOS and Android versions



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Comparing two bubble sort algorithmsPython script to create Android/iOS strings from a .csvOOP and non-OOP versions of layout and page animation codeParse 2D matrix, 2 versionsTwo versions of SudokuSmall camera app in react-native for AndroidCustom header with React-Navigation and React-Native-PaperMultiple stacks implemented via a linked lists on top of single fixed-size arrayTwo versions of PDF-SelectorThree versions of a counting-up timer in JavaScript



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








4












$begingroup$


Please review and let me know which version is better. I'm just trying to find any caveats or better ways to accomplish the a version comparison independent from Android and iOS.



Formats accepted: '1.0.0' or '1' formats and an operator, e.g: compareVersion('1', '1.2.0', '>')



export function compareVersion(version1, version2, operator) 
const formattedV1 = version1.split(".");
const formattedV2 = version2.split(".");

let diff = 0;

if (formattedV1.length !== formattedV2.length)
const lengthDiff = formattedV1.length - formattedV2.length;
for (let index = 0; index < Math.abs(lengthDiff); index += 1)
if (lengthDiff > 0)
formattedV2.push("0");
else
formattedV1.push("0");




for (let index = 0; index < formattedV1.length; index += 1)
if (diff === 0)
const v1 = parseInt(formattedV1[index]);
const v2 = parseInt(formattedV2[index]);
if (isNaN(v1)


switch (operator)
case "=":
case "==":
return diff === 0;
case ">=":
return diff >= 0;
case "<=":
return diff <= 0;
case ">":
return diff > 0;
case "<":
return diff < 0;

default:
throw new Error("Problem comparing versions");




OR



export function compareVersions(a, b, operator) 
const aParts = a.split('.');
const bParts = b.split('.');

const pairs = [];

for (let index = 0; index < Math.max(aParts.length, bParts.length); index += 1)
pairs.push(
a: parseInt(aParts[index]),
b: parseInt(bParts[index]),
);


let diff = 0;

pairs.forEach((pair) =>
if (diff === 0)
if (pair.a > pair.b)
diff = 1;

if (pair.b > pair.a)
diff = -1;

if (!isNaN(pair.a) && isNaN(pair.b))
diff = 1;

if (isNaN(pair.a) && !isNaN(pair.b))
diff = -1;


);

switch (operator)
case '=':
case '==':
return diff === 0;
case '>=':
return diff >= 0;
case '<=':
return diff <= 0;
case '>':
return diff > 0;
case '<':
return diff < 0;

default:
throw new Error('Problem comparing versions');











share|improve this question









New contributor




Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$


















    4












    $begingroup$


    Please review and let me know which version is better. I'm just trying to find any caveats or better ways to accomplish the a version comparison independent from Android and iOS.



    Formats accepted: '1.0.0' or '1' formats and an operator, e.g: compareVersion('1', '1.2.0', '>')



    export function compareVersion(version1, version2, operator) 
    const formattedV1 = version1.split(".");
    const formattedV2 = version2.split(".");

    let diff = 0;

    if (formattedV1.length !== formattedV2.length)
    const lengthDiff = formattedV1.length - formattedV2.length;
    for (let index = 0; index < Math.abs(lengthDiff); index += 1)
    if (lengthDiff > 0)
    formattedV2.push("0");
    else
    formattedV1.push("0");




    for (let index = 0; index < formattedV1.length; index += 1)
    if (diff === 0)
    const v1 = parseInt(formattedV1[index]);
    const v2 = parseInt(formattedV2[index]);
    if (isNaN(v1)


    switch (operator)
    case "=":
    case "==":
    return diff === 0;
    case ">=":
    return diff >= 0;
    case "<=":
    return diff <= 0;
    case ">":
    return diff > 0;
    case "<":
    return diff < 0;

    default:
    throw new Error("Problem comparing versions");




    OR



    export function compareVersions(a, b, operator) 
    const aParts = a.split('.');
    const bParts = b.split('.');

    const pairs = [];

    for (let index = 0; index < Math.max(aParts.length, bParts.length); index += 1)
    pairs.push(
    a: parseInt(aParts[index]),
    b: parseInt(bParts[index]),
    );


    let diff = 0;

    pairs.forEach((pair) =>
    if (diff === 0)
    if (pair.a > pair.b)
    diff = 1;

    if (pair.b > pair.a)
    diff = -1;

    if (!isNaN(pair.a) && isNaN(pair.b))
    diff = 1;

    if (isNaN(pair.a) && !isNaN(pair.b))
    diff = -1;


    );

    switch (operator)
    case '=':
    case '==':
    return diff === 0;
    case '>=':
    return diff >= 0;
    case '<=':
    return diff <= 0;
    case '>':
    return diff > 0;
    case '<':
    return diff < 0;

    default:
    throw new Error('Problem comparing versions');











    share|improve this question









    New contributor




    Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$














      4












      4








      4





      $begingroup$


      Please review and let me know which version is better. I'm just trying to find any caveats or better ways to accomplish the a version comparison independent from Android and iOS.



      Formats accepted: '1.0.0' or '1' formats and an operator, e.g: compareVersion('1', '1.2.0', '>')



      export function compareVersion(version1, version2, operator) 
      const formattedV1 = version1.split(".");
      const formattedV2 = version2.split(".");

      let diff = 0;

      if (formattedV1.length !== formattedV2.length)
      const lengthDiff = formattedV1.length - formattedV2.length;
      for (let index = 0; index < Math.abs(lengthDiff); index += 1)
      if (lengthDiff > 0)
      formattedV2.push("0");
      else
      formattedV1.push("0");




      for (let index = 0; index < formattedV1.length; index += 1)
      if (diff === 0)
      const v1 = parseInt(formattedV1[index]);
      const v2 = parseInt(formattedV2[index]);
      if (isNaN(v1)


      switch (operator)
      case "=":
      case "==":
      return diff === 0;
      case ">=":
      return diff >= 0;
      case "<=":
      return diff <= 0;
      case ">":
      return diff > 0;
      case "<":
      return diff < 0;

      default:
      throw new Error("Problem comparing versions");




      OR



      export function compareVersions(a, b, operator) 
      const aParts = a.split('.');
      const bParts = b.split('.');

      const pairs = [];

      for (let index = 0; index < Math.max(aParts.length, bParts.length); index += 1)
      pairs.push(
      a: parseInt(aParts[index]),
      b: parseInt(bParts[index]),
      );


      let diff = 0;

      pairs.forEach((pair) =>
      if (diff === 0)
      if (pair.a > pair.b)
      diff = 1;

      if (pair.b > pair.a)
      diff = -1;

      if (!isNaN(pair.a) && isNaN(pair.b))
      diff = 1;

      if (isNaN(pair.a) && !isNaN(pair.b))
      diff = -1;


      );

      switch (operator)
      case '=':
      case '==':
      return diff === 0;
      case '>=':
      return diff >= 0;
      case '<=':
      return diff <= 0;
      case '>':
      return diff > 0;
      case '<':
      return diff < 0;

      default:
      throw new Error('Problem comparing versions');











      share|improve this question









      New contributor




      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      Please review and let me know which version is better. I'm just trying to find any caveats or better ways to accomplish the a version comparison independent from Android and iOS.



      Formats accepted: '1.0.0' or '1' formats and an operator, e.g: compareVersion('1', '1.2.0', '>')



      export function compareVersion(version1, version2, operator) 
      const formattedV1 = version1.split(".");
      const formattedV2 = version2.split(".");

      let diff = 0;

      if (formattedV1.length !== formattedV2.length)
      const lengthDiff = formattedV1.length - formattedV2.length;
      for (let index = 0; index < Math.abs(lengthDiff); index += 1)
      if (lengthDiff > 0)
      formattedV2.push("0");
      else
      formattedV1.push("0");




      for (let index = 0; index < formattedV1.length; index += 1)
      if (diff === 0)
      const v1 = parseInt(formattedV1[index]);
      const v2 = parseInt(formattedV2[index]);
      if (isNaN(v1)


      switch (operator)
      case "=":
      case "==":
      return diff === 0;
      case ">=":
      return diff >= 0;
      case "<=":
      return diff <= 0;
      case ">":
      return diff > 0;
      case "<":
      return diff < 0;

      default:
      throw new Error("Problem comparing versions");




      OR



      export function compareVersions(a, b, operator) 
      const aParts = a.split('.');
      const bParts = b.split('.');

      const pairs = [];

      for (let index = 0; index < Math.max(aParts.length, bParts.length); index += 1)
      pairs.push(
      a: parseInt(aParts[index]),
      b: parseInt(bParts[index]),
      );


      let diff = 0;

      pairs.forEach((pair) =>
      if (diff === 0)
      if (pair.a > pair.b)
      diff = 1;

      if (pair.b > pair.a)
      diff = -1;

      if (!isNaN(pair.a) && isNaN(pair.b))
      diff = 1;

      if (isNaN(pair.a) && !isNaN(pair.b))
      diff = -1;


      );

      switch (operator)
      case '=':
      case '==':
      return diff === 0;
      case '>=':
      return diff >= 0;
      case '<=':
      return diff <= 0;
      case '>':
      return diff > 0;
      case '<':
      return diff < 0;

      default:
      throw new Error('Problem comparing versions');








      javascript beginner comparative-review react-native






      share|improve this question









      New contributor




      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 6 mins ago









      Jamal

      30.6k11121227




      30.6k11121227






      New contributor




      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked yesterday









      VincentVincent

      211




      211




      New contributor




      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Vincent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















          1 Answer
          1






          active

          oldest

          votes


















          0












          $begingroup$

          One role



          Be careful to do only what the functions should.



          The function is called compareVersions however what it does is validate and compare versions.



          The potential throw is the result of validation and has nothing to do with comparing the values.



          As you have not called the function validateAndCompareVersions you have over stepped its role.



          How to throw



          If (and try to avoid throwing exceptions), if you must throw, throw correctly.



          In this case the first throw should be a RangeError and the message should make sense.



          You have very poor error message "Problem comparing versions: not a valid number"; The first part is redundant, exception contains a trace that will locate the "problem" and the "Problem" is implied in the fact that this is an exception.



          "not a valid number" The arguments are version strings, "1.0.0" is not a number. The error should indicate the problem explicitly.



           throw new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");


          The second exception is a little better, but could be improved



           throw new RangeError("Invalid operator: " + o);


          How to catch



          Only catch what is thrown for you. Higher level catchers will handle the rest.



          Having the throws in the function means you must add additional support code outside the function. Try catches break the flow of the code, not having a try catch means that a input error will halt the app.



          try 
          compareVersions(a,b,type);
          catch(e)
          if (e.name === "RangeError")
          // do what is needed to prevent app from stopping
          else
          throw e; // rethrow for development cycle or high level catchers




          You may need to be a little more specific, you can either extend an existing error or define a new error. Extending is the JS way so using the name property



          // in function
          const error = new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");
          error.name = "InvalidVersionStr";
          throw error;

          // outside function
          try
          compareVersions(a,b,type);
          catch(e)
          if (e.name === "InvalidVersionStr")
          // do what is needed to prevent app from stopping
          else
          throw e; // rethrow for development cycle or high level catchers




          Validate or normalize



          It is best to avoid exceptions.



          In JavaScript we can pretend we have a 3 state Boolean, true, false, and undefined. We can use the 3rd state to signal an error without needing to break flow or halt execution. You can return undefined with return;



          Then you calling function need only handle the undefined



           const versionResult = compareVersions(a, b, type);
          if (versionResult === undefined) /* put the spanner here */


          Better yet the function should assume all is good and just return true or false.



          Validate the version strings at the source and deal with it when you get it (that is where the problem actually is)



          You can either validate the version string or normalize the string



          function normaliseVersionStr(ver) ^d*$/.test(ver) ? ver : "0";

          function validateVersionStr(ver) ^d*$/.test(ver);


          // Good strings returned as they are
          normaliseVersionStr("1.0.0")
          normaliseVersionStr("1")
          normaliseVersionStr("1.000.0")

          // Bad string returned as version 0
          normaliseVersionStr("1.0.0A")
          normaliseVersionStr("1.")
          normaliseVersionStr("1.0")
          normaliseVersionStr("")


          Alternative solution



          Now that you can trust the arguments you get you can write a better function as you dont need to bother with all the possible edge cases.



          There are many ways to do this, and they depend on what you define as same, greater, less. I will assume the following



           01 == 1 == 1.0.0 == 01.0.0 == 1.00.00
          0.01.0 == 0.1.0
          0.0.1 < 0.1.0
          2.0.1 < 2.1.0
          1.9.0 < 2


          If we then pad the strings to match (each version str) parts sizes, and remove leading zeros.



           1 and 1.0.0 become 100 and 100
          1 and 2 become 1 and 2
          1 and 0.0.1 become 100 and 1
          1.99.0 and 1 become 1990 and 1000


          Then use eval to do the final operation. If you don't like eval, you can use new Function



          Example



          It is assumed that the operator is defined in the source (not as an user input). If the operator is a user input string then you should validate or normalize that string before calling the function.



          An invalid operator will throw an exception.



          // logical operator optional. Default "=="
          // "==", "<", ">", "<=", ">="
          // "=" is considered to be "=="
          // can also use "!=", "!==", "==="
          // strA, strB must be valid version strings
          function compareVersionStrings(strA, strB, operator = "==")
          const a = strA.split("."), b = strB.split(".");
          const len = Math.max(a.length, b.length);
          var valA = a.shift(), valB = b.shift(), i = 1;
          while (i < len)
          const vA = a[i] !== undefined ? a[i] : "";
          const vB = b[i] !== undefined ? b[i] : "";
          const digits = Math.max(vA.length, vB.length);
          valA += vA.padStart(digits, "0");
          valB += vB.padStart(digits, "0");
          i++;

          valA = valA.replace(/0*d$/,"");
          valB = valB.replace(/0*d$/,"");
          operator = operator === "=" ? "==" : operator;
          return eval(`$valA $operator $valB`);
          // or
          return (new Function(`return $valA $operator $valB)`)();






          share|improve this answer









          $endgroup$













            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: "196"
            ;
            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: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            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
            );



            );






            Vincent is a new contributor. Be nice, and check out our Code of Conduct.









            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217593%2fcomparing-2-ios-and-android-versions%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0












            $begingroup$

            One role



            Be careful to do only what the functions should.



            The function is called compareVersions however what it does is validate and compare versions.



            The potential throw is the result of validation and has nothing to do with comparing the values.



            As you have not called the function validateAndCompareVersions you have over stepped its role.



            How to throw



            If (and try to avoid throwing exceptions), if you must throw, throw correctly.



            In this case the first throw should be a RangeError and the message should make sense.



            You have very poor error message "Problem comparing versions: not a valid number"; The first part is redundant, exception contains a trace that will locate the "problem" and the "Problem" is implied in the fact that this is an exception.



            "not a valid number" The arguments are version strings, "1.0.0" is not a number. The error should indicate the problem explicitly.



             throw new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");


            The second exception is a little better, but could be improved



             throw new RangeError("Invalid operator: " + o);


            How to catch



            Only catch what is thrown for you. Higher level catchers will handle the rest.



            Having the throws in the function means you must add additional support code outside the function. Try catches break the flow of the code, not having a try catch means that a input error will halt the app.



            try 
            compareVersions(a,b,type);
            catch(e)
            if (e.name === "RangeError")
            // do what is needed to prevent app from stopping
            else
            throw e; // rethrow for development cycle or high level catchers




            You may need to be a little more specific, you can either extend an existing error or define a new error. Extending is the JS way so using the name property



            // in function
            const error = new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");
            error.name = "InvalidVersionStr";
            throw error;

            // outside function
            try
            compareVersions(a,b,type);
            catch(e)
            if (e.name === "InvalidVersionStr")
            // do what is needed to prevent app from stopping
            else
            throw e; // rethrow for development cycle or high level catchers




            Validate or normalize



            It is best to avoid exceptions.



            In JavaScript we can pretend we have a 3 state Boolean, true, false, and undefined. We can use the 3rd state to signal an error without needing to break flow or halt execution. You can return undefined with return;



            Then you calling function need only handle the undefined



             const versionResult = compareVersions(a, b, type);
            if (versionResult === undefined) /* put the spanner here */


            Better yet the function should assume all is good and just return true or false.



            Validate the version strings at the source and deal with it when you get it (that is where the problem actually is)



            You can either validate the version string or normalize the string



            function normaliseVersionStr(ver) ^d*$/.test(ver) ? ver : "0";

            function validateVersionStr(ver) ^d*$/.test(ver);


            // Good strings returned as they are
            normaliseVersionStr("1.0.0")
            normaliseVersionStr("1")
            normaliseVersionStr("1.000.0")

            // Bad string returned as version 0
            normaliseVersionStr("1.0.0A")
            normaliseVersionStr("1.")
            normaliseVersionStr("1.0")
            normaliseVersionStr("")


            Alternative solution



            Now that you can trust the arguments you get you can write a better function as you dont need to bother with all the possible edge cases.



            There are many ways to do this, and they depend on what you define as same, greater, less. I will assume the following



             01 == 1 == 1.0.0 == 01.0.0 == 1.00.00
            0.01.0 == 0.1.0
            0.0.1 < 0.1.0
            2.0.1 < 2.1.0
            1.9.0 < 2


            If we then pad the strings to match (each version str) parts sizes, and remove leading zeros.



             1 and 1.0.0 become 100 and 100
            1 and 2 become 1 and 2
            1 and 0.0.1 become 100 and 1
            1.99.0 and 1 become 1990 and 1000


            Then use eval to do the final operation. If you don't like eval, you can use new Function



            Example



            It is assumed that the operator is defined in the source (not as an user input). If the operator is a user input string then you should validate or normalize that string before calling the function.



            An invalid operator will throw an exception.



            // logical operator optional. Default "=="
            // "==", "<", ">", "<=", ">="
            // "=" is considered to be "=="
            // can also use "!=", "!==", "==="
            // strA, strB must be valid version strings
            function compareVersionStrings(strA, strB, operator = "==")
            const a = strA.split("."), b = strB.split(".");
            const len = Math.max(a.length, b.length);
            var valA = a.shift(), valB = b.shift(), i = 1;
            while (i < len)
            const vA = a[i] !== undefined ? a[i] : "";
            const vB = b[i] !== undefined ? b[i] : "";
            const digits = Math.max(vA.length, vB.length);
            valA += vA.padStart(digits, "0");
            valB += vB.padStart(digits, "0");
            i++;

            valA = valA.replace(/0*d$/,"");
            valB = valB.replace(/0*d$/,"");
            operator = operator === "=" ? "==" : operator;
            return eval(`$valA $operator $valB`);
            // or
            return (new Function(`return $valA $operator $valB)`)();






            share|improve this answer









            $endgroup$

















              0












              $begingroup$

              One role



              Be careful to do only what the functions should.



              The function is called compareVersions however what it does is validate and compare versions.



              The potential throw is the result of validation and has nothing to do with comparing the values.



              As you have not called the function validateAndCompareVersions you have over stepped its role.



              How to throw



              If (and try to avoid throwing exceptions), if you must throw, throw correctly.



              In this case the first throw should be a RangeError and the message should make sense.



              You have very poor error message "Problem comparing versions: not a valid number"; The first part is redundant, exception contains a trace that will locate the "problem" and the "Problem" is implied in the fact that this is an exception.



              "not a valid number" The arguments are version strings, "1.0.0" is not a number. The error should indicate the problem explicitly.



               throw new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");


              The second exception is a little better, but could be improved



               throw new RangeError("Invalid operator: " + o);


              How to catch



              Only catch what is thrown for you. Higher level catchers will handle the rest.



              Having the throws in the function means you must add additional support code outside the function. Try catches break the flow of the code, not having a try catch means that a input error will halt the app.



              try 
              compareVersions(a,b,type);
              catch(e)
              if (e.name === "RangeError")
              // do what is needed to prevent app from stopping
              else
              throw e; // rethrow for development cycle or high level catchers




              You may need to be a little more specific, you can either extend an existing error or define a new error. Extending is the JS way so using the name property



              // in function
              const error = new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");
              error.name = "InvalidVersionStr";
              throw error;

              // outside function
              try
              compareVersions(a,b,type);
              catch(e)
              if (e.name === "InvalidVersionStr")
              // do what is needed to prevent app from stopping
              else
              throw e; // rethrow for development cycle or high level catchers




              Validate or normalize



              It is best to avoid exceptions.



              In JavaScript we can pretend we have a 3 state Boolean, true, false, and undefined. We can use the 3rd state to signal an error without needing to break flow or halt execution. You can return undefined with return;



              Then you calling function need only handle the undefined



               const versionResult = compareVersions(a, b, type);
              if (versionResult === undefined) /* put the spanner here */


              Better yet the function should assume all is good and just return true or false.



              Validate the version strings at the source and deal with it when you get it (that is where the problem actually is)



              You can either validate the version string or normalize the string



              function normaliseVersionStr(ver) ^d*$/.test(ver) ? ver : "0";

              function validateVersionStr(ver) ^d*$/.test(ver);


              // Good strings returned as they are
              normaliseVersionStr("1.0.0")
              normaliseVersionStr("1")
              normaliseVersionStr("1.000.0")

              // Bad string returned as version 0
              normaliseVersionStr("1.0.0A")
              normaliseVersionStr("1.")
              normaliseVersionStr("1.0")
              normaliseVersionStr("")


              Alternative solution



              Now that you can trust the arguments you get you can write a better function as you dont need to bother with all the possible edge cases.



              There are many ways to do this, and they depend on what you define as same, greater, less. I will assume the following



               01 == 1 == 1.0.0 == 01.0.0 == 1.00.00
              0.01.0 == 0.1.0
              0.0.1 < 0.1.0
              2.0.1 < 2.1.0
              1.9.0 < 2


              If we then pad the strings to match (each version str) parts sizes, and remove leading zeros.



               1 and 1.0.0 become 100 and 100
              1 and 2 become 1 and 2
              1 and 0.0.1 become 100 and 1
              1.99.0 and 1 become 1990 and 1000


              Then use eval to do the final operation. If you don't like eval, you can use new Function



              Example



              It is assumed that the operator is defined in the source (not as an user input). If the operator is a user input string then you should validate or normalize that string before calling the function.



              An invalid operator will throw an exception.



              // logical operator optional. Default "=="
              // "==", "<", ">", "<=", ">="
              // "=" is considered to be "=="
              // can also use "!=", "!==", "==="
              // strA, strB must be valid version strings
              function compareVersionStrings(strA, strB, operator = "==")
              const a = strA.split("."), b = strB.split(".");
              const len = Math.max(a.length, b.length);
              var valA = a.shift(), valB = b.shift(), i = 1;
              while (i < len)
              const vA = a[i] !== undefined ? a[i] : "";
              const vB = b[i] !== undefined ? b[i] : "";
              const digits = Math.max(vA.length, vB.length);
              valA += vA.padStart(digits, "0");
              valB += vB.padStart(digits, "0");
              i++;

              valA = valA.replace(/0*d$/,"");
              valB = valB.replace(/0*d$/,"");
              operator = operator === "=" ? "==" : operator;
              return eval(`$valA $operator $valB`);
              // or
              return (new Function(`return $valA $operator $valB)`)();






              share|improve this answer









              $endgroup$















                0












                0








                0





                $begingroup$

                One role



                Be careful to do only what the functions should.



                The function is called compareVersions however what it does is validate and compare versions.



                The potential throw is the result of validation and has nothing to do with comparing the values.



                As you have not called the function validateAndCompareVersions you have over stepped its role.



                How to throw



                If (and try to avoid throwing exceptions), if you must throw, throw correctly.



                In this case the first throw should be a RangeError and the message should make sense.



                You have very poor error message "Problem comparing versions: not a valid number"; The first part is redundant, exception contains a trace that will locate the "problem" and the "Problem" is implied in the fact that this is an exception.



                "not a valid number" The arguments are version strings, "1.0.0" is not a number. The error should indicate the problem explicitly.



                 throw new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");


                The second exception is a little better, but could be improved



                 throw new RangeError("Invalid operator: " + o);


                How to catch



                Only catch what is thrown for you. Higher level catchers will handle the rest.



                Having the throws in the function means you must add additional support code outside the function. Try catches break the flow of the code, not having a try catch means that a input error will halt the app.



                try 
                compareVersions(a,b,type);
                catch(e)
                if (e.name === "RangeError")
                // do what is needed to prevent app from stopping
                else
                throw e; // rethrow for development cycle or high level catchers




                You may need to be a little more specific, you can either extend an existing error or define a new error. Extending is the JS way so using the name property



                // in function
                const error = new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");
                error.name = "InvalidVersionStr";
                throw error;

                // outside function
                try
                compareVersions(a,b,type);
                catch(e)
                if (e.name === "InvalidVersionStr")
                // do what is needed to prevent app from stopping
                else
                throw e; // rethrow for development cycle or high level catchers




                Validate or normalize



                It is best to avoid exceptions.



                In JavaScript we can pretend we have a 3 state Boolean, true, false, and undefined. We can use the 3rd state to signal an error without needing to break flow or halt execution. You can return undefined with return;



                Then you calling function need only handle the undefined



                 const versionResult = compareVersions(a, b, type);
                if (versionResult === undefined) /* put the spanner here */


                Better yet the function should assume all is good and just return true or false.



                Validate the version strings at the source and deal with it when you get it (that is where the problem actually is)



                You can either validate the version string or normalize the string



                function normaliseVersionStr(ver) ^d*$/.test(ver) ? ver : "0";

                function validateVersionStr(ver) ^d*$/.test(ver);


                // Good strings returned as they are
                normaliseVersionStr("1.0.0")
                normaliseVersionStr("1")
                normaliseVersionStr("1.000.0")

                // Bad string returned as version 0
                normaliseVersionStr("1.0.0A")
                normaliseVersionStr("1.")
                normaliseVersionStr("1.0")
                normaliseVersionStr("")


                Alternative solution



                Now that you can trust the arguments you get you can write a better function as you dont need to bother with all the possible edge cases.



                There are many ways to do this, and they depend on what you define as same, greater, less. I will assume the following



                 01 == 1 == 1.0.0 == 01.0.0 == 1.00.00
                0.01.0 == 0.1.0
                0.0.1 < 0.1.0
                2.0.1 < 2.1.0
                1.9.0 < 2


                If we then pad the strings to match (each version str) parts sizes, and remove leading zeros.



                 1 and 1.0.0 become 100 and 100
                1 and 2 become 1 and 2
                1 and 0.0.1 become 100 and 1
                1.99.0 and 1 become 1990 and 1000


                Then use eval to do the final operation. If you don't like eval, you can use new Function



                Example



                It is assumed that the operator is defined in the source (not as an user input). If the operator is a user input string then you should validate or normalize that string before calling the function.



                An invalid operator will throw an exception.



                // logical operator optional. Default "=="
                // "==", "<", ">", "<=", ">="
                // "=" is considered to be "=="
                // can also use "!=", "!==", "==="
                // strA, strB must be valid version strings
                function compareVersionStrings(strA, strB, operator = "==")
                const a = strA.split("."), b = strB.split(".");
                const len = Math.max(a.length, b.length);
                var valA = a.shift(), valB = b.shift(), i = 1;
                while (i < len)
                const vA = a[i] !== undefined ? a[i] : "";
                const vB = b[i] !== undefined ? b[i] : "";
                const digits = Math.max(vA.length, vB.length);
                valA += vA.padStart(digits, "0");
                valB += vB.padStart(digits, "0");
                i++;

                valA = valA.replace(/0*d$/,"");
                valB = valB.replace(/0*d$/,"");
                operator = operator === "=" ? "==" : operator;
                return eval(`$valA $operator $valB`);
                // or
                return (new Function(`return $valA $operator $valB)`)();






                share|improve this answer









                $endgroup$



                One role



                Be careful to do only what the functions should.



                The function is called compareVersions however what it does is validate and compare versions.



                The potential throw is the result of validation and has nothing to do with comparing the values.



                As you have not called the function validateAndCompareVersions you have over stepped its role.



                How to throw



                If (and try to avoid throwing exceptions), if you must throw, throw correctly.



                In this case the first throw should be a RangeError and the message should make sense.



                You have very poor error message "Problem comparing versions: not a valid number"; The first part is redundant, exception contains a trace that will locate the "problem" and the "Problem" is implied in the fact that this is an exception.



                "not a valid number" The arguments are version strings, "1.0.0" is not a number. The error should indicate the problem explicitly.



                 throw new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");


                The second exception is a little better, but could be improved



                 throw new RangeError("Invalid operator: " + o);


                How to catch



                Only catch what is thrown for you. Higher level catchers will handle the rest.



                Having the throws in the function means you must add additional support code outside the function. Try catches break the flow of the code, not having a try catch means that a input error will halt the app.



                try 
                compareVersions(a,b,type);
                catch(e)
                if (e.name === "RangeError")
                // do what is needed to prevent app from stopping
                else
                throw e; // rethrow for development cycle or high level catchers




                You may need to be a little more specific, you can either extend an existing error or define a new error. Extending is the JS way so using the name property



                // in function
                const error = new RangeError("Invalid version string: '" + (isNaN(v1) ? v1 : v2) + "'");
                error.name = "InvalidVersionStr";
                throw error;

                // outside function
                try
                compareVersions(a,b,type);
                catch(e)
                if (e.name === "InvalidVersionStr")
                // do what is needed to prevent app from stopping
                else
                throw e; // rethrow for development cycle or high level catchers




                Validate or normalize



                It is best to avoid exceptions.



                In JavaScript we can pretend we have a 3 state Boolean, true, false, and undefined. We can use the 3rd state to signal an error without needing to break flow or halt execution. You can return undefined with return;



                Then you calling function need only handle the undefined



                 const versionResult = compareVersions(a, b, type);
                if (versionResult === undefined) /* put the spanner here */


                Better yet the function should assume all is good and just return true or false.



                Validate the version strings at the source and deal with it when you get it (that is where the problem actually is)



                You can either validate the version string or normalize the string



                function normaliseVersionStr(ver) ^d*$/.test(ver) ? ver : "0";

                function validateVersionStr(ver) ^d*$/.test(ver);


                // Good strings returned as they are
                normaliseVersionStr("1.0.0")
                normaliseVersionStr("1")
                normaliseVersionStr("1.000.0")

                // Bad string returned as version 0
                normaliseVersionStr("1.0.0A")
                normaliseVersionStr("1.")
                normaliseVersionStr("1.0")
                normaliseVersionStr("")


                Alternative solution



                Now that you can trust the arguments you get you can write a better function as you dont need to bother with all the possible edge cases.



                There are many ways to do this, and they depend on what you define as same, greater, less. I will assume the following



                 01 == 1 == 1.0.0 == 01.0.0 == 1.00.00
                0.01.0 == 0.1.0
                0.0.1 < 0.1.0
                2.0.1 < 2.1.0
                1.9.0 < 2


                If we then pad the strings to match (each version str) parts sizes, and remove leading zeros.



                 1 and 1.0.0 become 100 and 100
                1 and 2 become 1 and 2
                1 and 0.0.1 become 100 and 1
                1.99.0 and 1 become 1990 and 1000


                Then use eval to do the final operation. If you don't like eval, you can use new Function



                Example



                It is assumed that the operator is defined in the source (not as an user input). If the operator is a user input string then you should validate or normalize that string before calling the function.



                An invalid operator will throw an exception.



                // logical operator optional. Default "=="
                // "==", "<", ">", "<=", ">="
                // "=" is considered to be "=="
                // can also use "!=", "!==", "==="
                // strA, strB must be valid version strings
                function compareVersionStrings(strA, strB, operator = "==")
                const a = strA.split("."), b = strB.split(".");
                const len = Math.max(a.length, b.length);
                var valA = a.shift(), valB = b.shift(), i = 1;
                while (i < len)
                const vA = a[i] !== undefined ? a[i] : "";
                const vB = b[i] !== undefined ? b[i] : "";
                const digits = Math.max(vA.length, vB.length);
                valA += vA.padStart(digits, "0");
                valB += vB.padStart(digits, "0");
                i++;

                valA = valA.replace(/0*d$/,"");
                valB = valB.replace(/0*d$/,"");
                operator = operator === "=" ? "==" : operator;
                return eval(`$valA $operator $valB`);
                // or
                return (new Function(`return $valA $operator $valB)`)();







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 14 hours ago









                Blindman67Blindman67

                9,6801622




                9,6801622




















                    Vincent is a new contributor. Be nice, and check out our Code of Conduct.









                    draft saved

                    draft discarded


















                    Vincent is a new contributor. Be nice, and check out our Code of Conduct.












                    Vincent is a new contributor. Be nice, and check out our Code of Conduct.











                    Vincent is a new contributor. Be nice, and check out our Code of Conduct.














                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • 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.

                    Use MathJax to format equations. MathJax reference.


                    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%2fcodereview.stackexchange.com%2fquestions%2f217593%2fcomparing-2-ios-and-android-versions%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

                    名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

                    Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

                    Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar