Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
308 lines (198 sloc) 8.59 KB
Author: Björn Gustavsson <bjorn(at)erlang(dot)org>
Status: Accepted/19.0 Proposal is to be implemented in OTP release 19.0
Type: Standards Track
Created: 27-Oct-2015
Erlang-Version: R19
Post-History: 29-Oct-2015, 09-Nov-2015, 11-Nov-2015, 16-Nov-2015

EEP 45: New macros for function name and arity

Abstract

This EEP proposes two new macros called FUNCTION_NAME and FUNCTION_ARITY that will return the name and arity, respectively, of the current function.

Specification

The new predefined macro FUNCTION_NAME expands to the name of the current function (as an atom). The new predefined macro FUNCTION_ARITY expands to arity of the current function (as an integer). Example:

a_function(_, _) ->
  {?FUNCTION_NAME,?FUNCTION_ARITY}.

After preprocessing, the example will look like:

a_function(_, _) ->
  {a_function,2}.

The preprocessor will expand all other macros before expanding the FUNCTION_NAME and FUNCTION_ARITY macros. So if we have this example:

-define(F, a_function).
?F(_, _) ->
  {?FUNCTION_NAME,?FUNCTION_ARITY}.

the preprocessor will first expand it to:

a_function(_, _) ->
  {?FUNCTION_NAME,?FUNCTION_ARITY}.

and then to:

a_function(_, _) ->
  {a_function,2}.

The FUNCTION_NAME and FUNCTION_ARITY macros can be used in any form that starts with an atom followed by a left parenthesis (when all other macros have been expanded). The macros may be used even in a function head. Thus, the following example is legal (albeit not very useful):

a(?FUNCTION_NAME) -> ok.

It will be expanded to:

a(a) -> ok.

The FUNCTION_NAME and FUNCTION_ARITY macros will also work in the presence of other macros in the function head. Example:

-define(__, _, _).
b(?FUNCTION_NAME, ?FUNCTION_ARITY, ?__) ->
   ok.

This code will first be expanded to:

b(?FUNCTION_NAME, ?FUNCTION_ARITY, _, _) ->
   ok.

and then to:

b(b, 4, _, _) ->
  ok.

Using FUNCTION_NAME or FUNCTION_ARITY in an attribute will cause a compilation error. Example:

-attr(?FUNCTION_NAME).

The error message will look like this:

example.erl:4: ?FUNCTION_NAME can only be used within a function

An invocation of FUNCTION_NAME or FUNCTION_ARITY must not begin a form. Therefore, the following example is illegal:

?FUNCTION_NAME() -> ok.

The error message will look like this:

example.erl:4: ?FUNCTION_NAME must not begin a form

Implementation Requirements

This EEP does not specify exactly how the FUNCTION_NAME and FUNCTION_ARITY macros should be implemented, but it does impose some requirements on the implementation:

  • The implementation must be efficient. In particular, there should not be any noticeable slowdowns for modules that don't use the FUNCTION_NAME or FUNCTION_ARITY macros.

  • The expansion of FUNCTION_NAME and FUNCTION_ARITY must be done by the epp module. Postponing expansion of the macros to a later compiler pass is not acceptable, as it could cause compatibility issues with parse transforms and other tools that operate on the abstract format.

Examples

-define(FUNCTION_STRING, atom_to_list(?FUNCTION_NAME) ++ "/" ++
          integer_to_list(?FUNCTION_ARITY)).

test() ->
  ?FUNCTION_STRING.

The test/0 function will return "test/0". Note that the BEAM compiler will evaluate constant expressions at compilation time; thus, FUNCTION_STRING will be turned into a string literal during compilation.

c() ->
  F = fun() -> ?FUNCTION_NAME end,
  F().

The c/0 function will return c.

The macros can be used when creating a fun that refers to the containing function:

self_ref(Data, Handler) ->
    ...
    Handler(Data, fun ?FUNCTION_NAME/?FUNCTION_ARITY)
    ...

Motivation

Many users have asked for some sort of macro that could return the name of the current function, similar to FILE, LINE, and MODULE. For example: [Why no ?FUNCTION macro] why.

