1

I have recently stumbled on this curious thought while handling a C code.
I have written a function which returns a double and takes in as argument the pointer to a function and a certain number of parameters, namely

double template_1(double (*)(double),...);

this function correctly identifies a certain property of a real function

 double f(double ); 

represented as a pointer in template_1, in order to maketemplate_1 valid for every real function I might plug-in.

Now I had to write another function, let it be:

double derivative(double (*)(double),double);

double derivative(double (*f)(double),double x){

    double epsilon = ...; 

    return ( f(x+epsilon)-f(x-epsilon) )/(2.0*epsilon);
}

again with f in the argument to make it work for every f. My question is: since I would like to use derivative in template_1 without modifying it, is it possible to write a function which takes derivative and spits out something that has the form of double (*)(double ) ?

My idea was to define typedef double (*real_function)(double); and then to define

real_function g(double (*derivative)(double (*)(double),double ) )

which I'd like it to spit out something like: double derivative_2(double x); so that I could define something like g(derivative) = double (*h)( double); directly in template_1 argument unfortunately I don't have the faintest idea of how to make this work, or even if it can work.

Clijsters
  • 4,031
  • 1
  • 27
  • 37
Fra
  • 161
  • 8
  • It would be possible only in case this returned function is defined already. No, you can't "define" functions in the runtime. You will have to switch to some functional language such as Haskell or Lisp for this. – Eugene Sh. Mar 27 '17 at 19:27
  • There's no (portable) way to create a function at runtime in C. – Paul Hankin Mar 27 '17 at 19:27
  • @EugeneSh. most languages, and not just functional ones, support this (at least in some form) -- for example C++, java, go. – Paul Hankin Mar 27 '17 at 19:30
  • @PaulHankin Wasn't sure about that. I am familiar with functional ones more :) Higher order functions and currying is just very natural there. – Eugene Sh. Mar 27 '17 at 19:33
  • Post needs title re-statement. "is it possible to write a function which returns a pointer to a function different from the function in its argument?" Sure, `real_function foo(real_function rf, ...) { return exp; }` is a positive answer to the question, but likely not what OP wants per the body of the post. – chux - Reinstate Monica Mar 27 '17 at 19:36
  • 2
    You are basically asking for some sort of stateful function, which you can realize in C by adding an opaque context parameter to each of your functions and which you use to store the state in. – Kerrek SB Mar 27 '17 at 19:51
  • I'm not sure I did understand, could you please expand on what you mean or point to some reference? thank you! – Fra Mar 27 '17 at 19:57

3 Answers3

2

There are a couple ways to do anonymous functions in C. As the comments said, they aren't portable. But depending on the use case you may find this useful: Anonymous functions using GCC statement expressions

A couple of people have seemed to have similar issues, not sure how portable they are but they may be resourceful: https://github.com/graphitemaster/lambdapp https://github.com/Leushenko/C99-Lambda

Basically, if there's a way to architect your program in a way that doesn't require anonymous functions, then do it that way. If you have no other option, then I would give one of these a shot.

Community
  • 1
  • 1
Ronin
  • 2,867
  • 3
  • 14
  • 14
1

If you have a function my_fancy_function:

double my_fancy_function (double x) { return sin(x) + cos(x); }

Then, you can use a helper macro that creates the derived function for you.

#define DEFINE_DERIVATIVE_OF(FUNC) \
double derivative_of_ ## FUNC (double x) { \
    return derivative(FUNC, x); \
}

DEFINE_DERIVATIVE_OF(my_fancy_function)

You then pass this newly defined function to your template.

template_1(derivative_of_my_fancy_function, x, y, z);
jxh
  • 69,070
  • 8
  • 110
  • 193
1

Warning: I am a C++ developer with little C knowledge so everything that follows is likely unidiomatic C.

As KerrekSB said, you would need to carry some state with your function. This is not possible with raw functions but you can define a struct that carries the state and add a function that works with this struct. This obviously has the drawback of losing the nice function call syntax. I whipped up an example:

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

typedef double (*raw_fptr)(double);
struct real_function;
typedef double (*evaluate_function)(struct real_function*, double);

struct real_function {
        evaluate_function evaluate;
};
typedef struct real_function real_function;

double evaluate(real_function *f, double x) {
        if(f) {
                return f->evaluate(f, x);
        }
        return NAN;
}

struct raw_real_function {
        real_function real_function_base;
        raw_fptr raw_function;
};
typedef struct raw_real_function raw_real_function;

double evaluate_raw_real_function(real_function *f_base, double x) {
        if(f_base) {
                raw_real_function *f = (raw_real_function*)f_base;
                return f->raw_function(x);
        }
        return NAN;
}

raw_real_function make_raw_real_function(raw_fptr function) {
        raw_real_function result;
        result.raw_function = function;
        result.real_function_base.evaluate = evaluate_raw_real_function;
        return result;
}

struct derive_real_function {
        real_function real_function_base;
        real_function *function_to_derive;
};
typedef struct derive_real_function derive_real_function;

double derive(real_function *f_base, double x) {
        derive_real_function *f = (derive_real_function*)f_base;
        double epsilon = 1e-3;
        double upper = evaluate(f->function_to_derive, x+epsilon);
        double lower = evaluate(f->function_to_derive, x-epsilon);
        double result =  (upper - lower)/(2.0*epsilon);
        return result;
}

derive_real_function make_derivative(real_function * function_to_derive) {
        derive_real_function result;
        result.real_function_base.evaluate = derive;
        result.function_to_derive = function_to_derive;
        return result;
}

double x_cubed(double x) {
        return x * x * x;
}

int main(int argc, char **argv) {
        raw_real_function x_cubed_wrapped = make_raw_real_function(x_cubed);
        derive_real_function derived = make_derivative(&x_cubed_wrapped.real_function_base);
        derive_real_function derived_twice = make_derivative(&derived.real_function_base);
        double x = atof(argv[1]);
        double derivative = evaluate(&derived.real_function_base, x);
        double second_derivative = evaluate(&derived_twice.real_function_base, x);
        printf("derivative of x^3 at %f = %f\n", x, derivative);
        printf("second derivative of x^3 at %f = %f\n", x, second_derivative);
        return 0;
}

See (a slight variaton, due to input limitations) running here.

How does it work? I faked some inheritance with the structs real_function, raw_real_function and derive_real_function to generate virtual function calls. The struct real_function serves as the container of a virtual function table consisting of only the entry evaluate. This function pointer points to the "derived" structs' relevant evaluate function:

raw_real_function instances point to evaluate_raw_real_function (as initialized in make_raw_real_function. derive_real_function instances point evaluate to derive (as initialized in make_derivative).

When calling evaluate on the real_function_base member, it will call the associated evaluation function, which casts the real_function* to it's associated struct pointer and does what is needed with that information.

Since everything is just a real_function*, we can chain them at will but need to convert "normal" functions into the real_function format, that's what make_raw_real_function does.

  • It took me quite a while to understand the answer, thank you very much. I guess the main lesson here is that I'll learn more about C++ – Fra Apr 24 '17 at 19:58