-6

I hope its an extremely repetitive question. And my advance excuse to all the viewers who find it annoying.

Although I am bit experienced programmer, but I cannot justify the use of function pointer over direct call. Scenarios where I unable to find the differences are -

1) callbacks - same can be achieved by direct call.

2) Asynchronous or synchronous event handling - anyway event has to be identified, based on which element no. in function pointer array got updated. But the same can be also done via direct call.

3) In some post I had seen people commenting it is to be used when it is not known which function to call. I didn't get any proper justification for this.

I really appreciate if someone can explain me using above scenarios with practical and really simple realistic example.

kostix
  • 51,517
  • 14
  • 93
  • 176
Vikere
  • 1
  • 1
  • 4
  • 4
    C or C++? if C++ the answer is pretty much never unless interfacing with C; since lambdas and std::function have replaced them – UKMonkey May 30 '18 at 16:02
  • 3
    Isn't a function pointer the only way to pass functions in C? How would you implement a callback without functions pointers? – Carcigenicate May 30 '18 at 16:02
  • 8
    "I didn't get any proper justification for this." Try coding up a library, you'll get your justification pretty quickly :-) – Sergey Kalinichenko May 30 '18 at 16:03
  • 1
    Look at the implementation of `qsort`. See how it allows for user-defined comparator with possibly user-defined data types. – unxnut May 30 '18 at 16:05
  • If you are interested in embedded, study the source code of the Linux kernel (or just some drivers inside it) – Basile Starynkevitch May 30 '18 at 16:07
  • @Carcigenicate - callback is nothing but an address of function which indirect called by other function or some other entity. My statement may be misinterpret. But my query is why same cannot be done via direct call. You may be answering correctly but for my explanation give a practical use case scenario. That's why I asked to give some realistic example. – Vikere May 30 '18 at 16:10
  • The purpose of callbacks is that you're passing the function pointer to another function. That other function doesn't know what function to call unless you tell it. – Kevin May 30 '18 at 16:11
  • 1
    @Vikere Callback typically means giving a function to some code to have them use it to "call back" at a future time. That necessarily involves passing a function, or something representing a function like a pointer. I'm not sure what you mean by callback then in this question. If you're just calling a function in the scope that it was defined in, no, you wouldn't necessarily need a pointer. – Carcigenicate May 30 '18 at 16:12
  • Try making a generic heap data structure in C that can hold any type of data. You will discover the utility of function pointers in carrying out this task. – Christian Gibbons May 30 '18 at 16:28
  • @Carcigenicate Yes you are very correct. So to clarify - if there is a function taking function pointer as argument - void sum (int, int (*)()) So, it means 2nd part could be mapped to any function of same signature. Is it correct?? – Vikere May 30 '18 at 16:30
  • Try implementing the `qsort` stdlib function without a function pointer. Then come back and ask again. – tofro May 30 '18 at 16:39
  • a) it is a ghee whiz feature of the language so why not use it, just like bitfields. b) it should be easy to see cases where you cannot determine at runtime what you are calling, does that REQUIRE function calls? no absolutely not. but it is a quick and dirty way to do it, even if it is not a runtime thing. generic code that connects to some peripheral, the peripheral can come in through bluetooth or usb but is at some level handled the same way, have a bluetooth transport and a usb transport, glue in the function pointers at discovery and use for the duration. zillion other examples. – old_timer May 30 '18 at 17:25
  • @tofro @unxnut actually you can make a generic `qsort` without function pointers with macros but i am not say it the right way. – Tyker May 30 '18 at 17:26

6 Answers6

4

Some more things function pointers are often used for:

  • Runtime polymorphism: You can define a structure that encapsulates a function pointer, or a pointer to a function table. This enables you to call the specified function at runtime, even for a type of client object that did not exist when your library was written. You can use this to implement multiple dispatch or something like the visitor design pattern in C. This is also how C++ classes and their virtual member functions were originally implemented under the hood.
  • Closures: These can be structures containing a function pointer and one or more of its arguments.
  • State Machines: Instead of a switch with a case for each state label, I’ve often found it convenient to give the handler for each state its own function. The current state is the function you’re in, the state transitions are tail-recursive calls, and the program variables are parameters. The state labels then become function pointers, which you might store in a table or return from a function.
  • Higher-Order Functions: Two examples from the C standard library are qsort() and btree(), which generalize the type of elements and the comparison function.
  • Low-Level Support: Shared-library loaders, for example, need this.
