Loading ...
Sorry, an error occurred while loading the content.
 

Simulated dynamic binding (was RE: [wtl] XML with C++)

Expand Messages
  • dbowen@es.com
    ... Appendix A of ATL Internals talks about this, as well as an article on devx [1]. It s been called simulated dynamic binding , ATL style inheritance ,
    Message 1 of 25 , Apr 28 1:32 PM
      > First, a minor WTL-related design issue:
      >
      > "template <class _T>
      > class CMyXMLBase : public CExpatImpl <_T> "
      >
      > I can't figure out why everyone keeps doing that. In this case, it's
      > probably a doggerel version of the Abstract Template Design Pattern. If so,
      > make CExpatImpl into a concrete class and an abstract interface (IExpat, for
      > example). Then CMyXMLBase inherits IExpat and resolves any methods we need
      > in it, such as OnStartElement or OnEndElement.

      Appendix A of ATL Internals talks about this, as well as an article on devx [1]. It's been called "simulated dynamic binding", "ATL style inheritance", "upside down inheritance", "static polymorphism", and other things. Its used quite a bit in ATL / WTL for various base classes. Its not mutually exclusive to an interface, but is often used in conjunction with an interface (such as IDispatchImpl, IProvideClassInfo2Impl, etc.). Its also the technique used by of all the "mixin" windowing base classes of ATL / WTL (CWindowImpl, etc.).

      Using this approach, in the base class you do something like:

      T* pT = static_cast<T*>(this);
      pT->OverrideableFunction();

      Its essentially like having "OverrideableFunction" be a virtual function, but with a couple of benefits:

      1. It saves at least 2 levels of indirection (with a virtual function pointer and virtual function table) at run-time.
      2. The calculations for a static_cast<> are performed at compile time, so the code can be optimized better because its a compile time thing rather than a run-time thing (the compiler might even be able to inline the function call - which would be impossible if using a virtual function).
      3. It can possibly save you from needing a v-table and virtual function pointer all together - which saves at least the 4 byte virtual function pointer per instance, plus the size of the virtual table.
      4. Your base class doesn't have to define the method - thus acting like a pure virtual function that has to be defined in derived classes or you get compile errors.
      5. You can call static methods on the derived class. (And technically you could use public member variables as well - both static and non-static.)
      6. Other stuff I'm forgetting I'm sure.

      Item #5 can't be done with virtual classes and functions even if you wanted to. Just one of the many examples of this in ATL is when you are making a COM object with ATL - you define "BEGIN_COM_MAP", which expands to you defining a handful of static methods and members that the base class CComObjectRootEx calls to help implement QueryInterface.

      Now that's not to say that every single bit of code using "template <T> class Base : public T" always do things right, or that the author understood what its doing. I haven't look at CExpatImpl, so I can't speak to its use. But if you use the technique correctly, its a good thing IMO.

      -Daniel

      [1] <http://archive.devx.com/free/mgznarch/vcdj/1999/julmag99/atlinherit1.asp>
    • Igor Tandetnik
      ... devx [1]. It s been called simulated dynamic binding , ATL style inheritance , upside down inheritance , static polymorphism , and other things. Just
      Message 2 of 25 , Apr 28 1:38 PM
        > Appendix A of ATL Internals talks about this, as well as an article on
        devx [1]. It's been called "simulated dynamic binding", "ATL style
        inheritance", "upside down inheritance", "static polymorphism", and
        other things.

        Just to get the attribution straight, this technique is probably
        mentioned for the first time in

        James O. Coplien. "Curiously Recurring Template Patterns," C++ Report,
        February 1995

        With best wishes,
        Igor Tandetnik

        "For every complex problem, there is a solution that is simple, neat,
        and wrong." H.L. Mencken
      • Phlip
        ... Then with Igor online (weilding Coplien) I m certainly not going to knock it. I have all but called it simulated dynamic binding elsewhere. ... These are
        Message 3 of 25 , Apr 28 2:08 PM
          Igor Tandetnik wrote:


          > Just to get the attribution straight, this technique is probably
          > mentioned for the first time in
          >
          > James O. Coplien. "Curiously Recurring Template Patterns," C++ Report,
          > February 1995

          Then with Igor online (weilding Coplien) I'm certainly not going to knock
          it.

          I have all but called it "simulated dynamic binding" elsewhere.

          > Using this approach, in the base class you do something like:
          >
          > T* pT = static_cast<T*>(this);
          > pT->OverrideableFunction();
          >
          > Its essentially like having "OverrideableFunction" be a virtual function,
          but with a couple of benefits:
          >
          > 1.
          > 2.
          > 3.

          These are all optimization issues. Of course a library vendor should put
          them first. I ain't vending a library...

          > 4. Your base class doesn't have to define the method - thus acting like
          a pure virtual function that has to be defined in derived classes or you get
          compile errors.

          Compilation firewalls are nice.

          > Now that's not to say that every single bit of code using "template <T>
          > class Base : public T" always do things right...

          The complaint was parenthetic to my next complaint, which was about
          CExpatImpl addressing the problem instead of the solution. I'l just throw in
          a map from strings to methods and see where that goes.

          --
          Phlip
          http://www.greencheese.org/LucidScheming
          -- It's a small Web, after all... --
        • Tim Tabor
          Although the ATL list used to debate whether Coplien was the first in print, Coplien himself attributes the pattern to others. The article Igor mentioned is
          Message 4 of 25 , Apr 28 2:13 PM
            Although the ATL list used to debate whether Coplien
            was the first in print, Coplien himself attributes
            the pattern to others. The article Igor mentioned is
            reproduced in C++ Gems:

            http://www.amazon.com/exec/obidos/ASIN/0135705819/

            Tim

            > -----Original Message-----
            > From: Igor Tandetnik [mailto:itandetnik@...]
            > Sent: Monday, April 28, 2003 4:39 PM

            > Just to get the attribution straight, this technique is
            > probably mentioned for the first time in
            >
            > James O. Coplien. "Curiously Recurring Template Patterns,"
            > C++ Report, February 1995
          • Marc Brooks
            ... Actually, #2 can ALSO catch some bugs at compile-time bug instead of runtime. Marc
            Message 5 of 25 , Apr 28 4:25 PM
              >> T* pT = static_cast<T*>(this);
              >> pT->OverrideableFunction();
              >>
              >> Its essentially like having "OverrideableFunction" be a virtual
              >> function, but with a couple of benefits:
              >>
              >> 1.
              >> 2. The calculations for a static_cast<> are performed at
              >> compile time, so the code can be optimized better
              >> because its a compile time thing rather than a run-time
              >> thing (the compiler might even be able to inline the
              >> function call - which would be impossible if using a
              >> virtual function).
              >> 3.

              > These are all optimization issues.

              Actually, #2 can ALSO catch some bugs at compile-time bug instead of
              runtime.

              Marc
            • Paul Selormey
              Thanks. The first time I read it in ATL Internals I also took it to be an invention of the ATL team with VC++ support. Best regards, Paul. ... From: Igor
              Message 6 of 25 , Apr 28 7:24 PM
                Thanks. The first time I read it in ATL Internals I also took it to be an
                "invention" of the ATL team with VC++ support.

                Best regards,
                Paul.

                ----- Original Message -----
                From: "Igor Tandetnik" <itandetnik@...>
                To: <wtl@yahoogroups.com>
                Sent: Tuesday, April 29, 2003 5:38 AM
                Subject: Re: Simulated dynamic binding (was RE: [wtl] XML with C++)


                > > Appendix A of ATL Internals talks about this, as well as an article on
                > devx [1]. It's been called "simulated dynamic binding", "ATL style
                > inheritance", "upside down inheritance", "static polymorphism", and
                > other things.
                >
                > Just to get the attribution straight, this technique is probably
                > mentioned for the first time in
                >
                > James O. Coplien. "Curiously Recurring Template Patterns," C++ Report,
                > February 1995
                >
                > With best wishes,
                > Igor Tandetnik
                >
                > "For every complex problem, there is a solution that is simple, neat,
                > and wrong." H.L. Mencken
                >
                >
                >
                >
                >
                > To unsubscribe from this group, send an email to:
                > wtl-unsubscribe@yahoogroups.com
                >
                >
                >
                > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
                >
                >
              • Tim Tabor
                ... Easy enough to draw that inference . From Appendix A: It is my understanding that the ATL team discovered simulated dynamic binding accidentally. When
                Message 7 of 25 , Apr 28 8:32 PM
                  > -----Original Message-----
                  > From: Paul Selormey [mailto:paul@...]
                  > Sent: Monday, April 28, 2003 10:25 PM
                  >
                  > Thanks. The first time I read it in ATL Internals I also took
                  > it to be an "invention" of the ATL team with VC++ support.

                  Easy enough to draw that "inference". From Appendix A:

                  It is my understanding that the ATL team
                  discovered simulated dynamic binding accidentally.
                  When they did, they went immediately to the
                  compiler team, who claimed that the C++ standard
                  does not mandate or prohibit such behavior, but
                  they promised to keep it working for ATL. Does
                  that mean that you should use simulated dynamic
                  binding when you're writing your most portable
                  code? Probably not. Should you still understand
                  it because ATL is rife with it? Absolutely.
                  Should you sneak it into your own bag of tricks?
                  Why not? It's in mind.
                • Paul Selormey
                  ...and with Forword by Jim Springfield - Inventor of ATL, I believed that stuff in the Appendix till I saw a discussion on it at CodeProject :(( On the
                  Message 8 of 25 , Apr 28 9:32 PM
                    ...and with Forword by Jim Springfield - Inventor of ATL, I believed
                    that stuff in the Appendix till I saw a discussion on it at CodeProject :((

                    On the CodeProject discussion, it came to light that the principle was
                    used in a C++ mathamatics programming book long before ATL! I do
                    not know if it predates Coplien's article.

                    Best regards,
                    Paul.

                    > > Thanks. The first time I read it in ATL Internals I also took
                    > > it to be an "invention" of the ATL team with VC++ support.
                    >
                    > Easy enough to draw that "inference". From Appendix A:
                    >
                    > It is my understanding that the ATL team
                    > discovered simulated dynamic binding accidentally.
                    > When they did, they went immediately to the
                    > compiler team, who claimed that the C++ standard
                    > does not mandate or prohibit such behavior, but
                    > they promised to keep it working for ATL. Does
                    > that mean that you should use simulated dynamic
                    > binding when you're writing your most portable
                    > code? Probably not. Should you still understand
                    > it because ATL is rife with it? Absolutely.
                    > Should you sneak it into your own bag of tricks?
                    > Why not? It's in mind.
                    >
                    >
                    >
                    > To unsubscribe from this group, send an email to:
                    > wtl-unsubscribe@yahoogroups.com
                    >
                    >
                    >
                    > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
                    >
                    >
                  • Nikos Bozinis
                    ... there s no denying that this approach is optimized for runtime speed, plus it has a curiosity value for impressing laymen/bystanders :) however how about
                    Message 9 of 25 , Apr 29 12:32 AM
                      --- In wtl@yahoogroups.com, <dbowen@e...> wrote:
                      > [...]
                      > Using this approach, in the base class you do something like:
                      >
                      > T* pT = static_cast<T*>(this);
                      > pT->OverrideableFunction();
                      >
                      > Its essentially like having "OverrideableFunction" be a virtual
                      > function, but with a couple of benefits:

                      there's no denying that this approach is optimized for runtime speed,
                      plus it has a curiosity value for impressing laymen/bystanders :)

                      however how about the downsides?

                      1. Templated classes have a code size deficit. ATL tries to remedy it
                      by moving as much code as possible to global helper functions but
                      still the fact remains that if you have say 10 different frame
                      classes in your program, you'll get 10 times the same code more or
                      less reproduced as dead weight. This wouldn't have happened in a
                      traditional class hierarchy.

                      2. I am no software theorist or OO evangelist but traditional virtual
                      pointer design is very helpful for practical reasons. I'm
                      thinking "scribble" (sample) here, having one base class with all the
                      virtual members and derived classes for specialization, with a single
                      container holding different objects with the same base class. I can't
                      think of any way to make this happen (never mind a simple one) with
                      this "upside down" trickery.

                      I suppose item #1 is the most damaging, the size vs. speed trade-off,
                      especially now that WTL is rebranding itself as "embedded device
                      friendly" and code size becomes the bottleneck.

                      Nikos
                    • Gordon Smith
                      On point 2. One of the main advantages of not having traditional inheritance is the ability to have a derived CWindow which is say a blue window, and
                      Message 10 of 25 , Apr 29 6:06 AM
                        On point 2. One of the main advantages of not having traditional
                        inheritance is the ability to have a "derived" CWindow which is say a "blue"
                        window, and having a derived CWindow which is say a "round" window. In the
                        traditional inheritance scheme you could not have a "round/blue" window thru
                        inheritance, with the upside down scheme you can do this _and_ derive from a
                        CMyWindow instead of CWindow - all without revisiting the "blue" and "round"
                        code...

                        Now going back to the origonal complaint about using this with the expat
                        parser, I think the comment is correct (ie the wrapper may not be the best
                        candidate for the "upside down" approach) in our wrapper for the parser we
                        had the following, which is classic contract programming:

                        ParseXML(const char * xml, IXMLParserCallback callback);

                        where

                        class IXMLParserCallback
                        {
                        public:
                        void StartTag(const char * tag) = 0;
                        void EndTag(const char * tag) = 0;
                        etc...
                        }

                        Gordon.

                        -----Original Message-----
                        From: Nikos Bozinis [mailto:umeca74@...]
                        Sent: Tuesday, April 29, 2003 3:32 AM
                        To: wtl@yahoogroups.com
                        Subject: Re: Simulated dynamic binding (was RE: [wtl] XML with C++)


                        ...
                        2. I am no software theorist or OO evangelist but traditional virtual
                        pointer design is very helpful for practical reasons. I'm
                        thinking "scribble" (sample) here, having one base class with all the
                        virtual members and derived classes for specialization, with a single
                        container holding different objects with the same base class. I can't
                        think of any way to make this happen (never mind a simple one) with
                        this "upside down" trickery.
                        ...




                        [Non-text portions of this message have been removed]
                      • Scott Andrew
                        I must say that the non-traditional inheritance (dynamic binding) has allowed us to create a really cool skinning engine at our company. We take full advantage
                        Message 11 of 25 , Apr 29 9:21 AM
                          I must say that the non-traditional inheritance (dynamic binding) has
                          allowed us to create a really cool skinning engine at our company. We
                          take full advantage of the dynamic binding to create our skinned UI and
                          our lower level classes. We couldn't have done what we have done in WTL
                          with MFC or without dynamic binding.

                          Scott


                          On Tuesday, April 29, 2003, at 06:06 AM, Gordon Smith wrote:

                          > On point 2. One of the main advantages of not having traditional
                          > inheritance is the ability to have a "derived" CWindow which is say a
                          > "blue"
                          > window, and having a derived CWindow which is say a "round" window.
                          > In the
                          > traditional inheritance scheme you could not have a "round/blue"
                          > window thru
                          > inheritance, with the upside down scheme you can do this _and_ derive
                          > from a
                          > CMyWindow instead of CWindow - all without revisiting the "blue" and
                          > "round"
                          > code...
                          >
                          > Now going back to the origonal complaint about using this with the
                          > expat
                          > parser, I think the comment is correct (ie the wrapper may not be the
                          > best
                          > candidate for the "upside down" approach) in our wrapper for the
                          > parser we
                          > had the following, which is classic contract programming:
                          >
                          > ParseXML(const char * xml, IXMLParserCallback callback);
                          >
                          > where
                          >
                          > class IXMLParserCallback
                          > {
                          > public:
                          > void StartTag(const char * tag) = 0;
                          > void EndTag(const char * tag) = 0;
                          > etc...
                          > }
                          >
                          > Gordon.
                          >
                          > -----Original Message-----
                          > From: Nikos Bozinis [mailto:umeca74@...]
                          > Sent: Tuesday, April 29, 2003 3:32 AM
                          > To: wtl@yahoogroups.com
                          > Subject: Re: Simulated dynamic binding (was RE: [wtl] XML with C++)
                          >
                          >
                          > ...
                          > 2. I am no software theorist or OO evangelist but traditional virtual
                          > pointer design is very helpful for practical reasons. I'm
                          > thinking "scribble" (sample) here, having one base class with all the
                          > virtual members and derived classes for specialization, with a single
                          > container holding different objects with the same base class. I can't
                          > think of any way to make this happen (never mind a simple one) with
                          > this "upside down" trickery.
                          > ...
                          >
                          >
                          >
                          >
                          > [Non-text portions of this message have been removed]
                          >
                          >
                          > ------------------------ Yahoo! Groups Sponsor
                          > ---------------------~-->
                          > Get 128 Bit SSL Encryption!
                          > http://us.click.yahoo.com/xaxhjB/hdqFAA/bW3JAA/saFolB/TM
                          > ---------------------------------------------------------------------
                          > ~->
                          >
                          > To unsubscribe from this group, send an email to:
                          > wtl-unsubscribe@yahoogroups.com
                          >
                          >
                          >
                          > Your use of Yahoo! Groups is subject to
                          > http://docs.yahoo.com/info/terms/
                          >
                          >
                        • Phlip
                          ... I thought a Skin was a canonical example of the Decorator Design Pattern (which is also the Pass the Buck Pattern ;-) Props for finding a clean way to
                          Message 12 of 25 , Apr 29 10:25 AM
                            Scott Andrew sez:


                            > I must say that the non-traditional inheritance (dynamic binding) has
                            > allowed us to create a really cool skinning engine at our company. We
                            > take full advantage of the dynamic binding to create our skinned UI and
                            > our lower level classes. We couldn't have done what we have done in WTL
                            > with MFC or without dynamic binding.

                            I thought a Skin was a canonical example of the Decorator Design Pattern
                            (which is also the "Pass the Buck" Pattern ;-)

                            Props for finding a clean way to delegate.

                            --
                            Phlip
                            https://services.systran.org/SDS/wiki.cgi?PhlipPlumlee
                          • spectecjr
                            ... speed, ... it ... The thing is, the code that s generated is typically on the order of a few lines, and is a prime candidate for being inlined in the first
                            Message 13 of 25 , Apr 29 2:25 PM
                              --- In wtl@yahoogroups.com, "Nikos Bozinis" <umeca74@h...> wrote:
                              > --- In wtl@yahoogroups.com, <dbowen@e...> wrote:
                              > > [...]
                              > > Using this approach, in the base class you do something like:
                              > >
                              > > T* pT = static_cast<T*>(this);
                              > > pT->OverrideableFunction();
                              > >
                              > > Its essentially like having "OverrideableFunction" be a virtual
                              > > function, but with a couple of benefits:
                              >
                              > there's no denying that this approach is optimized for runtime
                              speed,
                              > plus it has a curiosity value for impressing laymen/bystanders :)
                              >
                              > however how about the downsides?
                              >
                              > 1. Templated classes have a code size deficit. ATL tries to remedy
                              it
                              > by moving as much code as possible to global helper functions but
                              > still the fact remains that if you have say 10 different frame
                              > classes in your program, you'll get 10 times the same code more or
                              > less reproduced as dead weight. This wouldn't have happened in a
                              > traditional class hierarchy.

                              The thing is, the code that's generated is typically on the order of
                              a few lines, and is a prime candidate for being inlined in the first
                              place.

                              ATL compiled code is *small*.

                              > 2. I am no software theorist or OO evangelist but traditional
                              virtual
                              > pointer design is very helpful for practical reasons. I'm
                              > thinking "scribble" (sample) here, having one base class with all
                              the
                              > virtual members and derived classes for specialization, with a
                              single
                              > container holding different objects with the same base class. I
                              can't
                              > think of any way to make this happen (never mind a simple one)
                              with
                              > this "upside down" trickery.

                              That's why neither technique has superceded the other. The upside-
                              down trick is most useful when building policy-based frameworks, and
                              for performing some very specific hacks to the class hierarchy (eg.
                              making sure that IUnknown is implemented in one place, once). It's a
                              mix-in kind of thing. It may help you to view virtual members as
                              supporting runtime polymorphism, and the templated hierarchy trick
                              as supporting compile-time polymorphism.

                              > I suppose item #1 is the most damaging, the size vs. speed trade-
                              off,
                              > especially now that WTL is rebranding itself as "embedded device
                              > friendly" and code size becomes the bottleneck.

                              What code size? Have you run any tests here?

                              Unless you make all of *your* methods inline, you shouldn't have a
                              problem. In most cases, all ATL and WTL methods compile down to the
                              equivalent API call. Eg. if you do:

                              void foo(CWindow myWnd) {
                              myWindow.ShowWindow(SW_NORMAL);
                              }

                              ... what you get in your code is:

                              ::ShowWindow(myWnd.m_hWnd, SW_NORMAL);

                              ... which in many (if not all) cases will be more compact than the
                              equivalent MFC code.
                            • Nikos Bozinis
                              ... the problem is down to templated classes, not inlining. Read any book on templates and it will warn you on the code duplication side-effect they suffer.
                              Message 14 of 25 , Apr 30 3:22 AM
                                --- In wtl@yahoogroups.com, "spectecjr" <simoncooke@e...> wrote:
                                >
                                > > I suppose item #1 is the most damaging, the size vs. speed trade-
                                > off,
                                > > especially now that WTL is rebranding itself as "embedded device
                                > > friendly" and code size becomes the bottleneck.
                                >
                                > What code size? Have you run any tests here?
                                >

                                the problem is down to templated classes, not inlining. Read any book
                                on templates and it will warn you on the code duplication side-effect
                                they suffer. Each time one creates a different specialization of the
                                class (different T) you get more or less all the code duplicated,
                                triplicated etc

                                i have to admit though that i'd never done tests to find exact
                                figures for my claims, so i went back and did some. Starting with a
                                base WTL sdi project with good optimization flags towards size
                                minimization, I have indeed detected size differences (Release build)
                                when adding (empty) classes for dialogs and frames.

                                So if you have a basic app with a CAboutDlg and add another
                                CAboutDlg2, you end up with 500 bytes junk. Add an extra frame window
                                CMainFrame2 and -- this being a chunkier class -- here are 1.2K bytes
                                more (even when all the toolbar calls, handlers etc are removed).

                                Admitedly these results are better than what I thought when I made
                                the size argument. My original hunch was that the deficit was 3-4K
                                per dialog and much worse for frame classes. Obviously VS6
                                compiler/optimizer do a good job eliminating redundant code

                                So the morale of the story is:
                                my size disadvantage argument is technically correct, but it is so
                                small that it won't matter too much unless you have tons of dialogs
                                etc.

                                So I hereby withdraw my original argument :)
                              • Andreas Magnusson
                                One thing, make sure that you test with the link flags: /OPT:REF and /OPT:ICF. They are claimed to make differences with ATL/WTL, but it s been ages since I
                                Message 15 of 25 , Apr 30 4:58 AM
                                  One thing, make sure that you test with the link flags: /OPT:REF and
                                  /OPT:ICF. They are claimed to make differences with ATL/WTL, but it's been
                                  ages since I last checked. Esp. with empty classes/methods...

                                  /Andreas
                                  ----- Original Message -----
                                  From: "Nikos Bozinis" <umeca74@...>
                                  To: <wtl@yahoogroups.com>
                                  Sent: Wednesday, April 30, 2003 12:22 PM
                                  Subject: Re: Simulated dynamic binding (was RE: [wtl] XML with C++)


                                  > --- In wtl@yahoogroups.com, "spectecjr" <simoncooke@e...> wrote:
                                  > >
                                  > > > I suppose item #1 is the most damaging, the size vs. speed trade-
                                  > > off,
                                  > > > especially now that WTL is rebranding itself as "embedded device
                                  > > > friendly" and code size becomes the bottleneck.
                                  > >
                                  > > What code size? Have you run any tests here?
                                  > >
                                  >
                                  > the problem is down to templated classes, not inlining. Read any book
                                  > on templates and it will warn you on the code duplication side-effect
                                  > they suffer. Each time one creates a different specialization of the
                                  > class (different T) you get more or less all the code duplicated,
                                  > triplicated etc
                                  >
                                  > i have to admit though that i'd never done tests to find exact
                                  > figures for my claims, so i went back and did some. Starting with a
                                  > base WTL sdi project with good optimization flags towards size
                                  > minimization, I have indeed detected size differences (Release build)
                                  > when adding (empty) classes for dialogs and frames.
                                  >
                                  > So if you have a basic app with a CAboutDlg and add another
                                  > CAboutDlg2, you end up with 500 bytes junk. Add an extra frame window
                                  > CMainFrame2 and -- this being a chunkier class -- here are 1.2K bytes
                                  > more (even when all the toolbar calls, handlers etc are removed).
                                  >
                                  > Admitedly these results are better than what I thought when I made
                                  > the size argument. My original hunch was that the deficit was 3-4K
                                  > per dialog and much worse for frame classes. Obviously VS6
                                  > compiler/optimizer do a good job eliminating redundant code
                                  >
                                  > So the morale of the story is:
                                  > my size disadvantage argument is technically correct, but it is so
                                  > small that it won't matter too much unless you have tons of dialogs
                                  > etc.
                                  >
                                  > So I hereby withdraw my original argument :)
                                  >
                                  >
                                  >
                                  > To unsubscribe from this group, send an email to:
                                  > wtl-unsubscribe@yahoogroups.com
                                  >
                                  >
                                  >
                                  > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
                                  >
                                  >
                                  >
                                • Nikos Bozinis
                                  ... and ... i have /opt:ref and :nowin98 allright icf doesn t make a difference to my knowledge
                                  Message 16 of 25 , Apr 30 5:41 AM
                                    --- In wtl@yahoogroups.com, "Andreas Magnusson" <andreas_ch_m@h...>
                                    wrote:
                                    > One thing, make sure that you test with the link flags: /OPT:REF
                                    and
                                    > /OPT:ICF.

                                    i have /opt:ref and :nowin98 allright
                                    icf doesn't make a difference to my knowledge
                                  • McDonald, Andrew
                                    1. Any compiler/linker worth its salt will remove duplicate template code, better ones will also remove extra template code generated from templated classes
                                    Message 17 of 25 , May 2, 2003
                                      1. Any compiler/linker worth its salt will remove duplicate template code, better ones will also remove extra template
                                      code generated from templated classes with different template arguments but which result in the same machine code. I believe VC
                                      is one such compiler, but I've completely forgotten where I found the article than detailed this stuff. ( obviously inlined functions just
                                      generate more code whatever ). My experience is that template bloat is normally caused by overuse of inlining, i.e. inline template functions
                                      calling other inline functions and the whole lot getting inlined and bad template design.

                                      2. Its pretty easy to add virtual functions to a class hierachy using simulated dynamic binding, its impossible to remove them.

                                      i.e.

                                      template< class T >
                                      class TemplatedBase
                                      {
                                      public:
                                      void DoSomething(void)
                                      {
                                      T* pT = static_cast<T*>(this);
                                      pT->OverrideableFunction();
                                      }
                                      };

                                      class VirtualBase : public TemplatedBase< VirtualBase >
                                      {
                                      public:
                                      virtual void OverrideableFunction(void) = 0;
                                      };

                                      class SomeImplementation : public VirtualBase
                                      {
                                      public:
                                      virtual void OverrideableFunction(void);
                                      };



                                      -----Original Message-----
                                      From: Nikos Bozinis [mailto:umeca74@...]
                                      Sent: 29 April 2003 08:32
                                      To: wtl@yahoogroups.com
                                      Subject: Re: Simulated dynamic binding (was RE: [wtl] XML with C++)


                                      --- In wtl@yahoogroups.com, <dbowen@e...> wrote:
                                      > [...]
                                      > Using this approach, in the base class you do something like:
                                      >
                                      > T* pT = static_cast<T*>(this);
                                      > pT->OverrideableFunction();
                                      >
                                      > Its essentially like having "OverrideableFunction" be a virtual
                                      > function, but with a couple of benefits:

                                      there's no denying that this approach is optimized for runtime speed,
                                      plus it has a curiosity value for impressing laymen/bystanders :)

                                      however how about the downsides?

                                      1. Templated classes have a code size deficit. ATL tries to remedy it
                                      by moving as much code as possible to global helper functions but
                                      still the fact remains that if you have say 10 different frame
                                      classes in your program, you'll get 10 times the same code more or
                                      less reproduced as dead weight. This wouldn't have happened in a
                                      traditional class hierarchy.

                                      2. I am no software theorist or OO evangelist but traditional virtual
                                      pointer design is very helpful for practical reasons. I'm
                                      thinking "scribble" (sample) here, having one base class with all the
                                      virtual members and derived classes for specialization, with a single
                                      container holding different objects with the same base class. I can't
                                      think of any way to make this happen (never mind a simple one) with
                                      this "upside down" trickery.

                                      I suppose item #1 is the most damaging, the size vs. speed trade-off,
                                      especially now that WTL is rebranding itself as "embedded device
                                      friendly" and code size becomes the bottleneck.

                                      Nikos



                                      To unsubscribe from this group, send an email to:
                                      wtl-unsubscribe@yahoogroups.com



                                      Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
                                    • Igor Tandetnik
                                      ... code, better ones will also remove extra template ... arguments but which result in the same machine code. I believe VC ... article than detailed this
                                      Message 18 of 25 , May 2, 2003
                                        > 1. Any compiler/linker worth its salt will remove duplicate template
                                        code, better ones will also remove extra template
                                        > code generated from templated classes with different template
                                        arguments but which result in the same machine code. I believe VC
                                        > is one such compiler, but I've completely forgotten where I found the
                                        article than detailed this stuff. ( obviously inlined functions just
                                        > generate more code whatever ).

                                        Can it really? How does the linker deal with a situation like this:

                                        template <class T> void f();
                                        void (*PF)();

                                        PF pf1 = &f<int>;
                                        PF pf2 = &f<long>;
                                        assert(pf1 != pf2); // expected to succeed

                                        The compiler is no help - pf1 and pf2 may be assigned in two different
                                        translation units and passed as parameters to function in the third
                                        translation unit. How can the linker detect whether or not there are
                                        pointers to template instantiations floating around?

                                        With best wishes,
                                        Igor Tandetnik
                                      • Phlip
                                        ... The as-if rule implies a C++ compiler must produce a program that behaves as-if it had followed the virtual machine rules in the C++ Standard. If I call
                                        Message 19 of 25 , May 2, 2003
                                          Igor Tandetnik sez:


                                          > > 1. Any compiler/linker worth its salt will remove duplicate template
                                          > code, better ones will also remove extra template
                                          > > code generated from templated classes with different template
                                          > arguments but which result in the same machine code. I believe VC
                                          > > is one such compiler, but I've completely forgotten where I found the
                                          > article than detailed this stuff. ( obviously inlined functions just
                                          > > generate more code whatever ).
                                          >
                                          > Can it really? How does the linker deal with a situation like this:
                                          >
                                          > template <class T> void f();
                                          > void (*PF)();
                                          >
                                          > PF pf1 = &f<int>;
                                          > PF pf2 = &f<long>;
                                          > assert(pf1 != pf2); // expected to succeed
                                          >
                                          > The compiler is no help - pf1 and pf2 may be assigned in two different
                                          > translation units and passed as parameters to function in the third
                                          > translation unit. How can the linker detect whether or not there are
                                          > pointers to template instantiations floating around?

                                          The as-if rule implies a C++ compiler must produce a program that behaves
                                          as-if it had followed the virtual machine rules in the C++ Standard.

                                          If I call f<int>(), the only operations I can think of that could detect if
                                          I'm really inside f<long>() are either ones that would force two different
                                          machine language functions to exist, or ones whose behavior is already
                                          undefined. Being undefined frees the compiler to not perform aggressive
                                          checks such as alias checks

                                          The above is well-defined, but the compiler is not obligated to call f<long>
                                          if you invoke f<long>() (or similarily for f<int>). The compiler and linker
                                          could easily fold f<long> into f<int>, and then only link in f<int> when we
                                          collect its address, under the assumption that we won't and the result will
                                          get smaller.

                                          Disassemble and see. But don't get your hopes up. I thought that much of the
                                          explicit method folding in STL, ATL and WTL happened due to these known
                                          pessimizations.

                                          --
                                          Phlip
                                          http://www.c2.com/cgi/wiki?TestFirstUserInterfaces
                                        • Igor Tandetnik
                                          ... f ... linker ... when we ... will ... My sample does not try to call the function and detect from inside the function which instantiation is being
                                          Message 20 of 25 , May 2, 2003
                                            > The above is well-defined, but the compiler is not obligated to call
                                            f<long>
                                            > if you invoke f<long>() (or similarily for f<int>). The compiler and
                                            linker
                                            > could easily fold f<long> into f<int>, and then only link in f<int>
                                            when we
                                            > collect its address, under the assumption that we won't and the result
                                            will
                                            > get smaller.

                                            My sample does not try to call the function and detect from inside the
                                            function which instantiation is being called. My sample simply checks
                                            whether two pointers point to the same function or not. C++ standard
                                            5.10/1 says:

                                            Pointers to objects or functions of the same type (after pointer
                                            conversions) can be compared for equality. Two pointers of the same type
                                            compare equal if and only if they are both null, both point to the same
                                            object or function, or both point one past the end of the same array.

                                            If the linker folds f<int> and f<long> together, two pointers to
                                            different functions will compare equal. Are you saying that comparing
                                            addresses of two function temlpate instantiations is undefined? Would
                                            you expect a sudden change in the behavior of the following program when
                                            macro TEST is defined:

                                            // #define TEST

                                            template <class T> void f();
                                            void f<int>() {}
                                            void f<long>()
                                            {
                                            #ifdef TEST
                                            cout << "Hello";
                                            #endif
                                            }

                                            void (*PF)();
                                            PF pf1 = &f<int>;
                                            PF pf2 = &f<long>;
                                            if (pf1 == pf2)
                                            {
                                            cout << "Equal";
                                            }


                                            Come to think of it, it's pretty much the same as saying that linker can
                                            merge the implementation of f and g in the following fragment:

                                            void f() {}
                                            void g() {}

                                            Are you saying it can? Does it mean that (&f == &g) is not well-defined
                                            either? What is the meaning of 5.10/1 then?

                                            With best wishes,
                                            Igor Tandetnik
                                          • Phlip
                                            ... My ability to confuse the issue has struct again. assert(pf1 != pf2) will not guarantee f () doesn t secretly call f () (or vice versa) when you
                                            Message 21 of 25 , May 2, 2003
                                              > Are you saying it can? Does it mean that (&f == &g) is not well-defined
                                              > either? What is the meaning of 5.10/1 then?

                                              My ability to confuse the issue has struct again.

                                              assert(pf1 != pf2) will not guarantee f<int>() doesn't secretly call
                                              f<long>() (or vice versa) when you actually call it (and not thru its
                                              pointer).

                                              Your statement "If the linker folds f<int> and f<long> together, two
                                              pointers to different functions will compare equal" is not guaranteed,
                                              because the compiler can do things "as-if" the compiler had behaved
                                              pessimistically, so long as you can't tell the difference.

                                              The statement "Pointers to ... functions ... can be compared for equality"
                                              only implies if they are declared differently then their equality will be
                                              different. It implicitly means that if some optimization made them the same,
                                              they will still compare different.

                                              By comparison, consider the language lawyers' favorite, 'inline'. Taking the
                                              address of an inline does not somehow force other in-line expressions of
                                              that function to appear out-of-line. They may still inline. Functions not
                                              declared explicit or implicit inline may still inline, too.

                                              Feel free to take this one up with a C++ newsgroup near you. I'm not a
                                              language lawyer, but I have the subjective impression these rules have
                                              explicit loopholes to permit optimizations.

                                              --
                                              Phlip
                                              http://www.c2.com/cgi/wiki?TestFirstUserInterfaces
                                            • Igor Tandetnik
                                              ... well-defined ... Ah, I see. I guess this is a valid optimization, does not seem to be anything wrong with it. Does any actual compiler/linker behave this
                                              Message 22 of 25 , May 2, 2003
                                                > > Are you saying it can? Does it mean that (&f == &g) is not
                                                well-defined
                                                > > either? What is the meaning of 5.10/1 then?
                                                >
                                                > My ability to confuse the issue has struct again.
                                                >
                                                > assert(pf1 != pf2) will not guarantee f<int>() doesn't secretly call
                                                > f<long>() (or vice versa) when you actually call it (and not thru its
                                                > pointer).

                                                Ah, I see. I guess this is a valid optimization, does not seem to be
                                                anything wrong with it. Does any actual compiler/linker behave this way,
                                                that is, generate a common implementation for identical functions and
                                                forward calls to this common implementation? Can any version of VC do
                                                this? Maybe VC7 with whole program optimization turned on?

                                                With best wishes,
                                                Igor Tandetnik
                                              • Phlip
                                                ... I have pushed us well outside the envelop of my C++ awareness. ;-) -- Phlip http://www.c2.com/cgi/wiki?TestFirstUserInterfaces
                                                Message 23 of 25 , May 2, 2003
                                                  Igor Tandetnik sez:

                                                  > Ah, I see. I guess this is a valid optimization, does not seem to be
                                                  > anything wrong with it. Does any actual compiler/linker behave this way,
                                                  > that is, generate a common implementation for identical functions and
                                                  > forward calls to this common implementation? Can any version of VC do
                                                  > this? Maybe VC7 with whole program optimization turned on?

                                                  I have pushed us well outside the envelop of my C++ awareness. ;-)

                                                  --
                                                  Phlip
                                                  http://www.c2.com/cgi/wiki?TestFirstUserInterfaces
                                                • Igor Tandetnik
                                                  ... way, ... and ... do ... Well, maybe Andrew McDonald knows. I would really like to find out exactly which compilers are better than those worth their salt.
                                                  Message 24 of 25 , May 2, 2003
                                                    > Igor Tandetnik sez:
                                                    >
                                                    > > Ah, I see. I guess this is a valid optimization, does not seem to be
                                                    > > anything wrong with it. Does any actual compiler/linker behave this
                                                    way,
                                                    > > that is, generate a common implementation for identical functions
                                                    and
                                                    > > forward calls to this common implementation? Can any version of VC
                                                    do
                                                    > > this? Maybe VC7 with whole program optimization turned on?
                                                    >
                                                    > I have pushed us well outside the envelop of my C++ awareness. ;-)

                                                    Well, maybe Andrew McDonald knows. I would really like to find out
                                                    exactly which compilers are better than those worth their salt. What are
                                                    those better ones worth? :)

                                                    With best wishes,
                                                    Igor Tandetnik
                                                  • Phlip
                                                    ... I don t care. My sane subset (which now includes SDB) is much narrower than my envelop, and already tuned for such optimizations as matter to real
                                                    Message 25 of 25 , May 2, 2003
                                                      Igor Tandetnik sez:

                                                      > Well, maybe Andrew McDonald knows. I would really like to find out
                                                      > exactly which compilers are better than those worth their salt. What are
                                                      > those better ones worth? :)

                                                      I don't care. My sane subset (which now includes SDB) is much narrower than
                                                      my envelop, and already tuned for such optimizations as matter to real
                                                      customers. Footprint is, sadly, last, but it would be fun.

                                                      --
                                                      Phlip
                                                      http://www.c2.com/cgi/wiki?TestFirstUserInterfaces
                                                    Your message has been successfully submitted and would be delivered to recipients shortly.