Suggestion

Discussion in 'C++' started by Eivind Grimsby Haarr, Sep 6, 2004.

  1. When using polymorphism in a big system, I have sometimes come across
    problems when changing the signature of the function in the base class,
    and forgetting to change the signature of the derived functions
    accordingly. (Most often when only some of the derived classes redefine
    it.) Accessing the objects with base class pointers, the version in the
    base class is called, which is not what I wanted. This is most often very
    difficult to detect.

    This has made me come up with an idea for a compiler/language feature that
    would fix this problem: A keyword in front of the derived function that
    says that this function is derived from a base class, and the compiler
    should issue an error if a function with a similar signature doesn't
    exist in one of the base classes.

    What do you think about this idea? Is it just too much pain for a rare
    problem?

    Maybe anyone have other ideas on how to prevent such problems? Using
    macros to declare the signatures is of course one idea, but true
    C++-programmers don't like macros, right? (Perfect design and
    programming from the beginning would prevent it, of course, but even
    programmers are humans...)

    Naming the keyword 'isderived', I'll illustrate my idea with an example:

    Function f(double) is performing some calculation. In the base class B, a
    default calculation is provided, but a few of the many classes that derive
    from B has their own implementation.

    -------

    class B {
    virtual double f(double i) {...} // Uups! Forgot to declare 'const'
    }

    class OneOfManyDerivedClasses : public B {
    isderived double f(double i) {...} // Should be derived from base class
    }

    vector<B*> v;
    ....
    // Fill the vector with objects of different derived classes
    ....
    int sum = 0;
    for (it = v.begin(); it != v.end(); ++it) {
    sum+=(*v)->f(number);
    }

    ------

    If I later change the base class function to const, the function in the
    derived class will not be called when iterating through the vector. If
    this calculation is part of a complex calculation with many classes, this
    is difficult to detect. With the 'isderived' keyword, a compiler error
    would be issued, and the problem prevented.


    Any views?


    Mvh
    Eivind Grimsby Haarr

    [ 97 07 66 58 / ]
    Eivind Grimsby Haarr, Sep 6, 2004
    #1
    1. Advertising

  2. Eivind Grimsby Haarr

    Phlip Guest

    Eivind Grimsby Haarr wrote:
    >
    > When using polymorphism in a big system, I have sometimes come across
    > problems when changing the signature of the function in the base class,
    > and forgetting to change the signature of the derived functions
    > accordingly. (Most often when only some of the derived classes redefine
    > it.) Accessing the objects with base class pointers, the version in the
    > base class is called, which is not what I wanted. This is most often very
    > difficult to detect.
    >
    > This has made me come up with an idea for a compiler/language feature that
    > would fix this problem:


    Wouldn't that mistake break all the unit tests that depended on the base
    class polymorphing into the derived class's behavior?

    --
    Phlip
    http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
    Phlip, Sep 7, 2004
    #2
    1. Advertising

  3. Eivind Grimsby Haarr

    Unforgiven Guest

    "Eivind Grimsby Haarr" <> wrote in message
    news:p...
    >
    > When using polymorphism in a big system, I have sometimes come across
    > problems when changing the signature of the function in the base class,
    > and forgetting to change the signature of the derived functions
    > accordingly. (Most often when only some of the derived classes redefine
    > it.) Accessing the objects with base class pointers, the version in the
    > base class is called, which is not what I wanted. This is most often very
    > difficult to detect.
    >
    > This has made me come up with an idea for a compiler/language feature that
    > would fix this problem: A keyword in front of the derived function that
    > says that this function is derived from a base class, and the compiler
    > should issue an error if a function with a similar signature doesn't
    > exist in one of the base classes.
    >
    > What do you think about this idea? Is it just too much pain for a rare
    > problem?


    Someone had your idea already. ^_^
    The following samples follow VB.NET syntax.

    Public Class Base
    Public Overridable Sub SomeMethod(ByVal a As Integer)
    ' Stuff
    End Sub
    End Class

    Public Class Child
    Inherits Base
    Public Overrides Sub SomeMethod(ByVal a As Integer)
    ' Stuff
    End Sub
    End Class

    As you can see, the "Overrides" keyword does what you describe. Leave it
    out, and the compiler will tell you "sub 'SomeMethod' shadows an overridable
    method in a base class. To override the base method, this method must be
    declared 'Overrides'." This is a warning not an error, but if ignored, as
    the message indicates, the method will shadow (hide) the base class method,
    not override it, which means any polymorphic calls to a Base reference that
    is really a Child will always access the Base SomeMethod. If that's the
    behaviour you want but want to get rid of the warning, you should add the
    "Shadows" keyword, which tells the compiler explicitly that that is what you
    want to do.

    If you were to change the signature of SomeMethod in the base class (with
    Overrides on the child class method declaration), for instance have
    parameter "a" be a Double instead of an Integer, the compiler will give you
    both the error "sub 'SomeMethod' cannot be declared 'Overrides' because it
    does not override a sub in a base class." and the warning "sub 'SomeMethod'
    shadows an overloadable member declared in the base class 'Base'. If you
    want to overload the base method, this method must be declared 'Overloads'."

    As you can see, you're not the only one who thinks this kind of behaviour
    would be a good idea. I know it's one of the VB.NET language features I
    appreciate. ^_^

    --
    Unforgiven
    Unforgiven, Sep 7, 2004
    #3
  4. Eivind Grimsby Haarr

    Unforgiven Guest

    "Phlip" <> wrote in message
    news:i56%c.14750$...
    > Eivind Grimsby Haarr wrote:
    >>
    >> When using polymorphism in a big system, I have sometimes come across
    >> problems when changing the signature of the function in the base class,
    >> and forgetting to change the signature of the derived functions
    >> accordingly. (Most often when only some of the derived classes redefine
    >> it.) Accessing the objects with base class pointers, the version in the
    >> base class is called, which is not what I wanted. This is most often very
    >> difficult to detect.
    >>
    >> This has made me come up with an idea for a compiler/language feature
    >> that
    >> would fix this problem:

    >
    > Wouldn't that mistake break all the unit tests that depended on the base
    > class polymorphing into the derived class's behavior?


    Prolly, but that's only *if* you write unit tests ^_~

    (And don't anyone dare reply you should always write unit tests, I was being
    sarcastic damnit!)

    --
    Unforgiven
    Unforgiven, Sep 7, 2004
    #4
  5. Eivind Grimsby Haarr

    David Guest

    On Mon, 6 Sep 2004 22:50:42 UTC, Eivind Grimsby Haarr <>
    wrote:

    >
    > When using polymorphism in a big system, I have sometimes come across
    > problems when changing the signature of the function in the base class,
    > and forgetting to change the signature of the derived functions
    > accordingly. (Most often when only some of the derived classes redefine
    > it.) Accessing the objects with base class pointers, the version in the
    > base class is called, which is not what I wanted. This is most often very
    > difficult to detect.


    My solution, is that the person(s) responsible for the change have to
    insure their change does not adversely affect the rest of the system.
    For a big system, this may mean examining all the source or issuing
    some kind of announcement to a development group. Since it sounds like
    you have control of the system and the ability to do a full compile,
    it should have been possible to find all uses and verify that your
    proposed change could safely be made. On occasion, I've intentionally
    broken a method to help find all its users during a local build.

    For the "test case" crowd, it might be sufficient to change some of
    the tests to insure compatibility. However, I can imagine times where
    even a simple change could modify an entire test hierarchy. This is
    where I've seen a few TDD groups fall short from inexperience. It can
    be difficult to make such a change and then find all the uses and
    implications of that change.

    <snip>

    David
    David, Sep 7, 2004
    #5
  6. Eivind Grimsby Haarr

    Phlip Guest

    David wrote:

    > My solution, is that the person(s) responsible for the change have to
    > insure their change does not adversely affect the rest of the system.


    ensure ;-)

    > For a big system, this may mean examining all the source or issuing
    > some kind of announcement to a development group. Since it sounds like
    > you have control of the system and the ability to do a full compile,
    > it should have been possible to find all uses and verify that your
    > proposed change could safely be made. On occasion, I've intentionally
    > broken a method to help find all its users during a local build.


    A symetric typographical error could create the issue. Then you don't know
    you should announce or rebuild.

    > For the "test case" crowd, it might be sufficient to change some of
    > the tests to insure compatibility. However, I can imagine times where
    > even a simple change could modify an entire test hierarchy. This is
    > where I've seen a few TDD groups fall short from inexperience.


    "groups"? You mean TDD-ing teams?

    I use TDD to generate behavior, then I refactor that behavior into an object
    model. The behaviors might go here or there, but the tests that created each
    one still (in theory) demand them to exist. So (in theory), if that behavior
    now routes thru virtual functions, the tests would detect failure if the
    virtuality breaks.

    I could look at my C++ TDD programs that inherit, and see if breaking the
    virtual link will break a test. In theory.

    In practice, one can use the Abstract Test pattern to mirror production type
    hierarchies to test hierarchies. However, they tend to prove that all
    derived classes behaved the same, not different.

    > It can
    > be difficult to make such a change and then find all the uses and
    > implications of that change.


    Were all those uses themselves invented via TDD?

    --
    Phlip
    http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
    Phlip, Sep 7, 2004
    #6
  7. * Eivind Grimsby Haarr:
    >
    > When using polymorphism in a big system, I have sometimes come across
    > problems when changing the signature of the function in the base class,
    > and forgetting to change the signature of the derived functions
    > accordingly. (Most often when only some of the derived classes redefine
    > it.) Accessing the objects with base class pointers, the version in the
    > base class is called, which is not what I wanted. This is most often very
    > difficult to detect.
    >
    > This has made me come up with an idea for a compiler/language feature that
    > would fix this problem: A keyword in front of the derived function that
    > says that this function is derived from a base class, and the compiler
    > should issue an error if a function with a similar signature doesn't
    > exist in one of the base classes.
    >
    > What do you think about this idea? Is it just too much pain for a rare
    > problem?


    It's always a good idea to catch errors at the earliest time possible,
    preferably analysis and design, but if not, then compile-time.

    Your idea is a Good One (TM) and is implemented in .NET languages such as
    VB.NET and C#, in the latter using the keywords "override" (override) and
    "new" (shadow).

    Getting it into C++, that's another matter... ;-)

    --
    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, Sep 7, 2004
    #7
  8. "Eivind Grimsby Haarr" <> wrote in message
    news:p...
    >
    > [snip]


    It would be an interesting exercise to write a C++ program that would
    recurse into a directory structure and find all instances of a method
    (search for : public \ClassName/ then find the method (if it exists)
    within), and replace them. You could call it "rename". =)

    I don't know if you have time, but it seems like a pro would not take all
    that long to whip up something like this, even if it is platform dependent.

    James
    Aguilar, James, Sep 7, 2004
    #8
  9. Eivind Grimsby Haarr

    Phlip Guest

    Aguilar, James wrote:

    > It would be an interesting exercise to write a C++ program that would
    > recurse into a directory structure and find all instances of a method
    > (search for : public \ClassName/ then find the method (if it exists)
    > within), and replace them. You could call it "rename". =)
    >
    > I don't know if you have time, but it seems like a pro would not take all
    > that long to whip up something like this, even if it is platform

    dependent.

    It's the first feature of a "refactoring browser" - rename identifier. To
    learn how "easy" that is, search the net for a refactoring browser for C++.

    --
    Phlip
    http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
    Phlip, Sep 7, 2004
    #9
  10. "Phlip" <> wrote in message
    news:axb%c.14832$...
    >
    > It's the first feature of a "refactoring browser" - rename identifier. To
    > learn how "easy" that is, search the net for a refactoring browser for
    > C++.


    I'm making an assumption here that might not be correct, so correct me if
    I'm wrong -but- I assume that you are trying to imply that it is not easy (I
    don't really want to use my time to search for such a browser right now,
    since I personally have no use for it at the moment). Maybe you can explain
    why?

    In any case, here's my idea for an algorithm:

    ALGORITHM :

    Inputs: Method signature, set of type name,
    directory name *possibly blank for base level call*
    Vars: boolean valid (begins false)
    Returns: boolean
    WHILE (valid) {
    0. valid = true;
    1. Get all files in this folder **PLATFORM DEPENDENT**
    a. remove all files that do not end in extension .cc or .hh (GNU naming
    conventions)
    2. For each file
    a. Continue to eat input until you come to end of file or come to ":
    public
    \member of set/" or "\methSig&member of set/" (use tokens to process
    the input,
    basic stuff)
    b. If you come to the case described in 2a., valid becomes false and do
    step 3,
    otherwise, step four
    3. Edit "\methSig/" as appropriate and write the file
    4. Get list of directories and recurse. If any recursive call returns
    false, valid is
    set to false.
    }

    : ALGORITHM

    So that would do the part of making sure that within the classes, everything
    is changed. The reason for valid is to make sure that if there is a
    subclass of a subclass, it is included. It would not rename calls to the
    method or check to make sure that the change did not break outside uses of
    it, but I think this would accomplish what the OP wants (that is, to prevent
    any silent errors from showing up and biting him in the butt later on). It
    doesn't seem like it should be -that- hard, but I didn't mean to say it
    would be easy, especially for someone of my age in the processes of learning
    this stuff.
    Aguilar, James, Sep 7, 2004
    #10
  11. Eivind Grimsby Haarr

    Phlip Guest

    Aguilar, James wrote:

    > Phlip wrote:


    > > It's the first feature of a "refactoring browser" - rename identifier.

    To
    > > learn how "easy" that is, search the net for a refactoring browser for
    > > C++.

    >
    > I'm making an assumption here that might not be correct, so correct me if
    > I'm wrong -but- I assume that you are trying to imply that it is not easy

    (I
    > don't really want to use my time to search for such a browser right now,
    > since I personally have no use for it at the moment). Maybe you can

    explain
    > why?


    I have never tried it. However...

    > In any case, here's my idea for an algorithm:
    >
    > ALGORITHM :
    >
    > Inputs: Method signature, set of type name,
    > directory name *possibly blank for base level call*
    > Vars: boolean valid (begins false)
    > Returns: boolean
    > WHILE (valid) {
    > 0. valid = true;
    > 1. Get all files in this folder **PLATFORM DEPENDENT**
    > a. remove all files that do not end in extension .cc or .hh (GNU

    naming
    > conventions)
    > 2. For each file
    > a. Continue to eat input until you come to end of file or come to ":
    > public
    > \member of set/" or "\methSig&member of set/" (use tokens to

    process
    > the input,
    > basic stuff)
    > b. If you come to the case described in 2a., valid becomes false and

    do
    > step 3,
    > otherwise, step four
    > 3. Edit "\methSig/" as appropriate and write the file
    > 4. Get list of directories and recurse. If any recursive call returns
    > false, valid is
    > set to false.
    > }
    >
    > : ALGORITHM


    The first time that algorithm renames an innocent bystander, you will feel
    bad, and stop using it.

    When folks use a refactoring browser in a softer language that permits them,
    they fly, because the browser cannot make a mistake.

    My C++ code routinely screws up the intellisense and code browsing system in
    my Visual Studio editors. They use "just a little language parser" like you
    recommend. They don't use the real C++ compiler's program database, because
    they want to change their browsing on the fly as I add statements. So we get
    the worst of both worlds. My intellisense breaks when the wind blows, and my
    browser can't find variables that the compiler can.

    If a C++ refactoring browser were this unstable, nobody could tell when it
    was adding bugs, so nobody would use it.

    --
    Phlip
    http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
    Phlip, Sep 7, 2004
    #11
    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. Santastp

    Suggestion groups??

    Santastp, Sep 18, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    395
    Jay B. Harlow [MVP - Outlook]
    Sep 18, 2003
  2. Replies:
    5
    Views:
    540
    Ray Andraka
    Mar 3, 2005
  3. scadav
    Replies:
    2
    Views:
    434
    scadav
    Jul 3, 2004
  4. Michael
    Replies:
    4
    Views:
    286
    Sabre
    Aug 2, 2003
  5. Hardy Wang

    Suggestion needed for huge DataGrid

    Hardy Wang, Nov 12, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    334
Loading...

Share This Page