-1

The question is based on a design pattern solution easily doable in other languages but difficult to implement in C. The narrowed down code is below.

Building on this answer, I'm trying to find a solution for the dynamically generated values in an anonymous function.

Excerpt from the answer:

int (*max)(int, int) =
({
    int __fn__ (int x, int y) { return x > y ? x : y; }
    __fn__;
});

Static Library Code

struct Super{
}

void add(struct Super *(*superRef)()) {
    // cache the reference (in some linked list)

    // later at some point when an event occurs.
    struct Super *super = superRef(); // instantiate and use it.
}

Client Code linked: User of the Library Code

struct Sub{
     struct Super *super;
}

add(({
    struct Sub __fn__() { return malloc(sizeof(struct Sub)); } // error
    __fn__;
}));

Error:

error: passing 'void' to parameter of incompatible type 'struct Sub *(*)()

As per the request for clarification, think of the receiving function in a static library file receiving references to the structure objects (non-instantiated). The lib receives this object from the client code.

Secondly the client or static library library doesn't instantiate the received structure reference right away. Later when there's a notification in the system, the structure reference is called to instantiate and execute the rest of the stuff.

I repeat, the specific requirement is to hold non-instantiated references to the structures passed by users of the library (client code).

Summary

Basically a Runner that receives pointer to a polymorphic factory method which it caches and later calls to instantiate and executes when an event occurs.

halfer
  • 19,824
  • 17
  • 99
  • 186
