Message-formatting code with pluralization, revised to be more functionalTrying to find a good design for reading in values of different types from a fileMutable String ClassFormatting phone number without knowing localeVariant class (named any like in boost::any)Giveth me thy easier user input in C++ - follow upPattern for writing a generic string transformation functionBinary test file generator with checksumC++ Parsing with chain of responsibilityGeneric Skip list implementation in C++ Version 3Object-oriented calculator

Masking using two sliders on Google Earth Engine

How to choose using Collection<Id> rather than Collection<String>, or the opposite?

Solve equation using Mathematica

Can you continue the movement of a Bonus Action Dash granted by Expeditious Retreat if your Concentration is broken mid-move?

How can a class have multiple methods without breaking the single responsibility principle

How would a lunar colony attack Earth?

Is there a word or phrase that means 'works but not for the reason we expect it to'?

May a hotel provide accommodation for fewer people than booked?

Should students have access to past exams or an exam bank?

How to innovate in OR

Unknown indication below upper stave

How can Paypal know my card is being used in another account?

What is my clock telling me to do?

Why would an invisible personal shield be necessary?

What force enables us to walk? Friction or normal reaction?

How can I solve this sudoku?

Typesetting numbers above, below, left, and right of a symbol

How can flights operated by the same company have such different prices when marketed by another?

Why didn't Stark and Nebula use jump points with their ship to go back to Earth?

Easy way to get process from window

How did astronauts using rovers tell direction without compasses on the Moon?

why there is no “error” term in survival analysis?

Why are prop blades not shaped like household fan blades?

Can machine learning learn a function like finding maximum from a list?



Message-formatting code with pluralization, revised to be more functional


Trying to find a good design for reading in values of different types from a fileMutable String ClassFormatting phone number without knowing localeVariant class (named any like in boost::any)Giveth me thy easier user input in C++ - follow upPattern for writing a generic string transformation functionBinary test file generator with checksumC++ Parsing with chain of responsibilityGeneric Skip list implementation in C++ Version 3Object-oriented calculator






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








15












$begingroup$


I'm a C++ dev, and I've recently started working my way through Clean Code*. Whenever I encounter an example I think I could improve, I try to re-implement it in C++.



On pp. 28-29 there is an example with a message building class, which looks like this when implemented in C++ (includes and namespaces omitted):

.h




class GuessStatisticsMessage

public:
GuessStatisticsMessage() = default;
~GuessStatisticsMessage() = default;

std::string make(char candidate, int count);

private:
void createPluralDependentMessageParts(int count);
void createThereAreManyLetters(int count);
void createThereIsOneLetter();
void createThereAreNoLetters();

std::string number;
std::string verb;
std::string pluralModifier;
;



.cpp




std::string GuessStatisticsMessage::make(char candidate, int count)

createPluralDependentMessageParts(count);
return fmt::format("There ", verb, number, candidate, pluralModifier);


void GuessStatisticsMessage::createPluralDependentMessageParts(int count)

if (count == 0)
createThereAreNoLetters();
else if (count == 1)
createThereIsOneLetter();
else
createThereAreManyLetters(count);



void GuessStatisticsMessage::createThereAreManyLetters(int count)

verb = "are";
number = std::to_string(count);
pluralModifier = "s";


void GuessStatisticsMessage::createThereIsOneLetter()

verb = "is";
number = "one";
pluralModifier = "";


void GuessStatisticsMessage::createThereAreNoLetters()

verb = "are";
number = "no";
pluralModifier = "s";




In an attempt to make this code more functional I ended up with the following:

.h



class GuessStatisticsMessageAlt

public:
GuessStatisticsMessageAlt() = default;
~GuessStatisticsMessageAlt() = default;

std::string make(char candidate, int count);

private:
struct MessageComponents

std::string verb;
std::string number;
std::string pluralModifier;
;

MessageComponents createPluralDependentMessageParts(int count);
MessageComponents createThereAreManyLetters(int count);
MessageComponents createThereIsOneLetter();
MessageComponents createThereAreNoLetters();
;


.cpp



std::string GuessStatisticsMessageAlt::make(char candidate, int count)

auto messageComponents = createPluralDependentMessageParts(count);
return fmt::format("There ", messageComponents.verb, messageComponents.number,
candidate, messageComponents.pluralModifier);


GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createPluralDependentMessageParts(int count)

if (count == 0)
return createThereAreNoLetters();
else if (count == 1)
return createThereIsOneLetter();
else
return createThereAreManyLetters(count);



GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreManyLetters(int count)

