Topic: delegations and interfaces


Author: cppljevans@cox-internet.com (Larry Evans)
Date: Mon, 3 May 2004 16:37:05 +0000 (UTC)
Raw View
Dave Harris wrote:
> cdiggins@videotron.ca ("christopher diggins") wrote (abridged):
>
>>     struct mystruct : public FuBarDelegator<&x> {
>>        FuBar x;
>>     };
>>
>>Despite the problem of infinite regress in the current method of
>>generating templates, it would be very simple for compilers to
>>allow this kind of code,

I think this is what I was aiming at with "dynamic inheritance"
( http://article.gmane.org/gmane.comp.lib.boost.devel/33983 ).

[snip]


> However, it seems clear that some language extension is needed. So why not
> provide delegation directly? In D&E $12.7, Stroustrup talks about the
> syntax:
>
>    struct FuBar {
>        void Fu();
>        void Bar();
>    };
>
>    class mystruct : public *px  {
>        FuBar *px;
>    };
>
> Here we are conceptually inheriting from a variable directly. And that
> variable is a pointer which can be assigned to at run-time.

[snip]

A similar connection with "dynamic inheritance" was noted in:

http://article.gmane.org/gmane.comp.lib.boost.devel/34023

>
>>One advantage of this kind of delegation technique, over say a
>>Delegation macro, is that any delegated functions can easily be
>>overridden in a class that inherits from a Delegator.
>
>
> One of the problems is that this works for external sends but not for
> self-sends by FuBar. Modifying your code slightly:

[snipped code]

>       mystruct s;
>       FuBarBase &f = s;
>       f.Bar(); // invokes mystruct::Bar.
>       f.Fu(); // invokes FuBar::Bar.
>
> Apparently people found this confusing in practice. They expected
> mystruct::Bar to somehow override mystruct.x::Bar.

Initially, I was confused by the last sentence since the comment
after f.Bar indicates mystruct::Bar is called, but looking closer,
I see:

    f.Fu() --> f.FubarDelegator<t=&f.x>::Fu(){t->Fu();}
           --> (&f.x)->Fu();
           --> FuBar::Fu(){Bar();}
           --> FuBar::Bar();

which is what you concluded above.

>
> It seems the delegatee often wants some way to get back to the delegator.
> This could be achieved in your scheme by making the delegator code like:
>
>       template<T* t>
>       struct FuBarDelegator : FuBarBase {
>           virtual void Fu() { t->Fu( this ); }
>           virtual void Bar() { t->Bar( this ); }
>       };
>
> This might be less error-prone. It would be more explicit about there
> being two objects involved.

Interesting!  This problem sounds very similar to that mentioned in

   http://article.gmane.org/gmane.comp.lib.boost.devel/33983

where it contains:

   there's a pointer from subtype to supertype and back (more memory)

A more graphical description of the dynamic inheritance solution is in:

   http://article.gmane.org/gmane.comp.lib.boost.devel/34057

where the ability for delegatee to get back to the delegator and vice
versa is indicated by the double arrows ( implemented as two pointers
somewhat like a doubly linked list).

> Also, the code I showed in my previous article is fine. It works with the
> current language. As far as I can tell, your only problem with it is the

I'm planning on trying that code as soon as I get a "single strong
pointer per gc'ed object" refcounting garbage collector working.

Anyhow, the "heart" of the way it works now is the dynamic_inherit
class with header:

template
   < typename SuperType
   , typename DeltaType
   , template<typename>class Proxy=inherit_ptr
   >
class dynamic_inherit
   : public virtual_dtor_abs
   , public Proxy<SuperType>
     //pointer to "super type"
   , public DeltaType
     //the "delta" or additions to SuperType which form this_type.
//Purpose:
//  Enable instances of SuperType to be "decorated" (in the sense of
//  the GOF Decorator pattern) with a DeltaType dynamically.
//  The difference from the Decorator pattern is:
//    1)The SuperType (which corresponds to the Component participant
//      in the GOF Decorator pattern) is not inherited by this class
//      (which corresponds with the Decorator participant in the
//      Decorator pattern) but is simply pointed to by the
//      Proxy<SuperType> superclass, which corresponds to the
//      "component" reference in the Decorator class diagram.
//    2)The SuperType has a pointer back to this as it's subtype part.
//
//  This class also embodies some of the features of the GOF strategy
//  pattern in that the SuperType (which corresponds with the Context
//  participant in the strategy pattern) has a pointer to the this
//  class (which corresponds to the Strategy paricipant in the
//  strategy pattern).

I'm hoping to upload the code to boost's sandbox as soon as I get a
password for that.  If you're interested, I let you know when that
happens.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: llewelly.at@xmission.dot.com (llewelly)
Date: Wed, 5 May 2004 04:59:30 +0000 (UTC)
Raw View
brangdon@cix.co.uk (Dave Harris) writes:

> cdiggins@videotron.ca ("christopher diggins") wrote (abridged):
>>      struct mystruct : public FuBarDelegator<&x> {
>>         FuBar x;
>>      };
>>
>> Despite the problem of infinite regress in the current method of
>> generating templates, it would be very simple for compilers to
>> allow this kind of code,
>
> Of course, an object's address is not a compile-time constant,

Nit: Not necessarily so. See 14.3.2/1 bullet 4:

    # the address of an object or function with external linkage,
    # including function templates and function template-ids but
    # excluding non-static class members, expressed as & id-expression
    # where the & is optional if the name refers to a function or
    # array, or if the corresponding template-parameter is a
    # refer-ence; or

(Though x in the example above doesn't fit this clause.)


> and each
> instance of mystruct needs FuBarDelegator<&x> with a different address. So
> I think we have to think of it in terms of offsets.
[snip]

Pointers to members are valid template arguments. (14.3.2/1 bullet 5.)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: cdiggins@videotron.ca ("christopher diggins")
Date: Fri, 30 Apr 2004 16:38:45 +0000 (UTC)
Raw View
"Dave Harris" <brangdon@cix.co.uk> wrote in message
news:memo.20040429200225.1816A@brangdon.m...
> cdiggins@videotron.ca (christopher diggins) wrote (abridged):

[snip]

> > Is there a way to pass mystruct::x to the Delegator as template
> > parameter?
>
> Template parameters need to be compile-time constants. What I think
> you want to pass is the offset between the start of the template
> class and the start of the variable, which one might expect to be
> a compile-time constant. However, trying it leads to an infinite
> regress. The compile might place the variable after the template class,
> so that it need to know sizeof(FuBarDelegator<offset(x)>) before it
> knows the offset(x), and the sizeof a template can depend on the
> template parameters.
>
> -- Dave Harris, Nottingham, UK

Thank you very much Dave. I apologize for the errors in the source code. I
think then that what I have would be a good canidate for a proposal. What I
am striving towards is more accurately represented by the following code:

     template<T* t>
     struct FuBarDelegator {
         void Fu() { t->Fu(); }
         void Bar() { t->Bar(); }
     };

     struct FuBar {
        void Fu() { /* ... */ };
        void Bar() { /* ... */ };
     };

     struct mystruct : public FuBarDelegator<&x> {
        FuBar x;
     };

Despite the problem of infinite regress in the current method of generating
templates, it would be very simple for compilers to allow this kind of code,
all that is needed is to store a kind of placeholder when using a member
variable as a template parameter, which is resolved at the end of the
completion of generation of the template.

One advantage of this kind of delegation technique, over say a Delegation
macro, is that any delegated functions can easily be overridden in a class
that inherits from a Delegator.

Are there any ideas of the feasability and usefulness of such a proposal?

--
Christopher Diggins
http://www.cdiggins.com
http://www.heron-language.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 2 May 2004 19:44:33 +0000 (UTC)
Raw View
cdiggins@videotron.ca ("christopher diggins") wrote (abridged):
>      struct mystruct : public FuBarDelegator<&x> {
>         FuBar x;
>      };
>
> Despite the problem of infinite regress in the current method of
> generating templates, it would be very simple for compilers to
> allow this kind of code,

Of course, an object's address is not a compile-time constant, and each
instance of mystruct needs FuBarDelegator<&x> with a different address. So
I think we have to think of it in terms of offsets. I take your point to
be that if all we want is delegation, we don't need to solve the general
case of passing offsets.

However, it seems clear that some language extension is needed. So why not
provide delegation directly? In D&E $12.7, Stroustrup talks about the
syntax:

   struct FuBar {
       void Fu();
       void Bar();
   };

   class mystruct : public *px  {
       FuBar *px;
   };

Here we are conceptually inheriting from a variable directly. And that
variable is a pointer which can be assigned to at run-time.

Stroustrup experimented with the feature but found it too error prone in
practice.


> One advantage of this kind of delegation technique, over say a
> Delegation macro, is that any delegated functions can easily be
> overridden in a class that inherits from a Delegator.

One of the problems is that this works for external sends but not for
self-sends by FuBar. Modifying your code slightly:

      struct FuBarBase {
         virtual void Fu() = 0;
         virtual void Bar() = 0;
      };

      template<T* t>
      struct FuBarDelegator : FuBarBase {
          virtual void Fu() { t->Fu(); }
          virtual void Bar() { t->Bar(); }
      };

      struct FuBar {
         virtual void Fu() { Bar(); };
         virtual void Bar() { /* ... */ };
      };

      struct mystruct : FuBarDelegator<&x> {
         FuBar x;
         virtual void Bar();
      };

      mystruct s;
      FuBarBase &f = s;
      f.Bar(); // invokes mystruct::Bar.
      f.Fu(); // invokes FuBar::Bar.

Apparently people found this confusing in practice. They expected
mystruct::Bar to somehow override mystruct.x::Bar.

It seems the delegatee often wants some way to get back to the delegator.
This could be achieved in your scheme by making the delegator code like:

      template<T* t>
      struct FuBarDelegator : FuBarBase {
          virtual void Fu() { t->Fu( this ); }
          virtual void Bar() { t->Bar( this ); }
      };

This might be less error-prone. It would be more explicit about there
being two objects involved.


> Are there any ideas of the feasability and usefulness of such a
> proposal?

I would like to see better support for delegation. Especially through
pointers. However, any successful proposal will have to show it overcomes
the issues Stroustrup raises in D&E. And of course, there is always the
hope that a decent metaprogramming solution could cover this base. Good is
the enemy of better :-)

Also, the code I showed in my previous article is fine. It works with the
current language. As far as I can tell, your only problem with it is the
space overhead of the pointer or reference that needs to be stored in
FuBarDelegator. We probably need a better reason than mere efficiency to
change the language.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "christopher diggins" <cdiggins@videotron.ca>
Date: Wed, 28 Apr 2004 13:17:09 CST
Raw View
Given a class which behaves like the following interface:

interface IFuBar {
    void Fu();
    void Bar();
};

I can then write the following code:

struct FuBar {
    void Fu() { /* ... */ };
    void Bar() { /* ... */ };
};
template<typename T> struct FuBarDelegator {
    Delegator(T x);
    T x;
    void Fu() { x.Fu(); };
    void Bar() { x.Bar(); };
};
struct mystruct : public Delegator<IFuBar>
{
    mystruct() : Delegator<IFuBar>(x); // passes a reference to x
    FuBar x;
};

The problems is that this is unsatisfactory due to the redundancy the
reference to X in the base class and a rather pointless constructor call. Is
there a way to pass mystruct::x to the Delegator as template parameter? Is
there any other way to avoid the extra pointer?

--
Christopher Diggins
http://www.cdiggins.com
http://www.heron-language.com



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

--
Christopher Diggins
http://www.cdiggins.com
http://www.heron-language.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 29 Apr 2004 22:08:19 +0000 (UTC)
Raw View
cdiggins@videotron.ca (christopher diggins) wrote (abridged):
> Given a class which behaves like the following interface:
> [delegation code snipped]

I don't think interfaces are necessary here. You can just write:

    template <typename T>
    struct FuBarDelegator {
        T &t;
        FuBarDelegator( T &t ) : t(t) {}
        void Fu() { t.Fu(); }
        void Bar() { t.Bar(); }
    };

    struct FuBar {
       void Fu() { /* ... */ };
       void Bar() { /* ... */ };
    };

    struct mystruct : public FuBarDelegator<FuBar> {
       FuBar x;
       mystruct() : FuBarDelegator<FuBar>(x) {}
    };


> struct mystruct : public Delegator<IFuBar>

You never define Delegator. I assume it is a typo for FuBarDelegator.


> The problems is that this is unsatisfactory due to the redundancy
> the reference to X in the base class

As far as I can tell, it is an instance of an interface, which I
presume is implemented as a fat pointer. A plain reference, as in my
code above, would be more space-efficient, and probably easier to
optimise away. If you do have a reference, I am not sure what it is
a reference to - what's its lifetime?


> Is there a way to pass mystruct::x to the Delegator as template
> parameter?

Template parameters need to be compile-time constants. What I think
you want to pass is the offset between the start of the template
class and the start of the variable, which one might expect to be
a compile-time constant. However, trying it leads to an infinite
regress. The compile might place the variable after the template class,
so that it need to know sizeof(FuBarDelegator<offset(x)>) before it
knows the offset(x), and the sizeof a template can depend on the
template parameters.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]