Davislor
  • 14,674
  • 2
  • 34
  • 49
  • Another use case would be something like what one might call a "recipe factory": Say you had a series of actions that you wanted the code to be able to perform, and depending on some dynamic variables/state, you wanted to select these and those actions and combine them into a "recipe" at runtime for it to perform. Each type of instruction might be directly callable, but when you combine them all together into a single recipe, you want to be able to just call function after function, not run a switch/state machine on every single instruction, which would be slow. Function pointers are fast. – Andrew Jul 03 '21 at 05:34
  • One example would be if you had some kind of an algebra/function textbox where the user could enter in e.g. `pow(X + Y / Z, 2)` - Excel would be a great example of this - and you want to perform the specified algorithm very quickly or in batch. Much faster to call a series of prepared functions than to re-evaluate the algorithm every time. – Andrew Jul 03 '21 at 05:37
3

1) callbacks - same can be achieved by direct call.

Not true. For a direct call, the caller must know the function name and signature when the code is compiled, and can only ever call that one function. A callback is defined at runtime and can be changed dynamically, while the caller need only know the signature, not the name. Moreover each instance of an object may have a different callback, whereas with a direct call, all instances must call the same function.

2) Asynchronous or synchronous event handling - anyway event has to be identified, based on which element no. in function pointer array got updated. But the same can be also done via direct call.

Not sure what you mean, but an event handler is simply a kind of callback. The event may be identified by the caller and different call-back handlers called through pointers. Your point only stands if there is one event handler for all event types and the user is to be responsible for identification.

3) In some post I had seen people commenting it is to be used when it is not known which function to call. I didn't get any proper justification for this.

See (1) and (2) above. Often it is a means to hook platform independent third-party library code into a specific platform without having to deliver source-code or for system events that require user/application-defined handlers.

I would not sweat it however - if all your application requirements can be resolved without using a pointer to a function, then you don't need a pointer to a function. When you need one, you will probably know. You will most likely encounter it when you have to use an API that requires it before you ever implement an interface yourself that does. For example in the standard library the qsort() function requires a pointer to a function in order to define how two objects of arbitrary type are to be ordered - allowing qsort() to support any type of object - it is a way in C of making a function "polymorphic". C++ supports polymorphism directly, so there is often less need for explicit function-pointers in C++ - although internally polymorphism is implemented using function pointers in any case.

Clifford
  • 88,407
  • 13
  • 85
  • 165
1

There is a concept in programming called DRY -- don't repeat yourself.

Suppose you have 121 buttons in your UI. Each one of them behaves much the same, except when you press the button, a different operation happens.

You can (A) use virtual inheritance to dispatch to the right operation (requiring a class per button), or (B) use a function pointer (or a std::function) stored in the class in order to call the right "on click" handler, or (C) have every single button be a distinct type.

A virtual function is implemented in every compiler I have examined as a complex table that, in the end, is a collection of function pointers.

So your choices are function pointers or generating 121 completely distinct buttons that happen to mostly behave the same.

In any situation where you want to decouple the caller and the called, you must use something akin to a function pointer. There are a ridiculous number of cases, from work queues to thread off tasks, callbacks, etc.

In tiny programs where everything is hard coded, hard coding every call can work. But hard coded stuff like this doesn't scale. When you want to update those 121 buttons each hand-implemented, knowing their points of customization is going to be ridiculously difficult. And they will fall out of sync.

And 121 is a modest number of buttons. What about an app with 10,000? And you want to update every button's behavior to handle touch-based input?

Even more, when you type erase, you can reduce binary size significantly. 121 copies of a class implementing a button is going to take more executable space than 1 class, each of which stores a function pointer or two.

Function pointers are but one type of "type erasure". Type erasure reduces binary size, provides clearer contracts between provider and consumer, and makes it easier to refactor behavior around the type erased data.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Type erasure not in the sense that the functions are without a type - as they aren't without a type (it is stored in the function pointer) - but that what they are supposedly replacing, the polymorphic classes, are all types which can now be erased from existence. This is a good example you provide but there are a number of other substitutions that function pointers serve as which do not act as type erasures. – Andrew Jul 03 '21 at 05:47
1

Without function pointers, how would you implement a function which calculates the integral of any real-valued function?

typedef double (*Function)(double);

double Integral(Function f, double a, double b);
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
  • I am not sure you have made your case here and have certainly not addressed the specific usage of function-pointers described in the question. You have introduced an additional use, which is fine, but seems unlikely to convince the OP of their utility in the specific circumstances he has asked about. – Clifford May 30 '18 at 16:44
  • @Clifford https://en.wikipedia.org/wiki/Callback_(computer_programming) – August Karlstrom May 30 '18 at 16:47
  • I am not sure why you have addressed that link to me, or how it relates to either your answer or my previous comment. My point is simply that the question is rather broad but your answer rather much narrower. Moreover it is a good example, but perhaps not a complete answer - also somewhat succinct - you have answered a question with a question, and given the nature of the original question, I doubt the OP will even understand your answer. – Clifford May 30 '18 at 16:54
  • @Clifford In paragraph one the poster questions the use of callbacks. I have provided an example which illustrates its necessity. I doubt it is unclear to anyone. – August Karlstrom May 30 '18 at 17:02