return "are", std::to_string(count), "s" ;


GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereIsOneLetter()

return "is", "one", "" ;


GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreNoLetters()

return "are", "no", "s" ;



Since at this point there was no real need for a class, I continued, reaching the final result:

.h



std::string makeGuessStatisticsMessage(char candidate, int count);


.cpp



namespace 

struct MessageComponents

std::string verb;
std::string number;
std::string pluralModifier;
;

MessageComponents createThereAreManyLetters(int count)

return "are", std::to_string(count), "s" ;


MessageComponents createThereIsOneLetter()

return "is", "one", "" ;


MessageComponents createThereAreNoLetters()

return "are", "no", "s" ;


MessageComponents createPluralDependentMessageParts(int count)

if (count == 0)
return createThereAreNoLetters();

else if (count == 1)
return createThereIsOneLetter();

else
return createThereAreManyLetters(count);





std::string makeGuessStatisticsMessage(char candidate, int count)

auto messageComponents = createPluralDependentMessageParts(count);
return fmt::format("There ", messageComponents.verb, messageComponents.number,
candidate, messageComponents.pluralModifier);



The point is, I grapple a bit with when to apply different programming paradigms and find it difficult to decide if my re-implementation is actually an improvement in this case. In particular, hiding so much stuff in the anonymous namespace is something that bothers me somewhat.



So the primary question is - is this really an improvement? And the secondary - how can I learn to judge this better?



I hope it isn't too opinion-based, as this is a real struggle for me.




* Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin










share|improve this question











