Difference between a function pointer (proc) and a method?


test = ->(x : Int32) { x.to_s }

def test2(x : Int32)

pp typeof(test.call(123))

pp typeof(test2(123))

What is the difference between the two? A real world use case example would be great, thanks in advance!

You can pass around the test variable. You can’t pass around the test method (you can only invoke it). That’s the only difference.


Adding a code example for those reading the thread who are curious :slight_smile:

proc = Proc(String).new {
	"Hello, World!"

def my_method(my_proc)
  puts my_proc.call


Thanks. So… what about… a method that just returns the variable and doesn’t pass it around. Now what’s the difference? :smiley:

If a developer can just return a variable in a method and NOT have it be passed around, what’s the point of a proc?

1 Like

It’s another way to write and represent logic while writing programs in Crystal. The differences are subtle but still important to know about.

1 Like

An example i’m familiar with is with how i handle route actions for Athena. I convert each route’s action method into a proc so that i’m able to store a reference to the method that should be executed for a given route. Then when an actual request comes in, I can use that stored proc to call the correct action.

A proc also has a different scope, so it also allows me to take a Hash(String, String) as input and convert those strings within the scope of the proc so that there isn’t a union of the types from other actions. Then once the input params are converted to their correct types, i can call the proc with those values as arguments.


So for the static binding, that is: resolving code during compilation, they are mostly the same. The interesting part is dynamic binding, that is: resolving code in runtime. There are three main tools here: method overloading, inheritance overriding and function pointers. They serve different use-cases and there are important distinctions between them.

  • Inheritance overriding serves to choose a code path based on the instance type.
  • Method overloading makes the choice based on the argument list.
  • Function pointers let you make the choice yourself.
  • There are also important distinctions between inheritance and interfaces (classes vs. modules).

There is a monumental amount of information out there regarding this stuff, it may turn out to be fun for you to explore this further.