0

1) callbacks - same can be achieved by direct call.

Not in all cases, since the caller may not know at compile-time what function must be called. For instance, this is typical in libraries since they cannot know in advance your code.

However, it can also happen in your own code: whenever you want to re-use partially a function, you can either:

  • Create several versions of that function, each calling a different function. Duplicates code, very bad maintenance. Good performance unless hit by code bloat.
  • Pass a function pointer (or callable in general in C++). Flexible, less code, performance might suffer in some cases.
  • Create a set of branches (if/switch chain), if you know in advance the set of possible functions to call. Rigid, but might be faster than a function pointer for small number of branches.
  • In C++, create a templated version. Same as the first case, but automated; so good maintenance. Code bloat might be an issue.
  • Factor out the common code so that callers can call whatever they need piece by piece. Sometimes this isn't possible/easy -- specially when parametrizing complex algorithms that you want to keep reusable (e.g. qsort()). In C++, see the STL (Standard Template Library).

2) Asynchronous or synchronous event handling - anyway event has to be identified, based on which element no. in function pointer array got updated. But the same can be also done via direct call.

Some event systems are designed so that you simply configure which function(s) will be triggered when a given event happens. If this is an external library with a C interface, they have no choice but to use function pointers.

Some other systems let you create your own event loop and you fetch the events somehow and do whatever you want with them; so they avoid callbacks.

3) In some post I had seen people commenting it is to be used when it is not known which function to call. I didn't get any proper justification for this.

See the first case.

Acorn
  • 24,970
  • 5
  • 40
  • 69
0

Thanks all for actively participating in this discussion. Thanks for giving practical examples like -

1) Implement Library function

2) Look qsort

3) Refer Linux Kernel

4) Generic Heap data structure in C

I feel qsort() void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)) s is quite sufficient to clear my 1) & 3) point.

1) callbacks - same can be achieved by direct call. 3) In some post I had seen people commenting it is to be used when it is not known which function to call. I didn't get any proper justification for this.

Mainly by callbacks - it is a provision of calling a function for which the body is not yet defined. And it expected that the definition of the function will be provided later during run-time. So, compilation won't be hindered due to lack of function definition. Practical use if someone consider above qsort() function. In this the user is responsible for providing the function definition for compare() like -

int compare (int* a, int* b)
{
  //User defined body based on problem requirement
}

Lets consider a practical scenario where multiple threads have their respective compare function. In case of direct call every thread need to implement their own sorting function or if a common function then implementation would be much more bulky. But by using the callback method all threads can use same function for sorting, since the sorting algo remain same for all threads. Considering a layered architecture mainly higher layers have an abstract view of lower layer. So, here if say we have qsort() function [User defined qsort] implemented at application layer and lets say underlying application there is a ADC driver layer which capture sample and provide to application for sorting. Then for application it is not necessary to understand the definition of function responsible for collecting and providing the samples. But application will only focus on obtaining the sample. Hence, that main application won't know which function to call. Respective ADC driver will simply make a call to application using the qsort() and provide needful data.

Regarding 2 point still confused - 2) Asynchronous or synchronous event handling - anyway event has to be identified, based on which element no. in function pointer array got updated. But the same can be also done via direct call.

From above discussion I conclude that if event handlers pointed to some library function, then it need to be implemented via pointer to function. And secondly to create an independent and handy code it is necessary to maintain function pointer. Lets say between application and driver we have an interfacing layer. So, if either application or driver changes anytime it won't affect or very least affect each other. And this interface layer is implemented using pointer to function. But consider below scenario -

int (*fptr[10]) (void) =
{
    function1;     //function for starting LED
    function2;     //function for relay operation
      .
      .
    function10;    //function for motor control
}

lets say we have GPIO0.0 - GPIO0.10 has been mapped to the function pointer array. i.e. GPIO0.0 - 0th element of fptr . . GPIO0.10 - 10th element of fptr These GPIO pins has been configured for level triggered interrupt and their respective ISR will update the array element no. i=GPIO_Value; further the scheduler have an thread which will call the function pointer array -

fptr[i]();

Does the use of function pointer is justifiable here??

Vikere
  • 1
  • 1
  • 4