Message-formatting code with pluralization, revised to be more functionalTrying to find a good design for reading in values of different types from a fileFormatting 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 checksumGeneric Skip list implementation in C++ Version 3Object-oriented calculatorComputing the first n primes: an example from Clean Code revised for C++

Is 10/2 cable appropriate for a 240V, 30A garage heater outlet?

What's an "add" chord?

How to get the address of a C++ lambda function within the lambda itself?

Google just EOLed the original Pixel. How long until it's a brick?

What is the "opposite" of a random variable?

Why are Democrats mostly focused on increasing healthcare spending, rarely mentioning any proposals for decreasing the costs of healthcare services?

Decision problems for which it is unknown whether they are decidable

Is it sportsmanlike to waste opponents' time by giving check at the end of the game?

Dissecting the exotic bulbfish

Speaking German abroad and feeling condescended to when people speak English back to me

How does sudo handle $HOME differently since 19.10?

Find constant that allows an integral to be finite

Can using the BULK API to perform SOQL queries save on total number of queries?

Can a Scourge Aasimar fly?

What happened to Sophie in her last encounter with Arthur?

What are these criss-cross patterns close to Cambridge Airport (UK)?

At what point in time would humans notice a 21st century satellite observing them?

Physical interpretation of complex numbers

how to make a twisted wrapper

50% portfolio in single stock, JPM - appropriate for 80 year old?

Can we rotate symbols in LaTeX? How should we make this diagram?

Multivariate Limits

Find the Longest Even Length Word

Would nuclear bombs be effective against clouds of nanites?



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 fileFormatting 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 checksumGeneric Skip list implementation in C++ Version 3Object-oriented calculatorComputing the first n primes: an example from Clean Code revised for C++






.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

      136k21 gold badges175 silver badges448 bronze badges




      136k21 gold badges175 silver badges448 bronze badges










      asked Jul 21 at 9:48









      SG_90SG_90

      936 bronze badges




      936 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/4.0/"u003ecc by-sa 4.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

          5,6191 gold badge15 silver badges40 bronze badges




          5,6191 gold badge15 silver badges40 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,3563 gold badges15 silver badges28 bronze badges




          4,3563 gold badges15 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

          Tamil (spriik) Luke uk diar | Nawigatjuun

          Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

          Where does the image of a data connector as a sharp metal spike originate from?Where does the concept of infected people turning into zombies only after death originate from?Where does the motif of a reanimated human head originate?Where did the notion that Dragons could speak originate?Where does the archetypal image of the 'Grey' alien come from?Where did the suffix '-Man' originate?Where does the notion of being injured or killed by an illusion originate?Where did the term “sophont” originate?Where does the trope of magic spells being driven by advanced technology originate from?Where did the term “the living impaired” originate?