conversion operator - beginner's question

Discussion in 'C++' started by subramanian100in@yahoo.com, India, Nov 29, 2007.

  1. , India

    , India Guest

    In the book, C++ Coding Standards book by Hereb Sutter and Andrei
    Alexandrescu, in Item 40 on pages 86-87 viz, "Avoid providing implicit
    conversions", the authors have advised the use of named functions that
    offer conversions instead of conversion operators.

    In page 87, example 2: Errors that work.

    class String
    {
    // ...
    public:
    operator cons char *(); // deplorable form
    };

    Assume s1, s2 are 'String's:
    int x = s1 -s2; // compiles; undefined behaviour
    const char *p = s1 - 5; // compiles; undefined behaviour
    ....

    I am NOT going against the authors in asking the following.
    However, as a beginner I just to want to know if conversion operators
    should be avoided totally ?
    Because, in <istream>, we have operator bool() const; (in the sentry
    class)

    This helps in
    while(cin)
    // ...

    So here the standard library uses a conversion operator. Are there any
    guidelines as to when the conversion operators can be defined ?

    Kindly clarify.

    I once again state that I am not confronting the authors. I am asking
    this question from learner's point of view.

    Thanks
    V.Subramanian
    , India, Nov 29, 2007
    #1
    1. Advertising

  2. On 2007-11-29 17:25, , India wrote:
    > In the book, C++ Coding Standards book by Hereb Sutter and Andrei
    > Alexandrescu, in Item 40 on pages 86-87 viz, "Avoid providing implicit
    > conversions", the authors have advised the use of named functions that
    > offer conversions instead of conversion operators.
    >
    > In page 87, example 2: Errors that work.
    >
    > class String
    > {
    > // ...
    > public:
    > operator cons char *(); // deplorable form
    > };
    >
    > Assume s1, s2 are 'String's:
    > int x = s1 -s2; // compiles; undefined behaviour
    > const char *p = s1 - 5; // compiles; undefined behaviour
    > ...
    >
    > I am NOT going against the authors in asking the following.
    > However, as a beginner I just to want to know if conversion operators
    > should be avoided totally ?


    You should never say never, there are no absolute rules. Though in most
    cases it is advisable to follow them, especially if you are a beginner.
    But if you know what you are doing then there situations where they can
    be useful.

    > Because, in <istream>, we have operator bool() const; (in the sentry
    > class)
    >
    > This helps in
    > while(cin)
    > // ...
    >
    > So here the standard library uses a conversion operator. Are there any
    > guidelines as to when the conversion operators can be defined ?
    >
    > Kindly clarify.


    One example where they might be useful is when creating proxy-objects,
    then it might have a conversion to the object-type it is acting as a
    proxy for.

    --
    Erik Wikström
    Erik Wikström, Nov 29, 2007
    #2
    1. Advertising

  3. * , India:
    > In the book, C++ Coding Standards book by Hereb Sutter and Andrei
    > Alexandrescu, in Item 40 on pages 86-87 viz, "Avoid providing implicit
    > conversions", the authors have advised the use of named functions that
    > offer conversions instead of conversion operators.
    >
    > In page 87, example 2: Errors that work.
    >
    > class String
    > {
    > // ...
    > public:
    > operator cons char *(); // deplorable form
    > };
    >
    > Assume s1, s2 are 'String's:
    > int x = s1 -s2; // compiles; undefined behaviour
    > const char *p = s1 - 5; // compiles; undefined behaviour
    > ...
    >
    > I am NOT going against the authors in asking the following.
    > However, as a beginner I just to want to know if conversion operators
    > should be avoided totally ?


    No, just avoid them as default, and think /very/ carefully before
    providing one.


    > Because, in <istream>, we have operator bool() const; (in the sentry
    > class)


    The sentry class is just a specification "implementation" detail, a
    helper abstraction used to specify the functionality. You will never
    use that operator bool() directly. Additionally, the modern templated
    standard iostreams are not an example of good design. They're an
    example of lack of design and/or bad design. Simply put, if some way of
    doing things is employed by standard iostreams, then you know that it's
    most probably something to not adopt in your own designs, that it's most
    probably something to stay very very clear of, to fear and avoid.


    > This helps in
    > while(cin)
    > // ...


    No, what's invoked here is "std::basic_ios<char>::eek:perator void*".

    That's still an example of an Evil(TM) way of doing things.

    With billions of good ways to do this, it might seem fantastic and
    unbelievable that one of the very few really Evil ways ended up in the
    standard, sort of like "we really need some more Evil, let's see...",
    but such is standardization, and ask me not why: it's a mystery.


    > So here the standard library uses a conversion operator. Are there any
    > guidelines as to when the conversion operators can be defined ?


    A conversion operator can implement a logical IsA relationship where
    inheritance isn't applicable.


    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 29, 2007
    #3
  4. , India

    , India Guest

    On Nov 29, 10:59 pm, "Alf P. Steinbach" <> wrote:
    > * , India:
    > > Because, in <istream>, we have operator bool() const; (in the sentry
    > > class)

    >
    > The sentry class is just a specification "implementation" detail, a
    > helper abstraction used to specify the functionality. You will never
    > use that operator bool() directly. Additionally, the modern templated
    > standard iostreams are not an example of good design. They're an
    > example of lack of design and/or bad design. Simply put, if some way of
    > doing things is employed by standard iostreams, then you know that it's
    > most probably something to not adopt in your own designs, that it's most
    > probably something to stay very very clear of, to fear and avoid.
    >
    > > This helps in
    > > while(cin)
    > > // ...

    >
    > No, what's invoked here is "std::basic_ios<char>::eek:perator void*".
    >
    > That's still an example of an Evil(TM) way of doing things.
    >
    > With billions of good ways to do this, it might seem fantastic and
    > unbelievable that one of the very few really Evil ways ended up in the
    > standard, sort of like "we really need some more Evil, let's see...",
    > but such is standardization, and ask me not why: it's a mystery.
    >
    > > So here the standard library uses a conversion operator. Are there any
    > > guidelines as to when the conversion operators can be defined ?

    >
    > A conversion operator can implement a logical IsA relationship where
    > inheritance isn't applicable.
    >
    > Cheers, & hth.,
    >
    > - Alf


    I found the following piece of code in C++ Primer 4th edition by
    Stanley Lippman in page 26.

    Sales_item trans;

    while (std:cin >> trans)
    // ...

    Here, isn't operator bool() called ?

    Also let me know what is the correct way of doing the 'while
    condition' if it is not a good way of doing.

    Kindly clarify.

    Thanks
    V.Subramanian
    , India, Nov 30, 2007
    #4
  5. , India

    Kai-Uwe Bux Guest

    , India wrote:

    > On Nov 29, 10:59 pm, "Alf P. Steinbach" <> wrote:
    >> * , India:
    >> > Because, in <istream>, we have operator bool() const; (in the sentry
    >> > class)

    >>
    >> The sentry class is just a specification "implementation" detail, a
    >> helper abstraction used to specify the functionality. You will never
    >> use that operator bool() directly. Additionally, the modern templated
    >> standard iostreams are not an example of good design. They're an
    >> example of lack of design and/or bad design. Simply put, if some way of
    >> doing things is employed by standard iostreams, then you know that it's
    >> most probably something to not adopt in your own designs, that it's most
    >> probably something to stay very very clear of, to fear and avoid.
    >>
    >> > This helps in
    >> > while(cin)
    >> > // ...

    >>
    >> No, what's invoked here is "std::basic_ios<char>::eek:perator void*".
    >>
    >> That's still an example of an Evil(TM) way of doing things.
    >>
    >> With billions of good ways to do this, it might seem fantastic and
    >> unbelievable that one of the very few really Evil ways ended up in the
    >> standard, sort of like "we really need some more Evil, let's see...",
    >> but such is standardization, and ask me not why: it's a mystery.
    >>
    >> > So here the standard library uses a conversion operator. Are there any
    >> > guidelines as to when the conversion operators can be defined ?

    >>
    >> A conversion operator can implement a logical IsA relationship where
    >> inheritance isn't applicable.
    >>
    >> Cheers, & hth.,
    >>
    >> - Alf

    >
    > I found the following piece of code in C++ Primer 4th edition by
    > Stanley Lippman in page 26.
    >
    > Sales_item trans;
    >
    > while (std:cin >> trans)
    > // ...
    >
    > Here, isn't operator bool() called ?


    Nope. As Alf said, the conversion involved goes to void*


    > Also let me know what is the correct way of doing the 'while
    > condition' if it is not a good way of doing.


    Given the way iostreams handle things, this is a correct way to write the
    while loop. However, that does not imply that it was a good idea to make
    the standard streams support conversion to void*.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 30, 2007
    #5
  6. , India

    James Kanze Guest

    On Nov 29, 5:25 pm, ", India"
    <> wrote:
    > In the book, C++ Coding Standards book by Hereb Sutter and Andrei
    > Alexandrescu, in Item 40 on pages 86-87 viz, "Avoid providing implicit
    > conversions", the authors have advised the use of named functions that
    > offer conversions instead of conversion operators.


    > In page 87, example 2: Errors that work.


    > class String
    > {
    > // ...
    > public:
    > operator cons char *(); // deplorable form
    > };


    > Assume s1, s2 are 'String's:
    > int x = s1 -s2; // compiles; undefined behaviour
    > const char *p = s1 - 5; // compiles; undefined behaviour
    > ...


    > I am NOT going against the authors in asking the following.
    > However, as a beginner I just to want to know if conversion operators
    > should be avoided totally ?


    Pretty much so. About the only general exception I can think of
    is proxies, which only work because of implcit conversions.

    Otherwise, there are a few special cases; as a beginner, you
    probably don't have to worry much about these, however.

    > Because, in <istream>, we have operator bool() const; (in the
    > sentry class)


    > This helps in
    > while(cin)
    > // ...


    You're mixing up two things.

    In istream and ostream, there is a nested sentry class, which
    has an implicit conversion operator to bool. It is used when
    writing << and >> operators which go directly to the streambuf
    (rather than decomposing the operation into << or >> on simpler
    types). The "standard" idiom here is:

    std::eek:stream&
    operator<<( std::eek:stream& dest, SomeType const& obj )
    {
    std::eek:stream::sentry s( dest ) ;
    if ( s ) {
    // do it...
    }
    return dest ;
    }

    Obviously, other alternatives (not involving the explicit
    conversion) are possible, but in this (special) case, it really
    doesn't matter; the class is designed to be used in one specific
    case, and only in one specific case.

    Both istream and ostream derive from ios, and ios has an
    implicit conversion to void*. This supports idioms such as:
    while ( std::cin >> someVariable ) ...
    or
    while ( std::getline( std::cin, line ) ) ...
    , the void* acting here as a bool. (The reason bool wasn't used
    was because bool is an integral type, and >> and << are defined
    over it. So in some cases, you could get some strange overload
    resolutions, rather than an error from the compiler.)

    Whether this is good design or not is very debatable; as a
    general rule, it is NOT a good idea to both modify program state
    and have flow control in a single line/statement. Something
    like:

    std::cin >> someVariable ;
    while ( std::cin.succeeded() ) {
    // ...
    std::cin >> someVariable ;
    }

    would arguably be better. Similarly, one would like to be able
    to use the stream for initialization, and not just to modify
    existing variables.

    All one can say here is that I/O, in general, is hard, and that
    iostreams works a lot better than anything else anyone has
    proposed (or what's available in other languages). And the
    idiom is ubiquious enough that it doesn't cause problems in
    practice; everyone knows it and expects it. Since that's highly
    unlikely to be the case for any class you write, you should
    probably avoid such things.

    > So here the standard library uses a conversion operator.


    The standard library does a lot of things that aren't
    necessarily good practice. (The iostream's part is probably one
    of the better parts of it.) But a standard library also obeys
    different rules than your code, at least partially. It will be
    ubiquious, and it will be well known. Which means that code
    using it idiomatically will be readable, regardless of the
    conventions. Your code won't have those advantages.

    > Are there any guidelines as to when the conversion operators
    > can be defined ?


    Yes. Except for proxies and if you're designing the standard
    library of a major language, don't. (As with all rules, there
    are exceptions. But unless it is obvious that the case must be
    an exception, it probably isn't.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Nov 30, 2007
    #6
  7. , India

    , India Guest

    On Nov 30, 3:38 pm, James Kanze <> wrote:
    >
    > Both istream and ostream derive from ios, and ios has an
    > implicit conversion to void*. This supports idioms such as:
    > while ( std::cin >> someVariable ) ...
    > or
    > while ( std::getline( std::cin, line ) ) ...
    > , the void* acting here as a bool. (The reason bool wasn't used
    > was because bool is an integral type, and >> and << are defined
    > over it. So in some cases, you could get some strange overload
    > resolutions, rather than an error from the compiler.)
    >
    > Whether this is good design or not is very debatable; as a
    > general rule, it is NOT a good idea to both modify program state
    > and have flow control in a single line/statement. Something
    > like:
    >
    > std::cin >> someVariable ;
    > while ( std::cin.succeeded() ) {
    > // ...
    > std::cin >> someVariable ;
    > }
    >
    > would arguably be better. Similarly, one would like to be able
    > to use the stream for initialization, and not just to modify
    > existing variables.
    >
    > --
    > James Kanze (GABI Software)


    I have been using
    while (cin >> obj)
    //...

    Now you have advised a solution. Kindly let me know
    which member function on 'cin' should I invoke in order to know
    whether the input operation was successful. (I tried using
    std::cin.succeeded(), but it doesn't seem to be a member function)

    Kindly clarify.

    Thanks
    V.Subramanian
    , India, Nov 30, 2007
    #7
  8. , India

    Kai-Uwe Bux Guest

    , India wrote:

    > On Nov 30, 3:38 pm, James Kanze <> wrote:
    >>
    >> Both istream and ostream derive from ios, and ios has an
    >> implicit conversion to void*. This supports idioms such as:
    >> while ( std::cin >> someVariable ) ...
    >> or
    >> while ( std::getline( std::cin, line ) ) ...
    >> , the void* acting here as a bool. (The reason bool wasn't used
    >> was because bool is an integral type, and >> and << are defined
    >> over it. So in some cases, you could get some strange overload
    >> resolutions, rather than an error from the compiler.)
    >>
    >> Whether this is good design or not is very debatable; as a
    >> general rule, it is NOT a good idea to both modify program state
    >> and have flow control in a single line/statement. Something
    >> like:
    >>
    >> std::cin >> someVariable ;
    >> while ( std::cin.succeeded() ) {
    >> // ...
    >> std::cin >> someVariable ;
    >> }
    >>
    >> would arguably be better. Similarly, one would like to be able
    >> to use the stream for initialization, and not just to modify
    >> existing variables.
    >>
    >> --
    >> James Kanze (GABI Software)

    >
    > I have been using
    > while (cin >> obj)
    > //...
    >
    > Now you have advised a solution. Kindly let me know
    > which member function on 'cin' should I invoke in order to know
    > whether the input operation was successful. (I tried using
    > std::cin.succeeded(), but it doesn't seem to be a member function)


    You are missing the point. The code example is _not_ about how you should
    use std::cin. It addresses the question how std::cin should have been
    designed to begin with. Given the actual design of std::cin, there is
    nothing wrong with

    while ( std::cin >> someVariable ) {
    ...
    }


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 30, 2007
    #8
  9. , India

    James Kanze Guest

    On Nov 30, 3:01 pm, Kai-Uwe Bux <> wrote:
    > , India wrote:
    > >> Whether this is good design or not is very debatable; as a
    > >> general rule, it is NOT a good idea to both modify program state
    > >> and have flow control in a single line/statement. Something
    > >> like:


    > >> std::cin >> someVariable ;
    > >> while ( std::cin.succeeded() ) {
    > >> // ...
    > >> std::cin >> someVariable ;
    > >> }


    > >> would arguably be better. Similarly, one would like to be able
    > >> to use the stream for initialization, and not just to modify
    > >> existing variables.


    > > I have been using
    > > while (cin >> obj)
    > > //...


    > > Now you have advised a solution. Kindly let me know
    > > which member function on 'cin' should I invoke in order to know
    > > whether the input operation was successful. (I tried using
    > > std::cin.succeeded(), but it doesn't seem to be a member function)


    > You are missing the point. The code example is _not_ about how
    > you should use std::cin.


    Could have been designed, not should. As I pointed out, I/O in
    general is very hard to do elegantly. The solution in iostream
    is a compromise. If you want to do something like the above,
    you can:

    std::cin >> someVariable ;
    while ( ! std::cin.fail() ) {
    // ...
    std::cin >> someVariable ;
    }

    > It addresses the question how std::cin should have been
    > designed to begin with. Given the actual design of std::cin,
    > there is nothing wrong with


    > while ( std::cin >> someVariable ) {
    > ...
    > }


    Above and beyond the design of iostream, and what one can and
    cannot do: the above is the standard, idiomatic, idiom. Which
    means that anything else causes the reader to ask: why?
    Whatever other qualities or defects the idiom might have, that
    one reason means that you should not deviate from it without
    some very good reason.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Nov 30, 2007
    #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. =?Utf-8?B?S3VydCBTY2hyb2VkZXI=?=

    No Class at ALL!!! beginner/beginner question

    =?Utf-8?B?S3VydCBTY2hyb2VkZXI=?=, Feb 2, 2005, in forum: ASP .Net
    Replies:
    7
    Views:
    570
    =?Utf-8?B?S3VydCBTY2hyb2VkZXI=?=
    Feb 3, 2005
  2. Arvid Requate
    Replies:
    2
    Views:
    980
    Alf P. Steinbach
    Jun 23, 2006
  3. hurcan solter
    Replies:
    3
    Views:
    723
    Cholo Lennon
    Aug 29, 2007
  4. , India
    Replies:
    2
    Views:
    456
    Fraser Ross
    Sep 15, 2009
  5. cronusf
    Replies:
    12
    Views:
    483
Loading...

Share This Page