|
It’s the literal identifier for a function pointer. Module.function/arity. (“Arity” = “number of arguments.”) If you’re wondering “why add the arity”: Functions in BEAM are polymorphic on their arity, but not their argument types; i.e. multiple functions can share the same name but have different arity, but all definitions in a module of a function with the same name and arity are actually the same function. When you see Erlang/Elixir code with multiple definitions of a function of the same name and arity, those are called “clause heads”, and are defining the function “by parts”; code like the following gets compiled into one function that branches internally depending on the arguments passed: def fact(0), do: 1
def fact(1), do: 1
def fact(n), do: n * fact(n - 1)
That out of the way: `Foo.bar/N` in Elixir code is a function-pointer literal, which you can pass around just like you're passing around a closure. These three lines are all equivalent in semantics: # remote function pointer
f = Foo.bar/1
# closure
f = fn x -> Foo.bar(x) end
# closure with anonymous parameters
f = &Foo.bar(&1)
...in terms of what happens when you use `f` in your code; but the function-pointer version has lower overhead to call, and costs less memory to keep around, because it's not capturing anything from the environment. It's literally just a pointer.Oh, and this also exists: f = &bar/1
...which is a function-pointer referencing a local function in the current module. This distinction is important, because you can get local function pointers that point to private functions; whereas you can't get remote function pointers (the fully-qualified kind that include a module name) to private functions. It's kinda like C++ with private fields—you have to not use `this.` when accessing them.Oh, and one more variant: f = some_mod.foo/2
This isn't a function-pointer literal, but rather a function-pointer expression. `some_mod` here is a variable; this expression will give you a function-pointer to the function `foo/2` on whatever module is named by the atom in the `some_mod` variable. (This can only be resolved at runtime; your code will throw an error here when it executes this expression, if it finds out that `some_mod` doesn’t contain an atom, or that atom has no corresponding module, or that module doesn’t have a foo/2 function on it. You can catch this error, though; and the runtime itself catches this error to implement just-in-time module loading.) |