Developer
  • 924
  • 3
  • 14
  • 30
  • @DavyM I've edited with details, can you please copy/paste the code and compile to see error and provide a fix if possible. – Developer Jan 27 '18 at 02:35
  • 1
    That isn’t remotely standard C. Your specific compiler may be able to help, but the result won’t be portable. You’ve not identified the compiler, so it’s hard to know what else to say. – Jonathan Leffler Jan 27 '18 at 02:49
  • if there's an alternate solution or lateral thinking using Standard C, I'd prefer then to wipe above and go with the solution. The requirement is to build a static library that can receive references to `structs` defined in the client (user of the library) code and the static library can instantiate them. – Developer Jan 27 '18 at 02:54
  • 2
    Other languages where you can do this presumably allow a function to return a reference, and expressions employ reference semantics by default. C supports neither. The closest you can get will involve your function returning a pointer (which will also address the compiler diagnostic). Also note that identifiers with double underscores are reserved in C and any user code (like yours) which uses them therefore has undefined behaviour. – Peter Jan 27 '18 at 02:55
  • 3
    I'm in favor of searching for the alternate solution, since the statement-expression macro looks nasty. But the underlying goal is hard to understand. C doesn't have anonymous functions, doesn't have references either unless the word "reference" is simply being used as a synonym for "pointer", and I wouldn't bet on C having "non-instantiated references" either, if I could even figure out what that means. –  Jan 27 '18 at 03:27
  • Please read [MCVE]. Whatever `*(*subRef)()` is, it does not accept a parameter that can be implicitly cast to void. Hard to say anything else about it without an MCVE. The code you have there is not valid C or C++. – jwdonahue Jan 27 '18 at 03:44
  • I'm new and of course you guys knows better, however, let me narrow down more. In oop languages like java, c# we have interfaces and we can pass any object of the class that implements the interface, can we achieve something similar? like passing two different structs and each one having a member variable as a function pointer similar in it's signature. I understand C is not oop but is it possible? – Developer Jan 27 '18 at 03:44
  • Sure, just declare structures with similar function pointer fields and pass around pointers to the structures. – jwdonahue Jan 27 '18 at 03:46
  • @jwdonahue but receiver (static library) has no definition of these structures. It's the user of the library who will be creating structure with similar function pointers, in that case what would be function argument of the receiving function (defined in the library)? – Developer Jan 27 '18 at 03:47
  • Search for [simulated polymorphism in C](https://www.google.com/search?source=hp&ei=yvZrWpOSHZT0jwOzlJvACw&q=simulate+polymorphism+in+c&oq=simulated+polymo&gs_l=psy-ab.1.1.0i22i30k1l2.856.4862.0.8296.16.16.0.0.0.0.150.1078.14j2.16.0....0...1.1.64.psy-ab..0.16.1077...0j46j0i131k1j0i46k1j0i22i10i30k1.0.E-hzcRo5Kwg). Lots of examples. Basically, your function would take a void * because you can convert between them and any pointer type in C. – jwdonahue Jan 27 '18 at 03:51
  • Possible duplicate of [How can I simulate OO-style polymorphism in C?](https://stackoverflow.com/questions/524033/how-can-i-simulate-oo-style-polymorphism-in-c) – jwdonahue Jan 27 '18 at 03:54
  • thanks, I'm going to look deep into this, thanks for the link again. – Developer Jan 27 '18 at 03:56
  • guys, let me get back to you again, I pondered deep, the requirement is that the structure passed from client code to the library has to be in a non-instantiated state. On certain notification library code is going to call this anonymous function to trigger the instantiation. I know we have been going back and forth but if you can kindly review this line and make it work with malloc, it'd solve my problem. line below. I copied it from my function `addSub`. @jwdonahue I've edited the `addSub` function itself to meet MCVE. – Developer Jan 27 '18 at 08:30
  • `({ struct Sub __fn__() { return malloc(sizeof(struct Sub)); } __fn__; })` – Developer Jan 27 '18 at 08:31
  • I've also refined my question and the code and was able to get closer to what I want to achieve, please have a look at the code again. Thanks again for all the help. – Developer Jan 27 '18 at 08:41
  • Summary: The point is user can't instantiate it's structure, library is responsible to instantiate it. Because instantiation happens at a later point when some event occurs. Hope this helps. – Developer Jan 27 '18 at 08:48
  • please see my answer. Able to provide a factory method to the library. Instead of passing subtract (defined outside the library and in the user code), I'm manually overriding the run method to achieve polymorphism. – Developer Jan 29 '18 at 23:21
  • The Dropbox link is again dead. I will remove it from the question. External links to temporary file lockers are discouraged for this reason. – halfer May 04 '19 at 08:11

4 Answers4

2

The correct order is:

  1. learn C
  2. do magic

It just will not work in the other way. ({}) does not bend the semantics for you. If your add expects a function which returns struct Super*, it will not work with struct Sub, not even if you put the missing * there.

This just works on TutorialsPoint:

#include <stdio.h>
#include <stdlib.h>

int max(int a,int b){
    if(a>b)
        return a;
    return b;
}

struct Super{};

void add(struct Super *(*superRef)()) {
    struct Super *(*secretStorage)()=superRef;
    /* ... */
    struct Super *super = secretStorage();
    /* ... */
    free(super);
    printf("Stillalive\n");
}

int main()
{
    printf("Hello, World!\n");

    int (*myMax)(int,int); // <-- that is a function pointer

    myMax=max;             // <-- set with oldschool function
    printf("%d\n",myMax(1,2));

    myMax = ({             // <-- set with fancy magic
        int __fn__ (int x, int y) { return x < y ? x : y; }
        __fn__;
    });    
    printf("%d - intentionally wrong\n",myMax(1,2));

    add(
        ({
            struct Super* fn(){
                printf("Iamhere\n");
                return malloc(sizeof(struct Super));
            }
            fn;}));
    printf("Byfornow\n");
    return 0;
}

Created a small library project with anonymous magic embedded in anonymous magic and heap allocation. It does not make much sense, but it works:

testlib.h

#ifndef TESTLIB_H_
#define TESTLIB_H_

struct Testruct{
    const char *message;
    void (*printmessage)(const char *message);
};

extern struct Testruct *(*nonsense())();

#endif

testlib.c

#include "testlib.h"
#include <stdio.h>
#include <stdlib.h>

const char *HELLO="Hello World\n";

struct Testruct *(*nonsense())(){
    return ({
        struct Testruct *magic(){
            struct Testruct *retval=malloc(sizeof(struct Testruct));
            retval->message=HELLO;
            retval->printmessage=({
                void magic(const char *message){
                    printf(message);
                }
                magic;
            });
            return retval;
        }
        magic;
    });
}

test.c

#include "testlib.h"
#include <stdio.h>
#include <stdlib.h>

int main(){
    struct Testruct *(*factory)()=nonsense();
    printf("Alive\n");
    struct Testruct *stuff=factory();
    printf("Alive\n");
    stuff->printmessage(stuff->message);
    printf("Alive\n");
    free(stuff);
    printf("Alive\n");
    return 0;
}

I followed the steps in https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html for building an running it (practically 3 gcc calls: gcc -c -Wall -Werror -fpic testlib.c, gcc -shared -o libtestlib.so testlib.o, gcc -L. -Wall -o test test.c -ltestlib and a bit of fight with LD_LIBRARY_PATH)

tevemadar
  • 12,389
  • 3
  • 21
  • 49
  • thanks for the attempt, i'm going to upload a small isolated project based on the question, and upload to dropbox for you to review. – Developer Jan 28 '18 at 03:46
  • the problem is that you are executing both things in the same file, please review that i've two different execution contexts. One piece of code is in the library and the other in the code linked to the library, the solution just won't work. I'll work on an isolated project example. – Developer Jan 28 '18 at 03:50
  • hi, thanks for your continued help, I've added some details at the top of my question and created a small isolated project, hope this helps. Kindly download from https://www.dropbox.com/s/42pndsa75a0ylpv/Test.zip?dl=0 – Developer Jan 28 '18 at 10:29
  • ignore the last link please. update test project link. https://www.dropbox.com/s/gl9reb4g0mfa2gs/Test.zip?dl=0 – Developer Jan 29 '18 at 05:11
  • please see my answer. – Developer Jan 29 '18 at 23:26
  • @Developer I have not seen the dropbox stuff yet, but based on the description created some test code where the anonymous magic resides in a library, and it works as expected. You can find it below the horizontal separator line. While libraries and dynamic/shared libraries affect how the application is built and loaded, they have little to no effect on actual execution - when the executable code finally arrives into the memory, it just runs, its origin does not matter. Also, you have syntax errors, which happen in the source code. Source code does not know if it will end up in a library or not – tevemadar Jan 30 '18 at 00:03
  • I think there's a gap, the magic method comes from the user of the library. Please have a look at my answer. All code related to library lives in the src and the user of the library is in the test. Please specify where is the syntax error so i can fix. – Developer Jan 30 '18 at 00:09
  • also i've a problem understanding when you don't use my code – Developer Jan 30 '18 at 00:19
1

The code shown in the question is not standard C, but the GNU C variant that GCC supports. Unfortunately, there does not seem to be a tag, to correctly specify the variant of C involved.

Furthermore, the use case seems to rely on shoehorning specific type of object-oriented paradigm into a C library interface. This is horrible, because it involves assumptions and features C simply does not have. There is a reason why C (and GNU-C) and C++ and Objective-C are different programming languages.

The simple answer to "functions returning dynamically allocated values" where the type of the value is opaque to the library, is to use void *, and for function pointers, (void *)(). Note that in POSIX C, void * can also hold a function pointer.

The more complex answer would describe how libraries like GObject support object-oriented paradigms in C.

In practice, especially in POSIX C, using a type tag (usually int, but can be any other type) and an union, one can implement polymorphic structures, based on an union of structures with all having that type tag as the same first element. The most common example of such functionality is struct sockaddr.

Basically, your header file defines one or more structures with the same initial member, for example

enum {
    MYOBJECT_TYPE_DOUBLE,
    MYOBJECT_TYPE_VOID_FUNCTION,
};

struct myobject_double {
    int     type;  /* MYOBJECT_TYPE_DOUBLE */
    double  value;
};

struct myobject_void_function {
    int     type;  /* MYOBJECT_TYPE_VOID_FUNCTION */
    void  (*value)();
};

and at the end, an union type, or a structure type with an anonymous union (as provided by C11 or GNU-C), of all the structure types,

struct myobject {
    union {
        struct { int type; };          /* for direct 'type' member access */ 
        struct myobject_double         as_double;
        struct myobject_void_function  as_void_function;
    };
};

Note that technically, wherever that union is visible, it is valid to cast any pointer of any of those structure types to another of those structure types, and access the type member (see C11 6.5.2.3p6). It is not necessary to use the union at all, it suffices for the union to be defined and visible.

Still, for ease of maintenance (and to avoid arguments with language lawyer wannabes who did not read that paragraph in the C standard), I do recommend using the structure containing the anonymous union as the "base" type in the library interface.

For example, the library might provide a function to return the actual size of some object:

size_t myobject_size(struct myobject *obj)
{
    if (obj) 
        switch (obj->type) {
        case MYOBJECT_TYPE_DOUBLE:        return sizeof (struct myobject_double);
        case MYOBJECT_TYPE_VOID_FUNCTION: return sizeof (struct myobject_void_function);
        }
    errno = EINVAL;
    return 0;
}

It seems to me OP is trying to implement a factory pattern, where the library function provides the specification (class in OOP) for the object created, and a method to produce those objects later.

The only way in C to implement dynamic typing is via the kind of polymorphism I show above. This means that the specification for the future objects (again, class in OOP) must be an ordinary object itself.

The factory pattern itself is pretty easy to implement in standard C. The library header file contains for example

#include <stdlib.h>

/*
 * Generic, application-visible stuff
*/

struct any_factory {

    /* Function to create an object */
    void *(*produce)(struct any_factory *);

    /* Function to discard this factory */
    void  (*retire)(struct any_factory *);

    /* Flexible array member; the actual
       size of this structure varies. */
    unsigned long  payload[];
};

static inline void *factory_produce(struct any_factory *factory)
{
    if (factory && factory->produce)
        return factory->produce(factory);

    /* C has no exceptions, but does have thread-local 'errno'.
       The error codes do vary from system to system. */
    errno = EINVAL;
    return NULL;
}

static inline void factory_retire(struct any_factory *factory)
{
    if (factory) {
        if (factory->retire) {
            factory->retire(factory);
        } else {
            /* Optional: Poison function pointers, to easily
                         detect use-after-free bugs. */
            factory->produce = NULL;
            factory->retire = NULL; /* Already NULL, too. */
            /* Free the factory object. */
            free(factory);
        }
    }
}

/*
 * Library function.
 *
 * This one takes a pointer and size in chars, and returns
 * a factory object that produces dynamically allocated
 * copies of the data.
*/

struct any_factory *mem_factory(const void *, const size_t);

where factory_produce() is a helper function which invokes the factory to produce one object, and factory_retire() retires (discards/frees) the factory itself. Aside from the extra error checking, factory_produce(factory) is equivalent to (factory)->produce(factory), and factory_retire(factory) to (factory)->retire(factory).

The mem_factory(ptr, len) function is an example of a factory function provided by a library. It creates a factory, that produces dynamically allocated copies of the data seen at the time of the mem_factory() call.

The library implementation itself would be something along the lines of

#include <stdlib.h>
#include <string.h>
#include <errno.h>

struct mem_factory {
    void *(*produce)(struct any_factory *);
    void  (*retire)(struct any_factory *);
    size_t         size;
    unsigned char  data[];
};

/* The visibility of this union ensures the initial sequences
   in the structures are compatible; see C11 6.5.2.3p6.
   Essentially, this causes the casts between these structure
   types, for accessing their initial common members, valid. */
union factory_union {
    struct any_factory  any;
    struct mem_factory  mem;
};

static void *mem_producer(struct any_factory *any)
{
    if (any) {
        struct mem_factory *mem = (struct mem_factory *)any;

        /* We return a dynamically allocated copy of the data,
           padded with 8 to 15 zeros.. for no reason. */
        const size_t  size = (mem->size | 7) + 9;
        char         *result;

        result = malloc(size);
        if (!result) {
            errno = ENOMEM;
            return NULL;
        }

        /* Clear the padding. */
        memset(result + size - 16, 0, 16);

        /* Copy the data, if any. */
        if (mem->size)
            memcpy(result, mem->data, size);

        /* Done. */
        return result;
    }

    errno = EINVAL;
    return NULL;
}

static void mem_retirer(struct any_factory *any)
{
    if (any) {
        struct mem_factory *mem = (struct mem_factory *)any;

        mem->produce = NULL;
        mem->retire  = NULL;
        mem->size    = 0;
        free(mem);
    }
}

/* The only exported function:
*/
struct any_factory *mem_factory(const void *src, const size_t len)
{
    struct mem_factory *mem;

    if (len && !src) {
        errno = EINVAL;
        return NULL;
    }

    mem = malloc(len + sizeof (struct mem_factory));
    if (!mem) {
        errno = ENOMEM;
        return NULL;
    }

    mem->produce = mem_producer;
    mem->retire  = mem_retirer;
    mem->size    = len;

    if (len > 0)
        memcpy(mem->data, src, len);

    return (struct any_factory *)mem;
}

Essentially, the struct any_factory type is actually polymorphic (not in the application, but within the library only). All its variants (struct mem_factory here) has the two initial function pointers in common.

Now, if we examine the code above, and consider the factory pattern, you should realize that the function pointers provide very little of value: you could just use the polymorphic type I showed earlier in this answer, and have the inline producer and consumer functions call subtype-specific internal functions based on the type of the factory. factory.h:

#ifndef   FACTORY_H
#define   FACTORY_H
#include <stdlib.h>

struct factory {
    /* Common member across all factory types */
    const int  type;

    /* Flexible array member to stop applications
       from declaring static factories. */
    const unsigned long  data[];
};

/* Generic producer function */
void *produce(const struct factory *);

/* Generic factory discard function */
void retire(struct factory *);

/*
 * Library functions that return factories.
*/

struct factory  *mem_factory(const void *, const size_t);

#endif /* FACTORY_H */

and factory.c:

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "factory.h"

enum {
    INVALID_FACTORY = 0,

    /* List of known factory types */
    MEM_FACTORY,

    /* 1+(the highest known factory type) */
    NUM_FACTORY_TYPES
};

struct mem_factory {
    int     type;
    size_t  size;
    char    data[];
};

/* The visibility of this union ensures the initial sequences
   in the structures are compatible; see C11 6.5.2.3p6.
   Essentially, this causes the casts between these structure
   types, for accessing their initial common members, valid. */
union all_factories {
    struct factory      factory;
    struct mem_factory  mem_factory;
};

/* All factories thus far implemented
   are a single structure dynamically
   allocated, which makes retiring simple.
*/
void retire(struct factory *factory)
{
    if (factory &&
        factory->type > INVALID_FACTORY &&
        factory->type < NUM_FACTORY_TYPES) {
        /* Poison factory type, to make it easier
           to detect use-after-free bugs. */
        factory->type = INVALID_FACTORY;
        free(factory);
    }
}

char *mem_producer(struct mem_factory *mem)
{
    /* As a courtesy for users, return the memory
       padded to a length multiple of 16 chars
       with zeroes. No real reason to do this. */
    const size_t  size = (mem->size | 7) + 9;
    char         *result;   

    result = malloc(size);
    if (!result) {
        errno = ENOMEM;
        return NULL;
    }

    /* Clear padding. */
    memset(result + size - 16, 0, 16);

    /* Copy data, if any. */
    if (mem->size)
        memcpy(result, mem->data, mem->size);

    return result;
}

/* Generic producer function.
   Calls the proper individual producers.
*/
void *factory_producer(struct factory *factory)
{
    if (!factory) {
        errno = EINVAL;
        return NULL;
    }

    switch (factory->type) {

    case mem_factory:
        return mem_producer((struct mem_factory *)factory);

    default:
        errno = EINVAL;
        return NULL;
    }
}

/* Library functions that return factories.
*/
struct factory *mem_factory(const void *ptr, const size_t len)
{
    struct mem_factory *mem;

    if (!ptr && len > 0) {
        errno = EINVAL;
        return NULL;
    }

    mem = malloc(len + sizeof (struct mem_factory));
    if (!mem) {
        errno = ENOMEM;
        return NULL;
    }

    mem->type = MEM_FACTORY;
    mem->size = len;
    if (len > 0)
        memcpy(mem->data, ptr, len);

    return (struct factory *)mem;
}

If we look at standard C and POSIX C library implementations, we'll see that both of these approaches are used.

The standard I/O FILE structure often contains function pointers, and the fopen(), fread(), fwrite(), etc. functions are just wrappers around these. This is especially the case if the C library supports an interface similar to GNU fopencookie().

POSIX.1 socket, especially the struct sockaddr type, is the original prototype for the polymorphic structure shown first in this answer. Because their interface does not support anything similar to fopencookie() (that is, overriding the implementation of e.g. send(), recv(), read(), write(), close()), there is no need for the function pointers.

So, please do not ask which one is more suitable, as both are very commonly used, and it very much depends on minute details.. In general, I prefer the one that yields a simpler implementation providing all the necessary functionality.

I have personally found that it is not that useful to worry about future use cases without practical experience and feedback first. Rather than trying to create the end-all, best-ever framework that solves all future problems, the KISS principle and the Unix philosophy seem to yield much better results.

Nominal Animal
  • 38,216
  • 5
  • 59
  • 86
  • thanks for the answer, I'm a really thrown off, first i'm new to C and second I don't see things related to my code so I can't comprehend the solution – Developer Jan 27 '18 at 07:24
  • I've refined my question, please have a look again – Developer Jan 27 '18 at 08:41
  • 1
    @Developer: The fundamental discontinuity here is the concept of a *"non-instantiated structure"*. There is no such thing in C. There are types, and there are objects of that type. There is no instantiation. You are trying to write code in C like it was some other language, with a completely different paradigm: like speaking slowly but loudly to a non-English speaker, thinking it might help. This approach will not work. – Nominal Animal Jan 27 '18 at 21:57
  • @Developer: However, if this were the only bit that does not translate, you can implement the [factory pattern](https://en.wikipedia.org/wiki/Factory_pattern). The library function then returns the data (polymorphic as in my answer) needed to generate the actual objects later. I'll add an example of that to my answer. – Nominal Animal Jan 27 '18 at 22:01
  • yes, thanks for getting the name of the pattern out of it, yes it's a factory pattern and I need a polymorphic version, all structs will have a function that static library will call after instantiating from the anonymous or closure function passed (i hope i'm not overloading these terms in c), and I'm not that much experienced in C, so a simplest possible example using my code will help me understand better. Please add an addendum to your answer. – Developer Jan 27 '18 at 22:11
  • A tip, i came across this example a bit earlier that i can define a factory function in my .c file instead of using expressions `( { } )` and pass the address of the function as a parameter. Because I felt some resistance in using expression from community saying it's not standard c etc. – Developer Jan 27 '18 at 22:15
  • @Developer: Added the factory example code. The "resistance" you felt you received from the community, is because you are trying to proverbially force a square peg through a triangular hole. The paradigm, the way of looking at problems and solving them, differs a lot between different programming languages (and even more between programming language types -- OOP, functional, procedural programming). To learn how to fully master a programming language, you need to first understand how that language approaches problems. You cannot just use your C# knowledge in C, and assume it should work. – Nominal Animal Jan 27 '18 at 23:36
  • Thanks for your continued support. In order to reach to a point, I've created a small isolated project, hope this will get the point across and a solution. Can you please download it from https://www.dropbox.com/s/42pndsa75a0ylpv/Test.zip I've also added some details at the top of my question. – Developer Jan 28 '18 at 10:28
  • ignore the last link please. update test project link. https://www.dropbox.com/s/gl9reb4g0mfa2gs/Test.zip?dl=0 – Developer Jan 29 '18 at 05:11
  • @Developer: Standard C does not have anonymous functions. In `test/runner_test.c`, just declare the new functions in the file scope. Mark them `static`, and pick an unique name. If it needs context, provide it in a separate variable. From the comments, it looks like you are actually looking for a way to implement [closures](https://en.wikipedia.org/wiki/Closure_(computer_programming)) in C, or perhaps cleanup handlers (like [in pthreads](http://man7.org/linux/man-pages/man3/pthread_cleanup_push.3.html)), rather than just a factory pattern? – Nominal Animal Jan 29 '18 at 06:18
  • alright, I'll change my track and leave anonymous functions out since they are not standard C. However, pointer to functions is standard C, right? If you please notice, `line 38 (test/runner.c)` is a pointer to function (defined in `super.h/.c`), at the minimum if you can help me get this right, I'll consider this resolve. please skip first two tests (line 6 and line 35) and get `testSubRun2` pass. It's throwing segmentation fault. I'll comment out and update the project in a minute. – Developer Jan 29 '18 at 06:47
  • commented out anonymous function based tests, you'll find two pointer to function based implementations, please have a look. Here's the link again just in case. https://www.dropbox.com/s/gl9reb4g0mfa2gs/Test.zip?dl=0 – Developer Jan 29 '18 at 06:54
  • @Developer: I'm having serious difficulties in understanding what on earth you are trying to accomplish. – Nominal Animal Jan 29 '18 at 07:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164068/discussion-between-developer-and-nominal-animal). – Developer Jan 29 '18 at 07:59
  • please see my answer. – Developer Jan 29 '18 at 23:25
0

(Quoting your accepted answer to yourself)

Secondly a pointer to a parent struct can't receive a pointer to it's derived type (Embedded parent struct) so I can't do much there. I tried using void * but perhaps a solution might exists using memory address and then access some member of the struct without casting to specific types. I'll ask that in another question.

This is yet another pointer that one should learn the basics first. The thing you miss is called 'forward declaration':

struct chicken; // here we tell the compiler that 'struct chicken' is a thing
struct egg{
  struct chicken *laidby; // while the compiler knows no details about 'struct chicken',
                          // its existence is enough to have pointers for it
};
struct chicken{           // and later it has to be declared properly
  struct egg *myeggs;
};

What I'm missing is the ability to call the super method from the overridden run method in some way?

These are not methods and there is no override. In your code no OOP happens, C is a procedural programming language. While there are OOP extensions for C, you really should not go for them without knowing C basics.

tevemadar
  • 12,389
  • 3
  • 21
  • 49
-2

First community told me that anonymous functions are not part of C, so the alternate suggestion is to use named functions and pointer to it.

Secondly a pointer to a parent struct can't receive a pointer to it's derived type (Embedded parent struct) so I can't do much there. I tried using void * but perhaps a solution might exists using memory address and then access some member of the struct without casting to specific types. I'll ask that in another question.

What I'm missing is the ability to call the super method from the overridden run method in some way?

src/super.h

struct Super {
    void (*run)();
};

struct Super *newSuper();

src/super.c

static void run() {
    printf("Running super struct\n");
}

struct Super *newSuper() {
    struct Super *super = malloc(sizeof(struct Super));
    super->run = run;
    return super;
}

src/Runner.h

struct Runner {

    void (*addFactoryMethod)(struct Super *(*ref)());

    void (*execute)();
};

struct Runner *newRunner();

src/runner.c

struct Super *(*superFactory)();

void addFactoryMethod(struct Super *(*ref)()) {
    superFactory = ref;
}

static void execute() {
    struct Super *sup = superFactory(); // calling cached factory method
    sup->run();
}

struct Runner *newRunner() {
    struct Runner *runner = malloc(sizeof(struct Runner));
    runner->addFactoryMethod = addFactoryMethod;
    runner->execute = execute;
    return runner;
}

test/runner_test.c

void anotherRunMethod() {
    printf("polymorphism working\n");
    // how can i've the ability to call the overridden super method in here?
}

struct Super *newAnotherSuper() {
    struct Super *super = malloc(sizeof(struct Super));
    super->run = anotherRunMethod;
    return super;
}

void testSuper() {
    struct Runner *runner = newRunner();
    runner->addFactoryMethod(&newAnotherSuper);
    runner->execute();
}

int main() {
    testSuper();
    return 0;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Developer
  • 924
  • 3
  • 14
  • 30
  • I still do not see what problem this is tring to solve; the implementation (code shown above) does not seem to be a sane solution to any particular problem I can discern. It is obviously an attempt at applying OOP concepts in C (which itself is questionable, since C is not an OOP language), but to what *purpose*, I cannot fathom. I would be very interested to hear about the underlying problem this code intends to solve, but thus far, OP has only described what they want the code to do... Which is a completely different thing altogether. – Nominal Animal Jan 30 '18 at 11:03
  • Same. Do not understand the reason of it. Doing this you just write error prone, bad, unreadable code. if you need methods, classes etc etc just use another programming language. – 0___________ Jan 19 '20 at 12:03