[ag-automation] Questions/Annotations about implementation of fddi

Thomas Rothfuss tb10rts at web.de
Tue Oct 2 12:04:36 CEST 2007


Robert,

 >>Since this should be a C interface not a C++ one fddi_device is not
 >>an abstract class to derive from. But it is possible to separate
 >>the interface from the implementation by using the pimpl-Pattern
 >>(see http://www.gotw.ca/gotw/024.htm). Using "void *priv;" is the
 >>a similar mechanism.
 >
 >
 > I played with that variant and, although it looks interesting at the
 > first glance, it seems to have a major drawback. The current
 > implementation works without forcing the user into using malloc; he can
 > decide himself, which is important for industrial use [1]. So we can
 > write something like
 >
 >     fddi_bla_t bla;
 >
 >     fddi_bla_init(&bla);
 >
 > or
 >
 >     fddi_bla_t *bla;
 >
 >     bla = malloc(sizeof(fddi_bla_t));
 >     fddi_bla_init(bla);
 >
 > The choice is up to the user, we don't force him into one of the
 > variants. That would change to
 >
 >     fddi_bla_t bla;
 >     fddi_bla_impl_t bla_impl;
 >
 >     fddi_bla_init(&bla, &bla_impl);
 >
 > and
 >
 >     fddi_bla_t *bla;
 >
 >     bla = malloc(sizeof(fddi_bla_t));
 >     bla_impl = malloc(sizeof(fddi_bla_impl_t));
 >
 >     fddi_bla_init(bla, bla_impl);
 >
 > which is simply too uggly to live. I don't think it is worth the effort,
 > or do you have a better idea how to avoid this problem?
 >
 > Cheers,
 > Robert
 >
 > [1] I personally think that using malloc in a carefully reviewed library
 >     is more safe than most of the industrial code quality I've seen in
 >     commercial projects, but we don't want to constrain our user base.


You don't need the implementation (fddi_bla_impl_t) in the interface
at all. This is the wrong concept.


Well, the interface is a contract between the participants. All other
funtionality is internally. Let's assume there is following struct:

      struct fddi_bla
       {
         int var1;
         int var2;

         void* impl; /* for internal use only */
       };

     typedef struct fddi_bla fddi_bla_t;


The interface provides following functions:

      void add (const fddi_bla_t* bla);
      fddi_bla_t* first (void);
      fddi_bla_t* next (const fddi_bla_t* bla);

There are two participants P1 and P2.

P1 wants to add an element to P2:

     fddi_bla bla1;
     bla1.var1 = 1;
     bla1.var2 = 2;
     add (&bla1);

P1 wants to get the next element from P2:

     fddi_bla* bla2;

     for (bla2 = first (); bla2 != NULL; bla2 = next (bla2))
       {
           int i = bla2->var1;
           printf ("i = %d\n", i);
       }


In the first use case the element is allocated by P1 in the second one
by P2. Since the interface (struct) has an impl pointer which does not
care there is no problem.

note: Of course it must be _absolute_ clear whether the parameter is
in, out or inout and who allocates and deallocates it!!!



Now we change the structure to

      struct fddi_bla
       {
         int var1;
         int var2;

         fddi_bla_t* prev;
         fddi_bla_t* next;

         int private_var_of_P2;
       };


How shall P1 set the private_var_of_P2? If it is not an integer but
an internal structure of P2 how can P1 know about?

What about prev and next. P1 does not use it. Maybe it holds
elements of this struct in a tree. Shall we add a parent pointer
and a child vector to the fddi_bla struct, too?


P1 also has private data. Must the structure be extended?


I think that a clear interface without any implementation (except
the "void* impl" for C) is the best way to avoid the problems
mentioned above. The dependency is decoupled.

Thomas


More information about the ag-automation mailing list