Function pointers are useless. Prove me wrong

I think calling a function directly is always better than using a function pointer.

Seems overly verbose to write this:

fn main() {
  let add_ptr: fn(i32, i32) -> i32 = add;
  let result = add_ptr(5, 3);
  println!("Result: {}", result);
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

rather than this:

fn main() {
  let result = add(5, 3);
  println!("Result: {}", result);
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

If function pointers suddenly vanished from existence, all you'd have to do is refactor your code to improve signal/noise ratio and the world would be a better place.

By that argument, we should abandon using variables at all.

3 Likes

In your example the function pointer is superfluous. But that doesn't prove function pointers are useless in every situation. Callbacks or dynamically choosing what function to execute during run time are valid examples for situations where function pointers are useful, I'd say.

6 Likes

In this simple example it is indeed useless, but they have several legitimate use cases.

Are you arguing against closures too? [1]

  • A major use case of closures is callbacks. Rust uses them heavily:

    let vec = [1, 2, 3];
    
    let vec2: Vec<_> = vec.iter().map(|x| x + 2).collect();
    //                        closure ^^^^^^^^^
    
  • FFI code with callbacks must use function pointers, because C doesn't have Rust-style closures.

  • Function pointers are also necessary to implement dynamic type erasure (like trait objects).


  1. In Rust they are not implemented as function pointers, but they are similar in many ways ↩ī¸Ž

6 Likes

I would agree that that function pointers are a niche feature, but I would not dare calling them useless.
I could not find a place in my current projects where I've ever used a function pointer (and did not refactor it away). I mostly use generics with appropriate Fn* trait bounds when I need arbitrary functions, but then I also write rather higher-level code and fn pointers might have benefits when dealing with bare metal.

3 Likes

I presume variables are then useless too because you can always rewrite this:

fn main() {
   let i = 42;
   foo(i);
}

as this:

fn main() {
    foo(42);
}

I think you might have wanted to think about things a bit more before boldly asserting that something is useless. Instead you could have asked a question: "What are some uses for function pointers? I can't think of any."

3 Likes

I'm cool with the idea of boldly asserting something that will later get disproved. it's good for my learning because it triggers hypercorrection effect

2 Likes

Actually (insert meme), I try to avoid excess let variables in my code.
Most variables I use are constants, either globally or associated with a struct or trait.
I rather process input in functions on the fly in preferably short, concise, pure functions.
This way I rarely encounter the need to introduce local variables using let.
Are they useless though? I think not!

Edit: I just checked a project of mine for fun:

  • Total let: 116
  • let not in tests: 39
    • of those let Some: 10
    • of those let Ok: 3
    • of those let [...] (array/slice destructuring): 6

SLOC:

      31 text files.
      31 unique files.                              
       0 files ignored.

github.com/AlDanial/cloc v 2.04  T=0.01 s (2120.8 files/s, 233427.4 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Rust                            31            443            326           2643
-------------------------------------------------------------------------------
SUM:                            31            443            326           2643
-------------------------------------------------------------------------------