Is it good practice for a function to return data?

Discussion in 'C++' started by zalzon, Aug 23, 2004.

  1. zalzon

    zalzon Guest

    Is it good practice in C++ for a member function to return data or is
    it better that data is stored in private member variable and printed
    in the member function?

    should i be using

    int function1()
    {
    ....
    return i
    }

    and then call it from main()

    main()
    {
    int i = function1();
    printf("Value of i is %d", i);
    }


    or

    function()
    {
    ....
    printf("Value of i is %d", i);
    }
     
    zalzon, Aug 23, 2004
    #1
    1. Advertising

  2. zalzon wrote:

    > Is it good practice in C++ for a member function to return data
    > or is it better that data is stored in private member variable
    > and printed in the member function?
    >
    > Should I be using
    >
    > int function1(void) {
    > ....
    > return i;
    > }
    >
    > and then call it from main()
    >
    > int main(int argc, char* argv[]) {
    > int i = function1();
    > printf("Value of i is %d", i);

    return 0;
    > }
    >
    > or
    >
    > void function(void) {
    > ....
    > printf("Value of i is %d", i);
    > }


    You should try to avoid "side effects" --
    input and output are side effects.
    They change the state of the program.
    In C++ you should write:

    std::cout << "Value of i is " << i;
     
    E. Robert Tisdale, Aug 23, 2004
    #2
    1. Advertising

  3. zalzon

    Daniel T. Guest

    zalzon <> wrote:

    > Is it good practice in C++ for a member function to return data or is
    > it better that data is stored in private member variable and printed
    > in the member function?
    >
    > should i be using
    >
    > int function1()
    > {
    > ....
    > return i
    > }
    >
    > and then call it from main()
    >
    > main()
    > {
    > int i = function1();
    > printf("Value of i is %d", i);
    > }
    >
    >
    > or
    >
    > function()
    > {
    > ....
    > printf("Value of i is %d", i);
    > }


    In this spicific example, I would say that the first (function1) would
    be the better choice. It can be used to output the value of 'i' (as
    shown) and it can be used in contexts where the value isn't usposed to
    be output.
     
    Daniel T., Aug 23, 2004
    #3
  4. "zalzon" <> wrote in message
    news:...
    > Is it good practice in C++ for a member function to return data or is
    > it better that data is stored in private member variable and printed
    > in the member function?
    >
    > should i be using
    >
    > int function1()
    > {
    > ....
    > return i
    > }
    >
    > and then call it from main()
    >
    > main()
    > {
    > int i = function1();
    > printf("Value of i is %d", i);
    > }
    >
    >
    > or
    >
    > function()
    > {
    > ....
    > printf("Value of i is %d", i);
    > }


    Its almost always bad practice to print data from member functions,
    generally
    clients of the class want just to get the value, not print it out - which in
    a realworld
    program would be unwanted both because of the volume and the lack of
    context.
    What's more the data might not might not even be seen on STDOUT.
    If your data is just simple types like int, char, etc,
    the client can easily generate his own output functions, if the data is a
    more complex
    type is usually a good idea to provide (friend) formating function which
    works with the
    base output stream class - in this way the client can format output in many
    differnet forms,
    on the output or in a memory stream to produce his own output.

    dave
     
    Dave Townsend, Aug 23, 2004
    #4
  5. zalzon

    Jerry Coffin Guest

    zalzon <> wrote in message news:<>...
    > Is it good practice in C++ for a member function to return data or is
    > it better that data is stored in private member variable and printed
    > in the member function?


    That depends.

    > should i be using
    >
    > int function1()
    > {
    > ....
    > return i
    > }
    >
    > and then call it from main()
    >
    > main()
    > {
    > int i = function1();
    > printf("Value of i is %d", i);
    > }


    First of all, using printf in C++ is rarely a good idea.

    > or
    >
    > function()
    > {
    > ....
    > printf("Value of i is %d", i);
    > }


    IMO, it's perfectly reasonable for a class to overload the insertion
    and/or extraction operators to do I/O on complete objects. One common
    (and useful) idiom for that is to have a virtual member function to do
    the I/O, and have it invoked from a global overload of operator<< or
    operator>>, as applicable. In that case, a member function doing I/O
    makes perfect sense.

    OTOH, if your member function's basic idea is to produce a value
    (which you happen to be printing out at the moment) then having it do
    the I/O as well probably isn't such a great idea.

    There are a couple more possibilities. One is to put the computation
    (or whatever) into a base class that also has a (possibly pure)
    virtual function that handles processing the output. Then a derived
    class can specify how the output will be processed by overloading that
    virtual function.

    A similar possibility is to pass a parameter that specifies how to
    process the output -- one way is to pass a pointer to a function to be
    invoked on the output (this more or less matches the version above
    with virtual functions). Another is to use an iterator, and write the
    output to the iterator. In this case, you can easily put the output
    into something like a collection, or you can pass a
    std::eek:stream_iterator, which will write the data to a stream.

    Choosing between these isn't necessarily easy. One of the basic
    precepts, however, is that a function should generally do one thing,
    so you should usually think about what the function does and act
    accordingly. If the function's intent is "print out X" then doing the
    I/O probably makes sense. If its intent is "compute X" then it almost
    certainly should NOT print it out. If its intent is to produce a
    (perhaps large) number of X, then one of the final versions (e.g.
    virtual function or iterator) may make the most sense.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Aug 23, 2004
    #5
  6. zalzon

    Jerry Coffin Guest

    "E. Robert Tisdale" <> wrote in message news:<cgbbic$fjk$>...

    [ ... ]

    > You should try to avoid "side effects" --
    > input and output are side effects.


    So you think programs should avoid doing input and output? Assignment
    is also a side-effect, so you apparently think that should be avoided
    as well.

    That's certainly possible -- in fact, people have been doing it in
    Lisp, ML, and a number of other functional languages for years. I
    don't see C++ as being particularly well-suited to this style of
    programming though...

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Aug 23, 2004
    #6
  7. Jerry Coffin wrote:

    > E. Robert Tisdale wrote:
    >
    > [ ... ]
    >
    >>You should try to avoid "side effects" --
    >>input and output are side effects.

    >
    > So you think programs should avoid doing input and output?
    > Assignment is also a side-effect,
    > so you apparently think that should be avoided as well.


    Yes!

    > That's certainly possible --
    > in fact, people have been doing it
    > in Lisp, ML, and a number of other functional languages for years.
    > I don't see C++ as being particularly well-suited
    > to this style of programming though...


    C++ *is* well-suited to this programming style --
    it just isn't anal about it.
     
    E. Robert Tisdale, Aug 23, 2004
    #7
  8. zalzon

    ma740988 Guest

    (Jerry Coffin) wrote in message

    [...]

    > IMO, it's perfectly reasonable for a class to overload the insertion
    > and/or extraction operators to do I/O on complete objects. One common
    > (and useful) idiom for that is to have a virtual member function to do
    > the I/O, and have it invoked from a global overload of operator<< or
    > operator>>, as applicable. In that case, a member function doing I/O
    > makes perfect sense.


    I believe I'm following you here so if I were to re-write the above
    statement in terms of source code:

    class X
    {
    int Jdx;
    friend std::eek:stream& operator << (std::eek:stream& os, X const& x);
    public:
    virtual void std::eek:stream& Print ( ostream& os ) { os << Jdx; }
    }

    friend std::eek:stream& operator << (std::eek:stream& os, X const& x)
    {
    return x.Print(os);
    }

    So far so good?

    Now heres where this approach gets interesting from the perspective of
    an apprentice. For the purposes of discussion, assume class X has 10
    member data, three of which is - say - line of sight positions with
    units direction cosines.
    Occassionally I'm interested in outputting all 10 member data.
    Similarily, there are times when I'm interested in outputting only the
    line of sight positions.

    Perhaps irrelevant, but lets also assume the environment allows one
    the opportunity to type in the name of a function and pass parameters
    to function calls. Upon doing that the function executes. In any
    event, how do you approach the print function?

    >
    > OTOH, if your member function's basic idea is to produce a value
    > (which you happen to be printing out at the moment) then having it do
    > the I/O as well probably isn't such a great idea.
    >
    > There are a couple more possibilities. One is to put the computation
    > (or whatever) into a base class that also has a (possibly pure)
    > virtual function that handles processing the output. Then a derived
    > class can specify how the output will be processed by overloading that
    > virtual function.

    For instance?

    > A similar possibility is to pass a parameter that specifies how to
    > process the output -- one way is to pass a pointer to a function to be
    > invoked on the output (this more or less matches the version above
    > with virtual functions). Another is to use an iterator, and write the
    > output to the iterator. In this case, you can easily put the output
    > into something like a collection, or you can pass a
    > std::eek:stream_iterator, which will write the data to a stream.


    This sounds like
    vector<int> Vec(5);
    copy (Vec.begin(), Vec.end(), ostream_iterator<int>(cout, ' '));

    Yes/No?

    Now how would you map said approach to a class X?

    > Choosing between these isn't necessarily easy.


    Agreed. There are times when one's faced with multiple classes and a
    need to instrument data. Your first option is straightforward in the
    sense that each class could maintain their own print function. A
    while back I overheard a professor discussing the creation of an
    'instrumentation' class which supports the concept of plug-in. In
    essence, you'd plug-in (assuming I understand the prof) the
    instrumentation class into class X and sure enough/somehow your data
    will be extracted for you. That's a novel idea and sounds suprisingly
    efficient. Truth is, the idea is incomprehensible/makes no sense to
    me.
     
    ma740988, Aug 24, 2004
    #8
  9. zalzon

    Jerry Coffin Guest

    (ma740988) wrote in message news:<>...

    [ ... ]

    > class X
    > {
    > int Jdx;
    > friend std::eek:stream& operator << (std::eek:stream& os, X const& x);
    > public:
    > virtual void std::eek:stream& Print ( ostream& os ) { os << Jdx; }
    > }
    >
    > friend std::eek:stream& operator << (std::eek:stream& os, X const& x)
    > {
    > return x.Print(os);
    > }
    >
    > So far so good?


    Yup, reasonable so far -- though this only makes sense if X is going
    to (at least potentially) be a base class, in which case its dtor
    should usually be virtual as well.

    > Now heres where this approach gets interesting from the perspective of
    > an apprentice. For the purposes of discussion, assume class X has 10
    > member data, three of which is - say - line of sight positions with
    > units direction cosines.
    > Occassionally I'm interested in outputting all 10 member data.
    > Similarily, there are times when I'm interested in outputting only the
    > line of sight positions.


    You have a couple of possibilities here. One would be to have the
    class' output function write out all the data, and then have a
    function to return the LOS data, which can be written out separately.

    Another would be for the LOS data to be stored in a separate class of
    its own, and have an instance of that class in the other class.
    Without knowing more about what you're doing with it, it's hard to
    guess whether that's a good idea though.

    Yet another distinctly different possibility would be to create a
    manipulator that defines HOW the item will be written out. In a few
    cases this can make a lot of sense, but in many other cases it can be
    a pretty awful kludge.

    [ ... ]

    > > There are a couple more possibilities. One is to put the computation
    > > (or whatever) into a base class that also has a (possibly pure)
    > > virtual function that handles processing the output. Then a derived
    > > class can specify how the output will be processed by overloading that
    > > virtual function.

    > For instance?


    Here's a class I wrote a long time ago to process all the files in a
    specified directory tree (that fit a specified mask). The base class
    (Search) finds the applicable files. The derived class I've included
    simply prints out the full path to each file that was found. Another
    derived class might process a file by deleting it, doing a backup on
    it, encrypting it, or whatever.

    class Search {
    // Automates searching a directory (and optionally its subdirectories)
    // for a file then processing the file as specified in a derived
    class.
    //
    char *mask_;
    char oldpath[FILENAME_MAX];
    int doSubdirs_;

    public:

    // The actual processing to be done on files that are found MUST be
    // specified in the derived class.
    //
    virtual void process(FileEntry *)=0;

    void doSearch() {
    // The real guts of Search - carries out the actual search.
    FileEntry *entry_;

    // First look for files in the current directory fitting the
    // filename pattern.
    //
    for (
    entry_ = new FileEntry(mask_);
    entry_->found();
    entry_->next() )
    {
    process(entry_);
    }
    delete entry_;

    // Then look for directories in the current directory. These
    // names do NOT have to fit the filename string.
    //
    for (
    entry_ = new FileEntry("*");
    entry_->found();
    entry_->next()
    ) {
    if ( entry_->isSubdir()) {
    SetCurrentDirectory(entry_->name());
    doSearch();
    SetCurrentDirectory("..");
    }
    }
    delete entry_;
    }

    Search(char *mask, int recursive = 1)
    : mask_(mask), doSubdirs_(recursive)
    { // Save original directory before starting.
    GetCurrentDirectory(FILENAME_MAX, oldpath);
    }

    ~Search() {
    // And restore the original directory when we're done.
    SetCurrentDirectory(oldpath);
    }
    };

    class Whereis : public Search {

    public:

    Whereis( char *mask, int recursive = 1)
    // By default, a whereis is recursive.
    : Search(mask, recursive)
    {}

    void process(FileEntry *entry ) {
    char current[FILENAME_MAX];

    GetCurrentDirectory(sizeof(current), current);
    // A whereis processes a file by simply printing it out.
    std::cout << current << "\\" << *entry << std::endl;
    }
    };

    [ ... ]

    > This sounds like
    > vector<int> Vec(5);
    > copy (Vec.begin(), Vec.end(), ostream_iterator<int>(cout, ' '));
    >
    > Yes/No?


    Sort of, but not really. This is simply taking some existing data and
    copying it to another place. I was thinking more along the lines of
    something that creates the data, but deposits the output where the
    iterator directs it to.

    > Now how would you map said approach to a class X?


    Given what you've described, I probably wouldn't. :)

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Aug 25, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Greenhorn
    Replies:
    15
    Views:
    827
    Keith Thompson
    Mar 6, 2005
  2. vlsidesign
    Replies:
    26
    Views:
    985
    Keith Thompson
    Jan 2, 2007
  3. SM
    Replies:
    9
    Views:
    507
  4. /dev/phaeton
    Replies:
    16
    Views:
    699
    James Kuyper
    Feb 15, 2012
  5. dspfun
    Replies:
    52
    Views:
    212
    Malcolm McLean
    May 27, 2014
Loading...

Share This Page