An excursion to pseudo-polymorphism

Discussion in 'C Programming' started by guillemort@gmail.com, Jul 18, 2006.

  1. Guest

    We have a system of small objects in the lines of

    typedef struct {
    ...
    } text_object;

    And we have a "object master" that serves as a container for
    several of these small objects, in the lines of

    typedef struct {
    ...
    text_object *text;
    media_object *media;
    ...
    } object_master;

    Now, we need a generic/polymorphic way to initialise the small objects
    as the initialisation is similar for all of them. I would like to use
    inlined functions instead of macros for that, but currently don't see
    any natural, clean way for it. A pseudo-implementation with a macro
    (ALLOC_OBJ) is provided below.

    Any ideas for converting that macro to an inline function?

    my_error alloc_text(object_master *om, params* pms)
    {
    my_errcode err = 0;
    text_object *to;
    ALLOC_OBJ(om, to, textobj, TEXT_OBJECT_TYPE, pms);
    return err;
    }

    my_error alloc_text(object_master *om, params* pms)
    {
    my_errcode err = 0;
    media_object *mo;
    ALLOC_OBJ(om, mo, mediaobj, MEDIA_OBJECT_TYPE, pms);
    return err;
    }

    #define ALLOC_OBJ(objmaster, gen_obj, gen_obj_field, gen_obj_type,
    params)
    {
    my_ASSERT(obj != NULL);
    my_ASSERT(params != NULL);

    gen_obj = my_malloc(sizeof(*gen_obj));
    if (! gen_obj)
    return ERR_OOM;

    my_memset(gen_obj, 0, sizeof(*gen_obj));

    gen_obj->module = my_module_find(params);
    if (! gen_obj->module) {
    err = ERR_MISSING_MODULE;
    goto out_free_gen_obj;
    }
    if (my_typeof(gen_obj->module) != gen_obj_type) {
    err = ERR_WRONG_MODULE;
    goto out_free_gen_obj;
    }

    err = gen_obj->module->mod_init(gen_obj, params);
    if (err)
    goto out_free_gen_obj;

    goto out;

    out_free_gen_obj:
    my_memset(gen_obj, 0, sizeof(*gen_obj));
    my_free(gen_obj);
    gen_obj = NULL;

    out:
    /* especially rigorous w/o a macro */
    objmaster->gen_obj_field = gen_obj;
    }
     
    , Jul 18, 2006
    #1
    1. Advertising

  2. Tom St Denis Guest

    wrote:
    > We have a system of small objects in the lines of
    >
    > typedef struct {
    > ...
    > } text_object;



    You're trying to emulate C++, the best way is to use a plugin model.
    Prepare structures that have the address of functions that do init,
    deinit, etc. Then just call through them.

    Tom
     
    Tom St Denis, Jul 18, 2006
    #2
    1. Advertising

  3. Guest

    Tom St Denis wrote:
    > wrote:
    > > We have a system of small objects in the lines of
    > >
    > > typedef struct {
    > > ...
    > > } text_object;

    >
    >
    > You're trying to emulate C++, the best way is to use a plugin model.
    > Prepare structures that have the address of functions that do init,
    > deinit, etc. Then just call through them.
    >
    > Tom


    I'm sorry, but this is too vague. I can't see how function pointers can
    help in this case. ALLOC_OBJECT() is the problem, as it's generic. No
    use of making it a "member function" by a function pointer as there is
    nothing object-specifc going on, only identifiers/types change.

    Can you perhaps bring an example?
     
    , Jul 18, 2006
    #3
  4. Tom St Denis Guest

    wrote:
    > I'm sorry, but this is too vague. I can't see how function pointers can
    > help in this case. ALLOC_OBJECT() is the problem, as it's generic. No
    > use of making it a "member function" by a function pointer as there is
    > nothing object-specifc going on, only identifiers/types change.
    >
    > Can you perhaps bring an example?


    http://libtomcrypt.com

    That entire library is pluggable. For instance, my HMAC message
    authentication code ... er source code [hehehe] doesn't know what hash
    you are using. Doesn't know how the hash even works. Just knows it
    can call certain functions to handle the message being hashed.

    Similarly my Public Key code has no clue how your bignum math is done
    [I support three different math libraries, each with their own bignum
    data types, init/deinit functions, etc].

    etc, etc, etc.

    You're just giving up too easily.

    Tom
     
    Tom St Denis, Jul 18, 2006
    #4
  5. Guest

    Tom St Denis wrote:
    > wrote:
    > > I'm sorry, but this is too vague. I can't see how function pointers can
    > > help in this case. ALLOC_OBJECT() is the problem, as it's generic. No
    > > use of making it a "member function" by a function pointer as there is
    > > nothing object-specifc going on, only identifiers/types change.
    > >
    > > Can you perhaps bring an example?

    >
    > http://libtomcrypt.com
    >
    > That entire library is pluggable. For instance, my HMAC message
    > authentication code ... er source code [hehehe] doesn't know what hash
    > you are using. Doesn't know how the hash even works. Just knows it
    > can call certain functions to handle the message being hashed.
    >
    > Similarly my Public Key code has no clue how your bignum math is done
    > [I support three different math libraries, each with their own bignum
    > data types, init/deinit functions, etc].
    >
    > etc, etc, etc.
    >
    > You're just giving up too easily.
    >
    > Tom


    This is all elementary run-time polymorphism. This case is a little bit
    different and I'm afraid you fail to see the point. Please look at the
    initial post and give your own function version of OBJECT_ALLOCATE()
    that works both with text_objects and media_objects if you want to help.
     
    , Jul 18, 2006
    #5
  6. Tom St Denis Guest

    wrote:
    > This is all elementary run-time polymorphism. This case is a little bit
    > different and I'm afraid you fail to see the point. Please look at the
    > initial post and give your own function version of OBJECT_ALLOCATE()
    > that works both with text_objects and media_objects if you want to help.


    Are you saying you're adding methods that aren't known at compile time?

    Then just do variadic definitions and lookup by name...

    func_int_t insert_int = myplugin->lookup(methodname);
    insert_int(ID, blah, blah, blah);

    I don't care to look at your example because I know that you can
    emulate all basic functions of C++ with C structures.

    You just have to rethink the approach. It won't always be as nice as
    C++ [that's why they invented C++] but you can get the same job done
    regardless.

    Tom
     
    Tom St Denis, Jul 18, 2006
    #6
  7. Guest

    Tom St Denis wrote:
    > I don't care to look at your example because I know that you can
    > emulate all basic functions of C++ with C structures.


    Tom, why did you answer if you have nothing to say? I'll open another
    thread, please don't answer there.
     
    , Jul 19, 2006
    #7
  8. schrieb:
    > We have a system of small objects in the lines of
    >
    > typedef struct {
    > ...
    > } text_object;
    >
    > And we have a "object master" that serves as a container for
    > several of these small objects, in the lines of
    >
    > typedef struct {
    > ...
    > text_object *text;
    > media_object *media;
    > ...
    > } object_master;
    >
    > Now, we need a generic/polymorphic way to initialise the small objects
    > as the initialisation is similar for all of them. I would like to use
    > inlined functions instead of macros for that, but currently don't see
    > any natural, clean way for it. A pseudo-implementation with a macro
    > (ALLOC_OBJ) is provided below.


    You want templates for this, don't you? In C, you could use a structure,
    that contains the common parts:

    /* "common" or "base" object */
    typedef struct
    {
    void* module;
    } gen_object;

    /* specific object */
    typedef struct
    {
    void* module;
    void* media_data;
    } media_object;

    my_error alloc_media(object_master *om, params* pms)
    {
    my_errcode err = 0;
    media_object *mo;
    /* ALLOC_OBJ(om, to, textobj, MEDIA_OBJECT_TYPE, pms); */
    alloc_obj((gen_object**)&mo, sizeof *mo, MEDIA_OBJECT_TYPE, pms);
    om->media = mo;

    return err;
    }

    void alloc_obj(gen_object** obj, size_t size, int type, params* pms)
    {
    /* no error checking done */
    *obj = my_malloc(size);

    my_memset(*obj, 0, size);

    (*obj)->module = my_module_find(params);

    /* ... */
    }

    --
    Thomas
     
    Thomas J. Gritzan, Jul 19, 2006
    #8
  9. Guest

    Thomas J. Gritzan wrote:

    > You want templates for this, don't you?


    Exactly. I should have explicitly pointed that out.

    > In C, you could use a structure,
    > that contains the common parts:


    Well, yes, but it is a little fragile. It seems it is safest to just
    stick to the macro. Looks like templates are best emulated with macros,
    even though macros are infamous. Like goto that is notoriously
    ill-famed, but still useful for try/catch-like error handling. Any
    objections?

    Thanks for the example, it looks nice and does exactly what I wanted.
    However, it seems the macro provides better compile-time safety as no
    casts are involved and pointers retain their "identity". I hoped that a
    function can be generically used without loosing pointer identity (i.e.
    compiler knows the pointer type and hence the pointed-to struct size),
    postponing the obvious though in the back of my mind --- it is
    impossible. Well, it is impossible and I should not have started this
    discussion at all.
     
    , Jul 21, 2006
    #9
  10. Bill Pursell Guest

    wrote:
    > Thomas J. Gritzan wrote:
    >
    > > You want templates for this, don't you?

    >
    > Exactly. I should have explicitly pointed that out.
    >
    > > In C, you could use a structure,
    > > that contains the common parts:

    >
    > Well, yes, but it is a little fragile. It seems it is safest to just
    > stick to the macro. Looks like templates are best emulated with macros,
    > even though macros are infamous. Like goto that is notoriously
    > ill-famed, but still useful for try/catch-like error handling. Any
    > objections?
    >
    > Thanks for the example, it looks nice and does exactly what I wanted.
    > However, it seems the macro provides better compile-time safety as no
    > casts are involved and pointers retain their "identity". I hoped that a
    > function can be generically used without loosing pointer identity (i.e.
    > compiler knows the pointer type and hence the pointed-to struct size),
    > postponing the obvious though in the back of my mind --- it is
    > impossible. Well, it is impossible and I should not have started this
    > discussion at all.


    NO! You absolutely should have started the discussion. I enjoyed
    reading the examples, so even if you didn't get exactly what you
    wanted, me (and undoubtedly other thread lurkers) reaped some
    benefit.

    I was recently playing around with some similar ideas and
    had hoped that typedef'ing the void * would generate a
    compiler warning, but was unable to coerce any warnings. eg

    typedef void * foo;
    typedef void * bar;

    void f(foo a) {return;}
    void g(bar a) {return;}

    int main(void)
    {
    foo a;
    bar b;
    f(b);
    g(a);
    return 0;
    }

    Does anyone know a compiler that will warn here? Better
    yet, can I coerce a warning out of gcc?
     
    Bill Pursell, Jul 22, 2006
    #10
  11. On 21 Jul 2006 22:42:50 -0700, "Bill Pursell" <>
    wrote:
    <snip>
    > I was recently playing around with some similar ideas and
    > had hoped that typedef'ing the void * would generate a
    > compiler warning, but was unable to coerce any warnings. eg


    Nope. typedef in C is strictly an alias, not a distinct type.

    The only way to create a distinct new type in C is as a struct or
    union, or which the former is more familiar and usually more useful.
    (Chris Torek likes to retroform 'struct' as a humorous acronym for
    'STRange spelling for User Constructed Type'.)

    <OT> In C++ enum types are also distinct, although they still silently
    convert to but not from integers; and all class/struct, union, and
    enum tags are automatically usable as typenames without being
    explicitly declared as typedefs; but typedefs are still aliases.

    And of course class/struct types already have true, builtin,
    hierarchical polymorphism. If that's what you want. </>

    - David.Thompson1 at worldnet.att.net
     
    Dave Thompson, Jul 31, 2006
    #11
  12. Dave Thompson <> writes:
    > On 21 Jul 2006 22:42:50 -0700, "Bill Pursell" <>
    > wrote:
    > <snip>
    >> I was recently playing around with some similar ideas and
    >> had hoped that typedef'ing the void * would generate a
    >> compiler warning, but was unable to coerce any warnings. eg

    >
    > Nope. typedef in C is strictly an alias, not a distinct type.
    >
    > The only way to create a distinct new type in C is as a struct or
    > union, or which the former is more familiar and usually more useful.
    > (Chris Torek likes to retroform 'struct' as a humorous acronym for
    > 'STRange spelling for User Constructed Type'.)
    >
    > <OT> In C++ enum types are also distinct, although they still silently
    > convert to but not from integers; and all class/struct, union, and
    > enum tags are automatically usable as typenames without being
    > explicitly declared as typedefs; but typedefs are still aliases.
    >
    > And of course class/struct types already have true, builtin,
    > hierarchical polymorphism. If that's what you want. </>


    Actually, enumerated types are distinct in C as well -- but the
    enumeration constants are of type int, not of the enum type. For
    example:

    enum foo { zero, one, two };
    enum foo *fp;
    int *ip;
    ip = fp; /* illegal */

    For that matter, a declaration of a pointer, array, or function type
    creates a distinct new type. (The language has no facility for
    declaring new numeric types.) But structures are the most flexible
    form of new types, since they can contain whatever else you need them
    to.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Jul 31, 2006
    #12
  13. Ian Collins Guest

    Keith Thompson wrote:
    > Dave Thompson <> writes:
    >
    >>On 21 Jul 2006 22:42:50 -0700, "Bill Pursell" <>
    >>wrote:
    >><snip>
    >>
    >>>I was recently playing around with some similar ideas and
    >>>had hoped that typedef'ing the void * would generate a
    >>>compiler warning, but was unable to coerce any warnings. eg

    >>
    >>Nope. typedef in C is strictly an alias, not a distinct type.
    >>
    >>The only way to create a distinct new type in C is as a struct or
    >>union, or which the former is more familiar and usually more useful.
    >>(Chris Torek likes to retroform 'struct' as a humorous acronym for
    >>'STRange spelling for User Constructed Type'.)
    >>
    >><OT> In C++ enum types are also distinct, although they still silently
    >>convert to but not from integers; and all class/struct, union, and
    >>enum tags are automatically usable as typenames without being
    >>explicitly declared as typedefs; but typedefs are still aliases.
    >>
    >>And of course class/struct types already have true, builtin,
    >>hierarchical polymorphism. If that's what you want. </>

    >
    >
    > Actually, enumerated types are distinct in C as well -- but the
    > enumeration constants are of type int, not of the enum type. For
    > example:
    >
    > enum foo { zero, one, two };
    > enum foo *fp;
    > int *ip;
    > ip = fp; /* illegal */
    >

    But they are effectively a type in name only in C, by virtue of

    enum foo f;

    f = 42;

    --
    Ian Collins.
     
    Ian Collins, Jul 31, 2006
    #13
  14. Ian Collins <> writes:
    > Keith Thompson wrote:
    >> Dave Thompson <> writes:

    [...]
    >> Actually, enumerated types are distinct in C as well -- but the
    >> enumeration constants are of type int, not of the enum type. For
    >> example:
    >>
    >> enum foo { zero, one, two };
    >> enum foo *fp;
    >> int *ip;
    >> ip = fp; /* illegal */
    >>

    > But they are effectively a type in name only in C, by virtue of
    >
    > enum foo f;
    >
    > f = 42;


    That's merely because there's an implicit conversion between int and
    enum foo. C is full of implicit conversions: between void* and any
    pointer-to-object type, between any two numeric types, from a null
    pointer constant to any pointer type.

    A *value* of type enum foo is pretty much interchangeable with any
    integer type. An *object* of type enum foo is not. In that sense,
    it's a distinct type.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Jul 31, 2006
    #14
  15. Ian Collins Guest

    Keith Thompson wrote:
    > Ian Collins <> writes:
    >
    >>Keith Thompson wrote:
    >>
    >>>Dave Thompson <> writes:

    >
    > [...]
    >
    >>>Actually, enumerated types are distinct in C as well -- but the
    >>>enumeration constants are of type int, not of the enum type. For
    >>>example:
    >>>
    >>> enum foo { zero, one, two };
    >>> enum foo *fp;
    >>> int *ip;
    >>> ip = fp; /* illegal */
    >>>

    >>
    >>But they are effectively a type in name only in C, by virtue of
    >>
    >>enum foo f;
    >>
    >>f = 42;

    >
    >
    > That's merely because there's an implicit conversion between int and
    > enum foo. C is full of implicit conversions: between void* and any
    > pointer-to-object type, between any two numeric types, from a null
    > pointer constant to any pointer type.
    >
    > A *value* of type enum foo is pretty much interchangeable with any
    > integer type. An *object* of type enum foo is not. In that sense,
    > it's a distinct type.
    >

    Can you flesh out "An *object* of type enum foo is not" with an example?
    I'm not quite sure of the context.

    --
    Ian Collins.
     
    Ian Collins, Jul 31, 2006
    #15
  16. Ben Pfaff Guest

    Ian Collins <> writes:

    > Keith Thompson wrote:
    >> A *value* of type enum foo is pretty much interchangeable with any
    >> integer type. An *object* of type enum foo is not. In that sense,
    >> it's a distinct type.
    >>

    > Can you flesh out "An *object* of type enum foo is not" with an example?
    > I'm not quite sure of the context.


    If we have:
    enum foo { zero, one, two } enum_object;
    int int_object;
    then &object is not compatible with &int_object. In fact,
    enum_object and int_object might not have the same size.
    --
    "For those who want to translate C to Pascal, it may be that a lobotomy
    serves your needs better." --M. Ambuhl

    "Here are the steps to create a C-to-Turbo-Pascal translator..." --H. Schildt
     
    Ben Pfaff, Jul 31, 2006
    #16
    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. le Cl?
    Replies:
    15
    Views:
    3,143
    Michel
    Apr 11, 2009
  2. Krivenok Dmitry
    Replies:
    13
    Views:
    1,447
    Axter
    Jun 1, 2006
  3. Ron Ford

    Re: A CT&P excursion - beat it up!

    Ron Ford, Jun 7, 2008, in forum: C Programming
    Replies:
    10
    Views:
    491
  4. Re: A CT&P excursion - beat it up!

    , Jun 7, 2008, in forum: C Programming
    Replies:
    3
    Views:
    271
    Richard Tobin
    Jun 7, 2008
  5. Rainer Weikusat

    a logic excursion

    Rainer Weikusat, Mar 22, 2013, in forum: Perl Misc
    Replies:
    3
    Views:
    182
    Rainer Weikusat
    Mar 22, 2013
Loading...

Share This Page