$endgroup$




















    15












    $begingroup$


    I'm a C++ dev, and I've recently started working my way through Clean Code*. Whenever I encounter an example I think I could improve, I try to re-implement it in C++.



    On pp. 28-29 there is an example with a message building class, which looks like this when implemented in C++ (includes and namespaces omitted):

    .h




    class GuessStatisticsMessage

    public:
    GuessStatisticsMessage() = default;
    ~GuessStatisticsMessage() = default;

    std::string make(char candidate, int count);

    private:
    void createPluralDependentMessageParts(int count);
    void createThereAreManyLetters(int count);
    void createThereIsOneLetter();
    void createThereAreNoLetters();

    std::string number;
    std::string verb;
    std::string pluralModifier;
    ;



    .cpp




    std::string GuessStatisticsMessage::make(char candidate, int count)

    createPluralDependentMessageParts(count);
    return fmt::format("There ", verb, number, candidate, pluralModifier);


    void GuessStatisticsMessage::createPluralDependentMessageParts(int count)

    if (count == 0)
    createThereAreNoLetters();
    else if (count == 1)
    createThereIsOneLetter();
    else
    createThereAreManyLetters(count);



    void GuessStatisticsMessage::createThereAreManyLetters(int count)

    verb = "are";
    number = std::to_string(count);
    pluralModifier = "s";


    void GuessStatisticsMessage::createThereIsOneLetter()

    verb = "is";
    number = "one";
    pluralModifier = "";


    void GuessStatisticsMessage::createThereAreNoLetters()

    verb = "are";
    number = "no";
    pluralModifier = "s";




    In an attempt to make this code more functional I ended up with the following:

    .h



    class GuessStatisticsMessageAlt

    public:
    GuessStatisticsMessageAlt() = default;
    ~GuessStatisticsMessageAlt() = default;

    std::string make(char candidate, int count);

    private:
    struct MessageComponents

    std::string verb;
    std::string number;
    std::string pluralModifier;
    ;

    MessageComponents createPluralDependentMessageParts(int count);
    MessageComponents createThereAreManyLetters(int count);
    MessageComponents createThereIsOneLetter();
    MessageComponents createThereAreNoLetters();
    ;


    .cpp



    std::string GuessStatisticsMessageAlt::make(char candidate, int count)

    auto messageComponents = createPluralDependentMessageParts(count);
    return fmt::format("There ", messageComponents.verb, messageComponents.number,
    candidate, messageComponents.pluralModifier);


    GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createPluralDependentMessageParts(int count)

    if (count == 0)
    return createThereAreNoLetters();
    else if (count == 1)
    return createThereIsOneLetter();
    else
    return createThereAreManyLetters(count);



    GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreManyLetters(int count)

    return "are", std::to_string(count), "s" ;


    GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereIsOneLetter()

    return "is", "one", "" ;


    GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreNoLetters()

    return "are", "no", "s" ;



    Since at this point there was no real need for a class, I continued, reaching the final result:

    .h



    std::string makeGuessStatisticsMessage(char candidate, int count);


    .cpp



    namespace 

    struct MessageComponents

    std::string verb;
    std::string number;
    std::string pluralModifier;
    ;

    MessageComponents createThereAreManyLetters(int count)

    return "are", std::to_string(count), "s" ;


    MessageComponents createThereIsOneLetter()

    return "is", "one", "" ;


    MessageComponents createThereAreNoLetters()

    return "are", "no", "s" ;


    MessageComponents createPluralDependentMessageParts(int count)

    if (count == 0)
    return createThereAreNoLetters();

    else if (count == 1)
    return createThereIsOneLetter();

    else
    return createThereAreManyLetters(count);





    std::string makeGuessStatisticsMessage(char candidate, int count)

    auto messageComponents = createPluralDependentMessageParts(count);
    return fmt::format("There ", messageComponents.verb, messageComponents.number,
    candidate, messageComponents.pluralModifier);



    The point is, I grapple a bit with when to apply different programming paradigms and find it difficult to decide if my re-implementation is actually an improvement in this case. In particular, hiding so much stuff in the anonymous namespace is something that bothers me somewhat.



    So the primary question is - is this really an improvement? And the secondary - how can I learn to judge this better?



    I hope it isn't too opinion-based, as this is a real struggle for me.




    * Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin










    share|improve this question











    $endgroup$
















      15












      15








      15


      2



      $begingroup$


      I'm a C++ dev, and I've recently started working my way through Clean Code*. Whenever I encounter an example I think I could improve, I try to re-implement it in C++.



      On pp. 28-29 there is an example with a message building class, which looks like this when implemented in C++ (includes and namespaces omitted):

      .h




      class GuessStatisticsMessage

      public:
      GuessStatisticsMessage() = default;
      ~GuessStatisticsMessage() = default;

      std::string make(char candidate, int count);

      private:
      void createPluralDependentMessageParts(int count);
      void createThereAreManyLetters(int count);
      void createThereIsOneLetter();
      void createThereAreNoLetters();

      std::string number;
      std::string verb;
      std::string pluralModifier;
      ;



      .cpp




      std::string GuessStatisticsMessage::make(char candidate, int count)

      createPluralDependentMessageParts(count);
      return fmt::format("There ", verb, number, candidate, pluralModifier);


      void GuessStatisticsMessage::createPluralDependentMessageParts(int count)

      if (count == 0)
      createThereAreNoLetters();
      else if (count == 1)
      createThereIsOneLetter();
      else
      createThereAreManyLetters(count);



      void GuessStatisticsMessage::createThereAreManyLetters(int count)

      verb = "are";
      number = std::to_string(count);
      pluralModifier = "s";


      void GuessStatisticsMessage::createThereIsOneLetter()

      verb = "is";
      number = "one";
      pluralModifier = "";


      void GuessStatisticsMessage::createThereAreNoLetters()

      verb = "are";
      number = "no";
      pluralModifier = "s";




      In an attempt to make this code more functional I ended up with the following:

      .h



      class GuessStatisticsMessageAlt

      public:
      GuessStatisticsMessageAlt() = default;
      ~GuessStatisticsMessageAlt() = default;

      std::string make(char candidate, int count);

      private:
      struct MessageComponents

      std::string verb;
      std::string number;
      std::string pluralModifier;
      ;

      MessageComponents createPluralDependentMessageParts(int count);
      MessageComponents createThereAreManyLetters(int count);
      MessageComponents createThereIsOneLetter();
      MessageComponents createThereAreNoLetters();
      ;


      .cpp



      std::string GuessStatisticsMessageAlt::make(char candidate, int count)

      auto messageComponents = createPluralDependentMessageParts(count);
      return fmt::format("There ", messageComponents.verb, messageComponents.number,
      candidate, messageComponents.pluralModifier);


      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createPluralDependentMessageParts(int count)

      if (count == 0)
      return createThereAreNoLetters();
      else if (count == 1)
      return createThereIsOneLetter();
      else
      return createThereAreManyLetters(count);



      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreManyLetters(int count)

      return "are", std::to_string(count), "s" ;


      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereIsOneLetter()

      return "is", "one", "" ;


      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreNoLetters()

      return "are", "no", "s" ;



      Since at this point there was no real need for a class, I continued, reaching the final result:

      .h



      std::string makeGuessStatisticsMessage(char candidate, int count);


      .cpp



      namespace 

      struct MessageComponents

      std::string verb;
      std::string number;
      std::string pluralModifier;
      ;

      MessageComponents createThereAreManyLetters(int count)

      return "are", std::to_string(count), "s" ;


      MessageComponents createThereIsOneLetter()

      return "is", "one", "" ;


      MessageComponents createThereAreNoLetters()

      return "are", "no", "s" ;


      MessageComponents createPluralDependentMessageParts(int count)

      if (count == 0)
      return createThereAreNoLetters();

      else if (count == 1)
      return createThereIsOneLetter();

      else
      return createThereAreManyLetters(count);





      std::string makeGuessStatisticsMessage(char candidate, int count)

      auto messageComponents = createPluralDependentMessageParts(count);
      return fmt::format("There ", messageComponents.verb, messageComponents.number,
      candidate, messageComponents.pluralModifier);



      The point is, I grapple a bit with when to apply different programming paradigms and find it difficult to decide if my re-implementation is actually an improvement in this case. In particular, hiding so much stuff in the anonymous namespace is something that bothers me somewhat.



      So the primary question is - is this really an improvement? And the secondary - how can I learn to judge this better?



      I hope it isn't too opinion-based, as this is a real struggle for me.




      * Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin










      share|improve this question











      $endgroup$




      I'm a C++ dev, and I've recently started working my way through Clean Code*. Whenever I encounter an example I think I could improve, I try to re-implement it in C++.



      On pp. 28-29 there is an example with a message building class, which looks like this when implemented in C++ (includes and namespaces omitted):

      .h




      class GuessStatisticsMessage

      public:
      GuessStatisticsMessage() = default;
      ~GuessStatisticsMessage() = default;

      std::string make(char candidate, int count);

      private:
      void createPluralDependentMessageParts(int count);
      void createThereAreManyLetters(int count);
      void createThereIsOneLetter();
      void createThereAreNoLetters();

      std::string number;
      std::string verb;
      std::string pluralModifier;
      ;



      .cpp




      std::string GuessStatisticsMessage::make(char candidate, int count)

      createPluralDependentMessageParts(count);
      return fmt::format("There ", verb, number, candidate, pluralModifier);


      void GuessStatisticsMessage::createPluralDependentMessageParts(int count)

      if (count == 0)
      createThereAreNoLetters();
      else if (count == 1)
      createThereIsOneLetter();
      else
      createThereAreManyLetters(count);



      void GuessStatisticsMessage::createThereAreManyLetters(int count)

      verb = "are";
      number = std::to_string(count);
      pluralModifier = "s";


      void GuessStatisticsMessage::createThereIsOneLetter()

      verb = "is";
      number = "one";
      pluralModifier = "";


      void GuessStatisticsMessage::createThereAreNoLetters()

      verb = "are";
      number = "no";
      pluralModifier = "s";




      In an attempt to make this code more functional I ended up with the following:

      .h



      class GuessStatisticsMessageAlt

      public:
      GuessStatisticsMessageAlt() = default;
      ~GuessStatisticsMessageAlt() = default;

      std::string make(char candidate, int count);

      private:
      struct MessageComponents

      std::string verb;
      std::string number;
      std::string pluralModifier;
      ;

      MessageComponents createPluralDependentMessageParts(int count);
      MessageComponents createThereAreManyLetters(int count);
      MessageComponents createThereIsOneLetter();
      MessageComponents createThereAreNoLetters();
      ;


      .cpp



      std::string GuessStatisticsMessageAlt::make(char candidate, int count)

      auto messageComponents = createPluralDependentMessageParts(count);
      return fmt::format("There ", messageComponents.verb, messageComponents.number,
      candidate, messageComponents.pluralModifier);


      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createPluralDependentMessageParts(int count)

      if (count == 0)
      return createThereAreNoLetters();
      else if (count == 1)
      return createThereIsOneLetter();
      else
      return createThereAreManyLetters(count);



      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreManyLetters(int count)

      return "are", std::to_string(count), "s" ;


      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereIsOneLetter()

      return "is", "one", "" ;


      GuessStatisticsMessageAlt::MessageComponents GuessStatisticsMessageAlt::createThereAreNoLetters()

      return "are", "no", "s" ;



      Since at this point there was no real need for a class, I continued, reaching the final result:

      .h



      std::string makeGuessStatisticsMessage(char candidate, int count);


      .cpp



      namespace 

      struct MessageComponents

      std::string verb;
      std::string number;
      std::string pluralModifier;
      ;

      MessageComponents createThereAreManyLetters(int count)

      return "are", std::to_string(count), "s" ;


      MessageComponents createThereIsOneLetter()

      return "is", "one", "" ;


      MessageComponents createThereAreNoLetters()

      return "are", "no", "s" ;


      MessageComponents createPluralDependentMessageParts(int count)

      if (count == 0)
      return createThereAreNoLetters();

      else if (count == 1)
      return createThereIsOneLetter();

      else
      return createThereAreManyLetters(count);





      std::string makeGuessStatisticsMessage(char candidate, int count)

      auto messageComponents = createPluralDependentMessageParts(count);
      return fmt::format("There ", messageComponents.verb, messageComponents.number,
      candidate, messageComponents.pluralModifier);



      The point is, I grapple a bit with when to apply different programming paradigms and find it difficult to decide if my re-implementation is actually an improvement in this case. In particular, hiding so much stuff in the anonymous namespace is something that bothers me somewhat.



      So the primary question is - is this really an improvement? And the secondary - how can I learn to judge this better?



      I hope it isn't too opinion-based, as this is a real struggle for me.




      * Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin







      c++ object-oriented functional-programming comparative-review formatting






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jul 22 at 22:08









      200_success

      135k21 gold badges173 silver badges443 bronze badges




      135k21 gold badges173 silver badges443 bronze badges










      asked Jul 21 at 9:48









      SG_90SG_90

      785 bronze badges




      785 bronze badges























          2 Answers
          2






          active

          oldest

          votes


















          10












          $begingroup$

          • Getting rid of the class is definitely a step in the right direction.


          • Assuming count can never be negative, we should use an unsigned integer type for it.


          • I don't think the MessageComponents class is a good idea. It makes the design very inflexible. If we ever want to change the message, we'll have to change every single function there.


          • We're programming a very specific output message, and the code doesn't seem to be intended for re-use, so I don't think we need the named functions either.



          I'd suggest something more like:



          std::string makeStatisticsMessage(char letter, unsigned int count)

          auto const verb = (count == 1) ? "is" : "are";
          auto const number = (count == 0) ? "no" : (count == 1) ? "one" : std::to_string(count);
          auto const plural = (count == 1) ? "" : "s";
          return fmt::format("There ''.", verb, number, letter, plural);



          Although we now check count multiple times, I'd argue that it's much easier to follow the logic for each component separately.



          It also means that we can abstract or change the behavior for each component later (e.g. if we decide we want to print all the numbers as words instead of digits).






          share|improve this answer









          $endgroup$










          • 1




            $begingroup$
            One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:15






          • 4




            $begingroup$
            Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:22










          • $begingroup$
            I've accepted this answer since the other one builds on it. Both of them were helpful, though.
            $endgroup$
            – SG_90
            Jul 23 at 18:19



















          8












          $begingroup$

          While I am supporting @user673679's approach a lot in terms that putting everything into a single function, I still have concerns:




          1. Using an interface might be better if you want to refactor the functionality to support multiple languages:



            struct IGuessStatisticsMessage 
            virtual std::string makeStatisticsMessage(char letter, unsigned int count) = 0;
            virtual ~IGuessStatisticsMessage()
            ;


            This would allow to provide implementations for different languages easier:



            struct GuessStatisticsMessage_EN() : public IGuessStatisticsMessage 
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const verb = (count == 1) ? "is" : "are";
            auto const number = (count == 0) ? "no" : (count == 1) ? "one" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);

            ;

            struct GuessStatisticsMessage_DE() : public IGuessStatisticsMessage
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const number = (count == 0) ? "kein" : (count == 1) ? "ein" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("Es gibt ''.", number, letter, plural);

            ;



          2. Also I am not a friend of nested ternary expressions, they generally tend to be hard to read. I'd rather use some code like this:



            std::string makeStatisticsMessage(char letter, unsigned int count) {
            auto const verb = (count == 1) ? "is" : "are";
            std::string number;
            if(count == 0)
            number = "no";
            else if (count == 1)
            number = "one";

            else
            number = std::to_string(count);

            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);







          share|improve this answer











          $endgroup$














          • $begingroup$
            Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
            $endgroup$
            – SG_90
            Jul 23 at 18:16










          • $begingroup$
            @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
            $endgroup$
            – πάντα ῥεῖ
            Jul 23 at 18:21














          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
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f224603%2fmessage-formatting-code-with-pluralization-revised-to-be-more-functional%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          10












          $begingroup$

          • Getting rid of the class is definitely a step in the right direction.


          • Assuming count can never be negative, we should use an unsigned integer type for it.


          • I don't think the MessageComponents class is a good idea. It makes the design very inflexible. If we ever want to change the message, we'll have to change every single function there.


          • We're programming a very specific output message, and the code doesn't seem to be intended for re-use, so I don't think we need the named functions either.



          I'd suggest something more like:



          std::string makeStatisticsMessage(char letter, unsigned int count)

          auto const verb = (count == 1) ? "is" : "are";
          auto const number = (count == 0) ? "no" : (count == 1) ? "one" : std::to_string(count);
          auto const plural = (count == 1) ? "" : "s";
          return fmt::format("There ''.", verb, number, letter, plural);



          Although we now check count multiple times, I'd argue that it's much easier to follow the logic for each component separately.



          It also means that we can abstract or change the behavior for each component later (e.g. if we decide we want to print all the numbers as words instead of digits).






          share|improve this answer









          $endgroup$










          • 1




            $begingroup$
            One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:15






          • 4




            $begingroup$
            Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:22










          • $begingroup$
            I've accepted this answer since the other one builds on it. Both of them were helpful, though.
            $endgroup$
            – SG_90
            Jul 23 at 18:19
















          10












          $begingroup$

          • Getting rid of the class is definitely a step in the right direction.


          • Assuming count can never be negative, we should use an unsigned integer type for it.


          • I don't think the MessageComponents class is a good idea. It makes the design very inflexible. If we ever want to change the message, we'll have to change every single function there.


          • We're programming a very specific output message, and the code doesn't seem to be intended for re-use, so I don't think we need the named functions either.



          I'd suggest something more like:



          std::string makeStatisticsMessage(char letter, unsigned int count)

          auto const verb = (count == 1) ? "is" : "are";
          auto const number = (count == 0) ? "no" : (count == 1) ? "one" : std::to_string(count);
          auto const plural = (count == 1) ? "" : "s";
          return fmt::format("There ''.", verb, number, letter, plural);



          Although we now check count multiple times, I'd argue that it's much easier to follow the logic for each component separately.



          It also means that we can abstract or change the behavior for each component later (e.g. if we decide we want to print all the numbers as words instead of digits).






          share|improve this answer









          $endgroup$










          • 1




            $begingroup$
            One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:15






          • 4




            $begingroup$
            Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:22










          • $begingroup$
            I've accepted this answer since the other one builds on it. Both of them were helpful, though.
            $endgroup$
            – SG_90
            Jul 23 at 18:19














          10












          10








          10





          $begingroup$

          • Getting rid of the class is definitely a step in the right direction.


          • Assuming count can never be negative, we should use an unsigned integer type for it.


          • I don't think the MessageComponents class is a good idea. It makes the design very inflexible. If we ever want to change the message, we'll have to change every single function there.


          • We're programming a very specific output message, and the code doesn't seem to be intended for re-use, so I don't think we need the named functions either.



          I'd suggest something more like:



          std::string makeStatisticsMessage(char letter, unsigned int count)

          auto const verb = (count == 1) ? "is" : "are";
          auto const number = (count == 0) ? "no" : (count == 1) ? "one" : std::to_string(count);
          auto const plural = (count == 1) ? "" : "s";
          return fmt::format("There ''.", verb, number, letter, plural);



          Although we now check count multiple times, I'd argue that it's much easier to follow the logic for each component separately.



          It also means that we can abstract or change the behavior for each component later (e.g. if we decide we want to print all the numbers as words instead of digits).






          share|improve this answer









          $endgroup$



          • Getting rid of the class is definitely a step in the right direction.


          • Assuming count can never be negative, we should use an unsigned integer type for it.


          • I don't think the MessageComponents class is a good idea. It makes the design very inflexible. If we ever want to change the message, we'll have to change every single function there.


          • We're programming a very specific output message, and the code doesn't seem to be intended for re-use, so I don't think we need the named functions either.



          I'd suggest something more like:



          std::string makeStatisticsMessage(char letter, unsigned int count)

          auto const verb = (count == 1) ? "is" : "are";
          auto const number = (count == 0) ? "no" : (count == 1) ? "one" : std::to_string(count);
          auto const plural = (count == 1) ? "" : "s";
          return fmt::format("There ''.", verb, number, letter, plural);



          Although we now check count multiple times, I'd argue that it's much easier to follow the logic for each component separately.



          It also means that we can abstract or change the behavior for each component later (e.g. if we decide we want to print all the numbers as words instead of digits).







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jul 21 at 11:25









          user673679user673679

          4,6951 gold badge14 silver badges34 bronze badges




          4,6951 gold badge14 silver badges34 bronze badges










          • 1




            $begingroup$
            One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:15






          • 4




            $begingroup$
            Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:22










          • $begingroup$
            I've accepted this answer since the other one builds on it. Both of them were helpful, though.
            $endgroup$
            – SG_90
            Jul 23 at 18:19













          • 1




            $begingroup$
            One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:15






          • 4




            $begingroup$
            Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
            $endgroup$
            – πάντα ῥεῖ
            Jul 21 at 12:22










          • $begingroup$
            I've accepted this answer since the other one builds on it. Both of them were helpful, though.
            $endgroup$
            – SG_90
            Jul 23 at 18:19








          1




          1




          $begingroup$
          One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
          $endgroup$
          – πάντα ῥεῖ
          Jul 21 at 12:15




          $begingroup$
          One reason to use a class rather than a simple function could be a redesign to allow multiple languages for the output. In this case I would define a interface with a virtual function makeStatisticsMessage() and several inherited classes for the specific languages which should be supported.
          $endgroup$
          – πάντα ῥεῖ
          Jul 21 at 12:15




          4




          4




          $begingroup$
          Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
          $endgroup$
          – πάντα ῥεῖ
          Jul 21 at 12:22




          $begingroup$
          Also to enhance readability of your conditional logic, I'd recommend to avoid nested ternary operations in favor of if / else statements. The result would be the same and it's much better to follow for anyone (beginner or expert).
          $endgroup$
          – πάντα ῥεῖ
          Jul 21 at 12:22












          $begingroup$
          I've accepted this answer since the other one builds on it. Both of them were helpful, though.
          $endgroup$
          – SG_90
          Jul 23 at 18:19





          $begingroup$
          I've accepted this answer since the other one builds on it. Both of them were helpful, though.
          $endgroup$
          – SG_90
          Jul 23 at 18:19














          8












          $begingroup$

          While I am supporting @user673679's approach a lot in terms that putting everything into a single function, I still have concerns:




          1. Using an interface might be better if you want to refactor the functionality to support multiple languages:



            struct IGuessStatisticsMessage 
            virtual std::string makeStatisticsMessage(char letter, unsigned int count) = 0;
            virtual ~IGuessStatisticsMessage()
            ;


            This would allow to provide implementations for different languages easier:



            struct GuessStatisticsMessage_EN() : public IGuessStatisticsMessage 
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const verb = (count == 1) ? "is" : "are";
            auto const number = (count == 0) ? "no" : (count == 1) ? "one" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);

            ;

            struct GuessStatisticsMessage_DE() : public IGuessStatisticsMessage
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const number = (count == 0) ? "kein" : (count == 1) ? "ein" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("Es gibt ''.", number, letter, plural);

            ;



          2. Also I am not a friend of nested ternary expressions, they generally tend to be hard to read. I'd rather use some code like this:



            std::string makeStatisticsMessage(char letter, unsigned int count) {
            auto const verb = (count == 1) ? "is" : "are";
            std::string number;
            if(count == 0)
            number = "no";
            else if (count == 1)
            number = "one";

            else
            number = std::to_string(count);

            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);







          share|improve this answer











          $endgroup$














          • $begingroup$
            Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
            $endgroup$
            – SG_90
            Jul 23 at 18:16










          • $begingroup$
            @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
            $endgroup$
            – πάντα ῥεῖ
            Jul 23 at 18:21
















          8












          $begingroup$

          While I am supporting @user673679's approach a lot in terms that putting everything into a single function, I still have concerns:




          1. Using an interface might be better if you want to refactor the functionality to support multiple languages:



            struct IGuessStatisticsMessage 
            virtual std::string makeStatisticsMessage(char letter, unsigned int count) = 0;
            virtual ~IGuessStatisticsMessage()
            ;


            This would allow to provide implementations for different languages easier:



            struct GuessStatisticsMessage_EN() : public IGuessStatisticsMessage 
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const verb = (count == 1) ? "is" : "are";
            auto const number = (count == 0) ? "no" : (count == 1) ? "one" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);

            ;

            struct GuessStatisticsMessage_DE() : public IGuessStatisticsMessage
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const number = (count == 0) ? "kein" : (count == 1) ? "ein" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("Es gibt ''.", number, letter, plural);

            ;



          2. Also I am not a friend of nested ternary expressions, they generally tend to be hard to read. I'd rather use some code like this:



            std::string makeStatisticsMessage(char letter, unsigned int count) {
            auto const verb = (count == 1) ? "is" : "are";
            std::string number;
            if(count == 0)
            number = "no";
            else if (count == 1)
            number = "one";

            else
            number = std::to_string(count);

            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);







          share|improve this answer











          $endgroup$














          • $begingroup$
            Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
            $endgroup$
            – SG_90
            Jul 23 at 18:16










          • $begingroup$
            @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
            $endgroup$
            – πάντα ῥεῖ
            Jul 23 at 18:21














          8












          8








          8





          $begingroup$

          While I am supporting @user673679's approach a lot in terms that putting everything into a single function, I still have concerns:




          1. Using an interface might be better if you want to refactor the functionality to support multiple languages:



            struct IGuessStatisticsMessage 
            virtual std::string makeStatisticsMessage(char letter, unsigned int count) = 0;
            virtual ~IGuessStatisticsMessage()
            ;


            This would allow to provide implementations for different languages easier:



            struct GuessStatisticsMessage_EN() : public IGuessStatisticsMessage 
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const verb = (count == 1) ? "is" : "are";
            auto const number = (count == 0) ? "no" : (count == 1) ? "one" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);

            ;

            struct GuessStatisticsMessage_DE() : public IGuessStatisticsMessage
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const number = (count == 0) ? "kein" : (count == 1) ? "ein" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("Es gibt ''.", number, letter, plural);

            ;



          2. Also I am not a friend of nested ternary expressions, they generally tend to be hard to read. I'd rather use some code like this:



            std::string makeStatisticsMessage(char letter, unsigned int count) {
            auto const verb = (count == 1) ? "is" : "are";
            std::string number;
            if(count == 0)
            number = "no";
            else if (count == 1)
            number = "one";

            else
            number = std::to_string(count);

            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);







          share|improve this answer











          $endgroup$



          While I am supporting @user673679's approach a lot in terms that putting everything into a single function, I still have concerns:




          1. Using an interface might be better if you want to refactor the functionality to support multiple languages:



            struct IGuessStatisticsMessage 
            virtual std::string makeStatisticsMessage(char letter, unsigned int count) = 0;
            virtual ~IGuessStatisticsMessage()
            ;


            This would allow to provide implementations for different languages easier:



            struct GuessStatisticsMessage_EN() : public IGuessStatisticsMessage 
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const verb = (count == 1) ? "is" : "are";
            auto const number = (count == 0) ? "no" : (count == 1) ? "one" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);

            ;

            struct GuessStatisticsMessage_DE() : public IGuessStatisticsMessage
            std::string makeStatisticsMessage(char letter, unsigned int count)
            auto const number = (count == 0) ? "kein" : (count == 1) ? "ein" :
            std::to_string(count);
            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("Es gibt ''.", number, letter, plural);

            ;



          2. Also I am not a friend of nested ternary expressions, they generally tend to be hard to read. I'd rather use some code like this:



            std::string makeStatisticsMessage(char letter, unsigned int count) {
            auto const verb = (count == 1) ? "is" : "are";
            std::string number;
            if(count == 0)
            number = "no";
            else if (count == 1)
            number = "one";

            else
            number = std::to_string(count);

            auto const plural = (count == 1) ? "" : "s";
            return fmt::format("There ''.", verb, number, letter, plural);








          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jul 21 at 16:03

























          answered Jul 21 at 13:00









          πάντα ῥεῖπάντα ῥεῖ

          4,1283 gold badges14 silver badges28 bronze badges




          4,1283 gold badges14 silver badges28 bronze badges














          • $begingroup$
            Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
            $endgroup$
            – SG_90
            Jul 23 at 18:16










          • $begingroup$
            @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
            $endgroup$
            – πάντα ῥεῖ
            Jul 23 at 18:21

















          • $begingroup$
            Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
            $endgroup$
            – SG_90
            Jul 23 at 18:16










          • $begingroup$
            @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
            $endgroup$
            – πάντα ῥεῖ
            Jul 23 at 18:21
















          $begingroup$
          Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
          $endgroup$
          – SG_90
          Jul 23 at 18:16




          $begingroup$
          Thanks for the contribution. Would it make sense to go a step further by getting rid of the verb/number/plural vars altogether and returning a complete string depending on the count (having multiple return statements), or would you insist on keeping the vars?
          $endgroup$
          – SG_90
          Jul 23 at 18:16












          $begingroup$
          @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
          $endgroup$
          – πάντα ῥεῖ
          Jul 23 at 18:21





          $begingroup$
          @SG_90 The (local) variables are a minor point. Keeping a replacable interface is a major.
          $endgroup$
          – πάντα ῥεῖ
          Jul 23 at 18:21


















          draft saved

          draft discarded
















































          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%2f224603%2fmessage-formatting-code-with-pluralization-revised-to-be-more-functional%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

          Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

          Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

          Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form