Function pointers, Closures, and Lambda

前端 未结 12 1329
臣服心动
臣服心动 2020-11-28 01:51

I am just now learning about function pointers and, as I was reading the K&R chapter on the subject, the first thing that hit me was, \"Hey, this is kinda like a closure

相关标签:
12条回答
  • 2020-11-28 02:45

    Closure = logic + environment.

    For instance, consider this C# 3 method:

    public Person FindPerson(IEnumerable<Person> people, string name)
    {
        return people.Where(person => person.Name == name);
    }
    

    The lambda expression not only encapsulates the logic ("compare the name") but also the environment, including the parameter (i.e. local variable) "name".

    For more on this, have a look at my article on closures which takes you through C# 1, 2 and 3, showing how closures make things easier.

    0 讨论(0)
  • 2020-11-28 02:48

    The main difference arises from the lack of lexical scoping in C.

    A function pointer is just that, a pointer to a block of code. Any non-stack variable that it references is global, static or similar.

    A closure, OTOH, has its own state in the form of 'outer variables', or 'upvalues'. they can be as private or shared as you want, using lexical scoping. You can create lots of closures with the same function code, but different variables instances.

    A few closures can share some variables, and so can be the interface of an object (in the OOP sense). to make that in C you have to associate a structure with a table of function pointers (that's what C++ does, with a class vtable).

    in short, a closure is a function pointer PLUS some state. it's a higher-level construct

    0 讨论(0)
  • 2020-11-28 02:55

    In GCC it is possible to simulate lambda functions using the following macro:

    #define lambda(l_ret_type, l_arguments, l_body)       \
    ({                                                    \
        l_ret_type l_anonymous_functions_name l_arguments \
        l_body                                            \
        &l_anonymous_functions_name;                      \
    })
    

    Example from source:

    qsort (array, sizeof (array) / sizeof (array[0]), sizeof (array[0]),
         lambda (int, (const void *a, const void *b),
                 {
                   dump ();
                   printf ("Comparison %d: %d and %d\n",
                           ++ comparison, *(const int *) a, *(const int *) b);
                   return *(const int *) a - *(const int *) b;
                 }));
    

    Using this technique of course removes the possibility of your application working with other compilers and is apparently "undefined" behavior so YMMV.

    0 讨论(0)
  • 2020-11-28 02:55

    In C a function pointer is a pointer that will invoke a function when you dereference it, a closure is a value that contains a function's logic and the environment (variables and the values they are bound to) and a lambda usually refers to a value that is actually an unnamed function. In C a function is not a first class value so it cannot be passed around so you have to pass a pointer to it instead, however in functional languages (like Scheme) you can pass functions in the same way you pass any other value

    0 讨论(0)
  • 2020-11-28 02:56

    Most of the responses indicate that closures require function pointers, possibly to anonymous functions, but as Mark wrote closures can exist with named functions. Here's an example in Perl:

    {
        my $count;
        sub increment { return $count++ }
    }
    

    The closure is the environment that defines the $count variable. It is only available to the increment subroutine and persists between calls.

    0 讨论(0)
  • 2020-11-28 02:58

    A lambda (or closure) encapsulates both the function pointer and variables. This is why, in C#, you can do:

    int lessThan = 100;
    Func<int, bool> lessThanTest = delegate(int i) {
       return i < lessThan;
    };
    

    I used an anonymous delegate there as a closure (it's syntax is a little clearer and closer to C than the lambda equivalent), which captured lessThan (a stack variable) into the closure. When the closure is evaluated, lessThan (whose stack frame may have been destroyed) will continue to be referenced. If I change lessThan, then I change the comparison:

    int lessThan = 100;
    Func<int, bool> lessThanTest = delegate(int i) {
       return i < lessThan;
    };
    
    lessThanTest(99); // returns true
    lessThan = 10;
    lessThanTest(99); // returns false
    

    In C, this would be illegal:

    BOOL (*lessThanTest)(int);
    int lessThan = 100;
    
    lessThanTest = &LessThan;
    
    BOOL LessThan(int i) {
       return i < lessThan; // compile error - lessThan is not in scope
    }
    

    though I could define a function pointer that takes 2 arguments:

    int lessThan = 100;
    BOOL (*lessThanTest)(int, int);
    
    lessThanTest = &LessThan;
    lessThanTest(99, lessThan); // returns true
    lessThan = 10;
    lessThanTest(100, lessThan); // returns false
    
    BOOL LessThan(int i, int lessThan) {
       return i < lessThan;
    }
    

    But, now I have to pass the 2 arguments when I evaluate it. If I wished to pass this function pointer to another function where lessThan was not in scope, I would either have to manually keep it alive by passing it to each function in the chain, or by promoting it to a global.

    Though most mainstream languages that support closures use anonymous functions, there is no requirement for that. You can have closures without anonymous functions, and anonymous functions without closures.

    Summary: a closure is a combination of function pointer + captured variables.

    0 讨论(0)
提交回复
热议问题