The most common use case for a function name macro seems to be for logging information to a log file. Possible workarounds include using a parse transform, using process_info/2, or generating and catching an exception. Unless the application needs a parse transform for some other reason, implementing a parse transform just to catch the name of the current function is cumbersome. The other workarounds have run-time penalties.

Rationale

Why not only a single FUNCTION macro?

In order to minimize the pollution of the namespace of preprocessor symbols, should there not be only a single FUNCTION macro that would return a tuple with the name and arity of the current function?

It would certainly be possible, but many common use cases would be somewhat cumbersome:

io:format("~p/~p: ~s\n", [element(1, ?FUNCTION),
                          element(2, ?FUNCTION),
                          Message])

Compare that to the more readable:

io:format("~p/~p: ~s\n", [?FUNCTION_NAME,
                          ?FUNCTION_ARITY,
                          Message])

There are also contexts where element(1, ?FUNCTION) or element(2, ?FUNCTION) would be illegal, for example in function heads or after the fun keyword. The following example would fail to compile:

fun element(1, ?FUNCTION)/element(2, ?FUNCTION)

Why do I have to define FUNCTION_STRING myself?

The most important reason is that there are two reasonable definitions:

-define(FUNCTION_STRING,
   atom_to_list(?FUNCTION_NAME) ++ "/" ++
   integer_to_list(?FUNCTION_ARITY)).

and

-define(FUNCTION_STRING,
   ?MODULE_STRING ++ ":" ++
   atom_to_list(?FUNCTION_NAME) ++ "/" ++
   integer_to_list(?FUNCTION_ARITY)).

There is no run-time penality for defining FUNCTION_STRING yourself, as the compiler will turn either definition of FUNCTION_STRING into a literal string during compilation.

Another reason is to avoid polluting the macro namespace with more predefined macros than strictly needed.

Historical note: MODULE_STRING was added as an optimization in OTP R7B, because at the time the compiler did not optimize constant expressions as well as it does now.

Why are FUNCTION_NAME and FUNCTION_ARITY allowed in function heads?

I cannot see any practical use for the FUNCTION_NAME and FUNCTION_ARITY macro in a function head. Only allowing them to be used in function bodies would make sense. But consider this example:

f(a, _) ->
  ok;
f(?FUNCTION_NAME, ?FUNCTION_ARITY) ->
  ok.

To be able to reject invocations of FUNCTION_NAME and FUNCTION_ARITY in clauses other than the first, the preprocessor must basically be able to parse arbitrary Erlang code. The only practical solution would be to use the existing parser in the erl_parse module. That would slow down the preprocessor without providing any additional benefit.

Backwards Compatibility

Modules that define either FUNCTION_NAME or FUNCTION_ARITY will fail to compile with a message similar to this:

example.erl:4: redefining predefined macro 'FUNCTION_NAME'

Similarly, attempting to define FUNCTION_NAME or FUNCTION_ARITY from the command line using -D will also fail.

Implementation

The reference implementation has essentially zero extra cost for functions that do not use the FUNCTION_NAME or FUNCTION_ARITY macros. The preprocessor will only start scanning to determine the name and arity of the current function when an invocation of either FUNCTION_NAME or FUNCTION_ARITY has been seen. The scanning will stop as soon as the right parenthesis at the end of the argument list is found. The name and arity will be saved and reused if another of invocation of FUNCTION_NAME or FUNCTION_ARITY is seen in the same function definition.

The reference implementation can be fetched from Github like this:

git fetch git://github.com/bjorng/otp.git bjorn/function-macro

Copyright

This document has been placed in the public domain.

[EmacsVar]: <> "Local Variables:" [EmacsVar]: <> "mode: indented-text" [EmacsVar]: <> "indent-tabs-mode: nil" [EmacsVar]: <> "sentence-end-double-space: t" [EmacsVar]: <> "fill-column: 70" [EmacsVar]: <> "coding: utf-8" [EmacsVar]: <> "End:" [VimVar]: <> " vim: set fileencoding=utf-8 expandtab shiftwidth=4 softtabstop=4: "