[Design] Should accessors throw exception ?

Discussion in 'C++' started by mathieu, Sep 12, 2008.

  1. mathieu

    mathieu Guest

    Hi there,

    I'd like to know if there is a general answer to the following
    question: when making a public interface that access a container
    should the function throw an exception when the element is not found ?
    Otherwise I need two functions: a Find and a Get function which put
    the burden on the application programmer to always call Find before
    Get.
    The other alternative would be to return some kind of sentinel (like
    std::set<>::end() )...

    Comments ?

    Thanks
    -Mathieu

    eg.


    #include <map>
    #include <string.h>

    struct Phone { int P; };
    struct Name { const char *N;
    bool operator <(Name const &n) const { return strcmp(N,n.N) < 0; }
    };
    struct YellowPage
    {
    void Insert(Name const &n,Phone const &p)
    { I.insert( std::map<Name,Phone>::value_type(n,p) ); }
    bool Find(Name const & n) { return I.find(n) != I.end(); }
    Phone const &Get(Name const&n) { return I.find(n)->second; }
    private:
    std::map<Name,Phone> I;
    };
    mathieu, Sep 12, 2008
    #1
    1. Advertising

  2. mathieu

    Ron AF Greve Guest

    Hi,

    I think returning a special value like end() or 0 for a pointer is the best
    solution.

    I think exception should only be used when something exceptional occurs, for
    instance you expect a conifiguration file is there yet when you try to open
    it it is missing or you try to access a database but the DBA took it down
    for maintenance. This way you (or the user of your library) can catch those
    thiings somewhere 'high up' in the code knowing that everything in between
    is released and handled nicely and continue (maybe waiting a few minutes and
    try again.

    And indeed a find/get combination is more work. Also with the end() you make
    it work the same as the STL.

    Regards, Ron AF Greve

    http://www.InformationSuperHighway.eu

    "mathieu" <> wrote in message
    news:...
    > Hi there,
    >
    > I'd like to know if there is a general answer to the following
    > question: when making a public interface that access a container
    > should the function throw an exception when the element is not found ?
    > Otherwise I need two functions: a Find and a Get function which put
    > the burden on the application programmer to always call Find before
    > Get.
    > The other alternative would be to return some kind of sentinel (like
    > std::set<>::end() )...
    >
    > Comments ?
    >
    > Thanks
    > -Mathieu
    >
    > eg.
    >
    >
    > #include <map>
    > #include <string.h>
    >
    > struct Phone { int P; };
    > struct Name { const char *N;
    > bool operator <(Name const &n) const { return strcmp(N,n.N) < 0; }
    > };
    > struct YellowPage
    > {
    > void Insert(Name const &n,Phone const &p)
    > { I.insert( std::map<Name,Phone>::value_type(n,p) ); }
    > bool Find(Name const & n) { return I.find(n) != I.end(); }
    > Phone const &Get(Name const&n) { return I.find(n)->second; }
    > private:
    > std::map<Name,Phone> I;
    > };
    Ron AF Greve, Sep 12, 2008
    #2
    1. Advertising

  3. mathieu

    Ian Collins Guest

    mathieu wrote:
    > Hi there,
    >
    > I'd like to know if there is a general answer to the following
    > question: when making a public interface that access a container
    > should the function throw an exception when the element is not found ?
    > Otherwise I need two functions: a Find and a Get function which put
    > the burden on the application programmer to always call Find before
    > Get.


    I tend to favour returning NULL if the return type is a pointer and
    throwing an exception if the return type is a reference or an object
    without an obvious bad value.

    --
    Ian Collins.
    Ian Collins, Sep 12, 2008
    #3
  4. mathieu

    James Kanze Guest

    Re: Should accessors throw exception ?

    On Sep 12, 11:07 pm, mathieu <> wrote:

    > I'd like to know if there is a general answer to the following
    > question: when making a public interface that access a
    > container should the function throw an exception when the
    > element is not found ? Otherwise I need two functions: a Find
    > and a Get function which put the burden on the application
    > programmer to always call Find before Get.


    It depends on the application. I used two different solutions
    in my pre-standard AssocArray (a hash table): the operator[] had
    a pre-condition that the element was present, and asserted this
    precondition, but there was a get function which returned a
    pointer to the element, and returned a null pointer if the
    element wasn't found. In other contexts, I've found the
    behavior of std::map<>::eek:perator[] to be useful as well: just
    insert the missing element. On the other hand, I can't think of
    a context where throwing an exception would be the desired
    behavior.

    > The other alternative would be to return some kind of sentinel
    > (like std::set<>::end() )...


    Just return a pointer to the element, rather than a reference,
    and you have a sentinel value defined by the standard, the null
    pointer.

    --
    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, Sep 13, 2008
    #4
  5. mathieu

    James Kanze Guest

    Re: Should accessors throw exception ?

    On Sep 13, 12:55 am, Ian Collins <> wrote:
    > mathieu wrote:


    > > I'd like to know if there is a general answer to the
    > > following question: when making a public interface that
    > > access a container should the function throw an exception
    > > when the element is not found ? Otherwise I need two
    > > functions: a Find and a Get function which put the burden on
    > > the application programmer to always call Find before Get.


    > I tend to favour returning NULL if the return type is a
    > pointer and throwing an exception if the return type is a
    > reference or an object without an obvious bad value.


    Isn't this inversing cause and effect. I tend to choose to
    return a pointer if I need a sentinel value, and a reference
    otherwise.

    --
    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, Sep 13, 2008
    #5
  6. mathieu

    Ian Collins Guest

    Re: Should accessors throw exception ?

    James Kanze wrote:
    > On Sep 13, 12:55 am, Ian Collins <> wrote:
    >> mathieu wrote:

    >
    >>> I'd like to know if there is a general answer to the
    >>> following question: when making a public interface that
    >>> access a container should the function throw an exception
    >>> when the element is not found ? Otherwise I need two
    >>> functions: a Find and a Get function which put the burden on
    >>> the application programmer to always call Find before Get.

    >
    >> I tend to favour returning NULL if the return type is a
    >> pointer and throwing an exception if the return type is a
    >> reference or an object without an obvious bad value.

    >
    > Isn't this inversing cause and effect. I tend to choose to
    > return a pointer if I need a sentinel value, and a reference
    > otherwise.
    >

    Not really, consider dynamic_cast. I think you have given the same
    answer I did in a different way. NULL is a sentinel value.

    --
    Ian Collins.
    Ian Collins, Sep 13, 2008
    #6
  7. mathieu

    James Kanze Guest

    Re: Should accessors throw exception ?

    On Sep 13, 3:45 am, Ian Collins <> wrote:
    > James Kanze wrote:
    > > On Sep 13, 12:55 am, Ian Collins <> wrote:
    > >> mathieu wrote:


    > >>> I'd like to know if there is a general answer to the
    > >>> following question: when making a public interface that
    > >>> access a container should the function throw an exception
    > >>> when the element is not found ? Otherwise I need two
    > >>> functions: a Find and a Get function which put the burden
    > >>> on the application programmer to always call Find before
    > >>> Get.


    > >> I tend to favour returning NULL if the return type is a
    > >> pointer and throwing an exception if the return type is a
    > >> reference or an object without an obvious bad value.


    > > Isn't this inversing cause and effect. I tend to choose to
    > > return a pointer if I need a sentinel value, and a reference
    > > otherwise.


    > Not really, consider dynamic_cast. I think you have given the same
    > answer I did in a different way.


    Partially, but you seemed to be saying that you chose the means
    of reporting errors according to the return value, where as I
    would choose the type of the return value according to whether I
    needed to report errors or not. (Supposing there is a choice,
    of course. For constructors and overloaded operators, you often
    don't have any choice but to throw an exception in case of
    error.)

    > NULL is a sentinel value.


    Which is why I choose to return a pointer if I need a sentinal
    value. (In cases where I don't actually have something to
    point to, for example if the function returns a calculated
    value, I will use Fallible.)

    --
    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, Sep 13, 2008
    #7
  8. Re: Should accessors throw exception ?

    James Kanze wrote:
    > Which is why I choose to return a pointer if I need a sentinal
    > value. (In cases where I don't actually have something to
    > point to, for example if the function returns a calculated
    > value, I will use Fallible.)


    Do you have particular reasons to avoid Fallible references?

    --
    Gennaro Prota | name.surname yahoo.com
    Breeze C++ (preview): <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
    Gennaro Prota, Sep 13, 2008
    #8
  9. mathieu

    James Kanze Guest

    Re: Should accessors throw exception ?

    On Sep 14, 3:48 pm, (blargg) wrote:
    > In article <Xns9B18DCFE7997Fnobodyeb...@216.196.97.131>, Paavo
    > Helde<> wrote:


    > [...]


    > > One design I have found handy:


    > > T GetByName(const std::string name) const; // throws if name not found
    > > T GetByName(const std::string name, T defaultvalue) const; // returns
    > > defaultvalue if name not found


    > > So the client code has the option to choose if it wants a
    > > hard or soft fallback.


    > Nifty pattern, but wouldn't it tend to expand the interface
    > and bloat implementation if there were lots of functions like
    > this?


    How many getters do you have in one class? In cases where you
    systematically have something like this (e.g. data base access,
    with null values in some columns), you would, of course, use a
    class to represent nullable values; the above function would be
    in that class, and the class representing a row would simply
    return instances of that class.

    > I'd think returning something like boost::eek:ptional<T> that
    > throws when attempting to dereference when empty would be
    > best:


    > template<typename T>
    > checked_optional {
    > T t;
    > bool exists;
    > public:
    > checked_optional() : exists( false ) { }
    > checked_optional( T t ) : t( t ), exists( true ) { }
    > operator bool () const { return exists; }
    > T& operator * () const
    > {
    > if ( !exists )
    > throw "Bla bla";
    > return t;
    > }
    > };


    > checked_optional<T> GetByName( std::string name );


    > void use_t( T );


    > // Just dereference result if you want exception
    > use_t( *GetByName( "foo" ) );


    But that doesn't solve the problem. At the client level, if you
    want a default value, you have to declare an instance of a
    variable, then test it. The whole point is to be able to
    combine everything into a simple functional expression. (Also,
    the use of implicit conversion to bool is blatant overload
    abuse. If you want to check for validity, provide an isValid()
    function.)

    > // Check the result before dereferencing if you want to handle not found
    > checked_optional<T> t = GetByName( "foo" );
    > if ( t )
    > use_t( *t );
    > else
    > not_found();


    Wordy and obfuscated. And the interesting example would call
    use_t with a default value if the value wasn't found, e.g.:

    use_t( container.get( key ).elseDefaultTo( defaultValue ) ) ;

    --
    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, Sep 14, 2008
    #9
  10. mathieu

    James Kanze Guest

    Re: Should accessors throw exception ?

    On Sep 13, 6:28 pm, Gennaro Prota <gennaro/> wrote:
    > James Kanze wrote:
    > > Which is why I choose to return a pointer if I need a sentinal
    > > value. (In cases where I don't actually have something to
    > > point to, for example if the function returns a calculated
    > > value, I will use Fallible.)


    > Do you have particular reasons to avoid Fallible references?


    Well, the original implementation of Fallible required that the
    instantiation type be default constructable, so you couldn't
    instantiate it with a reference. At the time, I considered
    removing this limit, precisely in order to support references.
    I decided against it on the grounds that the standard already
    defined a Fallible for references---it's called a pointer.

    I recently did modify my Fallible to support types without
    default constructors. But that was because I needed it for an
    actual class type which didn't have a default constructor. The
    alternative would have been to add a default constructor to the
    class, which would have required adding a zombie state to the
    class. And which, of course, would have only solved the problem
    in this one particular case, and not generally.

    --
    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, Sep 14, 2008
    #10
  11. Re: Should accessors throw exception ?

    James Kanze wrote:
    > On Sep 13, 6:28 pm, Gennaro Prota <gennaro/> wrote:
    >> James Kanze wrote:
    >>> Which is why I choose to return a pointer if I need a sentinal
    >>> value. (In cases where I don't actually have something to
    >>> point to, for example if the function returns a calculated
    >>> value, I will use Fallible.)

    >
    >> Do you have particular reasons to avoid Fallible references?

    >
    > Well, the original implementation of Fallible required that the
    > instantiation type be default constructable, so you couldn't
    > instantiate it with a reference. At the time, I considered
    > removing this limit, precisely in order to support references.
    > I decided against it on the grounds that the standard already
    > defined a Fallible for references---it's called a pointer.


    Yes, that answers my question. Compared to a pointer, of course,
    Fallible<> also provides a check (which may be or not what you want, but
    is a feature :)).

    FWIW, my implementation of Fallible allows references, because it holds
    the T indirectly, via a holder< T > which is specialized for reference
    types, but I haven't had so far a concrete chance to use them. This was
    part of the reason for my question.

    > I recently did modify my Fallible to support types without
    > default constructors. But that was because I needed it for an
    > actual class type which didn't have a default constructor. The
    > alternative would have been to add a default constructor to the
    > class, which would have required adding a zombie state to the
    > class. And which, of course, would have only solved the problem
    > in this one particular case, and not generally.


    Yes, that certainly makes sense. I've encountered the same issue and,
    for the moment, I just did without Fallible, as I'm right in the middle
    of other interesting stuff :)

    --
    Gennaro Prota | name.surname yahoo.com
    Breeze C++ (preview): <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
    Gennaro Prota, Sep 14, 2008
    #11
  12. mathieu

    James Kanze Guest

    Re: Should accessors throw exception ?

    On Sep 14, 8:07 pm, Gennaro Prota <gennaro/> wrote:
    > James Kanze wrote:
    > > On Sep 13, 6:28 pm, Gennaro Prota <gennaro/> wrote:
    > >> James Kanze wrote:
    > >>> Which is why I choose to return a pointer if I need a sentinal
    > >>> value. (In cases where I don't actually have something to
    > >>> point to, for example if the function returns a calculated
    > >>> value, I will use Fallible.)


    > >> Do you have particular reasons to avoid Fallible references?


    > > Well, the original implementation of Fallible required that the
    > > instantiation type be default constructable, so you couldn't
    > > instantiate it with a reference. At the time, I considered
    > > removing this limit, precisely in order to support references.
    > > I decided against it on the grounds that the standard already
    > > defined a Fallible for references---it's called a pointer.


    > Yes, that answers my question. Compared to a pointer, of
    > course, Fallible<> also provides a check (which may be or not
    > what you want, but is a feature :)).


    It provides an earlier check, but on all of the implementations
    I use, dereferencing a null pointer causes a core dump, exactly
    like using the value of Fallible<> when it's not valid. (Well,
    almost exactly: the check for accessing through a null pointer
    has no runtime cost, and cannot be disabled; the check for using
    an invalid Fallible<> is an assertion.)

    > FWIW, my implementation of Fallible allows references, because
    > it holds the T indirectly, via a holder< T > which is
    > specialized for reference types, but I haven't had so far a
    > concrete chance to use them. This was part of the reason for
    > my question.


    Well, I'd still use a pointer rather than a Fallible reference,
    simply because it is standard. On the other hand, as I said, I
    did need a Fallible once for a class which didn't have a
    reasonable default constructor. I don't have any Holder<>
    class; I just implemented the usual separation of allocation and
    initialization directly in Fallible<> (using an unsigned char[]
    in the Fallible<> for allocation).

    --
    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, Sep 15, 2008
    #12
    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. Kerri
    Replies:
    2
    Views:
    12,996
    Kevin Spencer
    Oct 27, 2003
  2. Replies:
    15
    Views:
    7,487
    Roedy Green
    Sep 8, 2005
  3. Ben Pope
    Replies:
    8
    Views:
    357
    Martin Eisenberg
    Jul 26, 2005
  4. Clodoaldo
    Replies:
    4
    Views:
    261
    Jarek Zgoda
    Mar 25, 2008
  5. Emanuele D'Arrigo

    To throw or to throw not?

    Emanuele D'Arrigo, Nov 14, 2008, in forum: Python
    Replies:
    6
    Views:
    310
    Emanuele D'Arrigo
    Nov 15, 2008
Loading...

Share This Page