# Some thoughts on Callbacks

**URL:** <https://erlangforums.com/t/some-thoughts-on-callbacks/1851>\
**Category:** Chat / Discussions\
**Tags:** dialyzer, gen\_statem\
**Created:** [September 20, 2022, 11:14pm UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851 "2022-09-20T23:14:21Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![mmin](https://erlangforums.com/user_avatar/erlangforums.com/mmin/32/2193_2.png) [@mmin](https://erlangforums.com/u/mmin)\
**Post date:** [September 20, 2022, 11:14pm UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/1 "2022-09-20T23:14:21Z")

</div>

I was thinking about the following thing for some time and I want to hear what other people think of this.

While implementing some behavior, we must implement and export callbacks. So, the user interface and the behavior callbacks are grouped together. Exported callbacks are AFAIK not intended to be called by the user, but only by the behavior module. This, IMHO, could create confusion and unwanted behavior while trying to interact with some implementation of behavior, **especially _gen\_statem_** which allows custom callback names!

Could it be possible for dialyzer to catch those misuses? E.g. if “cellphone” is a _gen\_statem_ implementation, with states _create_, _open_, etc., but its interface only contains _start_… So, if the user calls _open_ or _create_ instead of _start_ a warning would be generated.  
Can we warn the user not to interact directly with callbacks?

Or on the other hand, are there some scenarios when you want to directly call callback functions?

---

<div class="post-metadata">

**Author:** ![kuna.prime](https://erlangforums.com/letter_avatar_proxy/v4/letter/k/b77776/32.png) [@kuna.prime](https://erlangforums.com/u/kuna.prime)\
**Post date:** [September 21, 2022, 12:39am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/2 "2022-09-21T00:39:34Z")

</div>

There is actually a broader problem here. Some functions in general need to be exported to be used for some framework (including OTP) to work but are not intended for the “end user”.  
As I understand, now we are mostly relying on the state of documentation. More specifically if the export is documented use it and if not there are no guarantees.

I propose solution in a form of new attribute `-internal()` like `-deprecated()` and `-removed()` (although i cannot find any documentation for them) .

for example, you could mark a function as internal for use only inside some app so that tools like `xref` or `compiler` could check for correct usage:

```erlang
-module(example1). 

-export([f1/0, f2/0]).

-internal({f1/0, [app1, app2]}). %usage allowed only in the context of app1 and app2

f1() ->
   ...

```

or even better:

```erlang
-module(example2). 

-export(f2/0]).

-internal({f1/0, [app1, app2]}). %exported for usage only in the context of app1 and app2

f1() ->
   ...

```

---

<div class="post-metadata">

**Author:** ![elbrujohalcon](https://erlangforums.com/user_avatar/erlangforums.com/elbrujohalcon/32/241_2.png) [@elbrujohalcon](https://erlangforums.com/u/elbrujohalcon)\
**Post date:** [September 21, 2022, 5:15am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/3 "2022-09-21T05:15:44Z")

</div>

I love this idea! It would greatly help tools like _Hank_.  
To add to the conversation, here is a related ticket I wrote a while back:

> <https://github.com/erlang/otp/issues/4847>
>
> There are behaviors where the callback function list includes 1-to-n functions w…ith unspecified names but a particular arity.
> Examples of this are \`ct\_suite\`'s \[\`Module:TestCase/0\`\](http://erlang.org/doc/man/ct\_suite.html#Module:Testcase-0) and \[\`Module:TestCase/1\`\](http://erlang.org/doc/man/ct\_suite.html#Module:Testcase-1), and \`gen\_statem\`'s \[\`Module:StateName/3\`\](http://erlang.org/doc/man/gen\_statem.html#Module:StateName-3) in all its variants.
> These callbacks, which I would like to call \_dynamic callbacks\_, are only specified in the documentation (particularly in the XML files that correspond to the modules describing the behaviors).
> For tools like \[\`rebar3\_hank\`\](https://hex.pm/packages/rebar3\_hank) and likely others (probably \`dialyzer\` among them), it would be very convenient to have them specified along with the regular callbacks.
> 
> \### Describe the solution you'd like
> I would like to be able to add callback specifications like the following one:
> 
> \`\`\`erlang
> \-callback Testcase() -\> \[ct\_info()\].
> \`\`\`
> 
> And I would like to get that information out of \`Module:behavior\_info(callbacks)\`, maybe with something like this…
> 
> \`\`\`erlang
> 1\> ct\_suite:behaviour\_info(callbacks).
> \[{all,0},
> {groups,0},
> {suite,0},
> {init\_per\_suite,1},
> {end\_per\_suite,1},
> {group,1},
> {init\_per\_group,2},
> {end\_per\_group,2},
> {init\_per\_testcase,2},
> {end\_per\_testcase,2},
> {"TestCase", 0},
> {"TestCase", 3}\]
> \`\`\`
> 
> It can be a string (as I showed above) or any other term that you find suitable. I originally considered using \`'\_'\` but that will lose information. Maybe \`{dynamic, "TestCase", 0}\` can work, too. Whatever is easier.
> 
> \*\*Additional context\*\*
> We discussed this issue in https://github.com/AdRoll/rebar3\_hank/pull/124#issuecomment-841066228

---

<div class="post-metadata">

**Author:** ![kennethL](https://erlangforums.com/user_avatar/erlangforums.com/kennethl/32/1226_2.png) [@kennethL](https://erlangforums.com/u/kennethL)\
**Post date:** [September 21, 2022, 7:14am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/4 "2022-09-21T07:14:22Z")

</div>

This has already been suggested 2007 in EEP-0005 here [Eep 0005 - Erlang/OTP](https://www.erlang.org/eeps/eep-0005). I still think it is an interesting feature which also could be applied to export of types. Many type specs are only intended to be used internally within the application but not by the users of the application.

---

<div class="post-metadata">

**Author:** ![kuna.prime](https://erlangforums.com/letter_avatar_proxy/v4/letter/k/b77776/32.png) [@kuna.prime](https://erlangforums.com/u/kuna.prime)\
**Post date:** [September 21, 2022, 9:26am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/5 "2022-09-21T09:26:51Z")

</div>

thank you for pointing out EEP, I was looking into them but I managed to miss 0005 one. That being said I would prefer to declare allowed apps instead of modules (as per my proposal).

---

<div class="post-metadata">

**Author:** ![nzok](https://erlangforums.com/letter_avatar_proxy/v4/letter/n/4af34b/32.png) [@nzok](https://erlangforums.com/u/nzok)\
**Post date:** [September 22, 2022, 2:19am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/6 "2022-09-22T02:19:15Z")

</div>

And the EEP already raised the issue of exporting to an app and proposed a way to do  
that lo! these many years ago. (In fact the export\_to proposal goes back to some time  
before 1997.)

There is a great deal of design thought needed before the proposal can really be  
extended to applications. For example, if application A defines module M and  
includes application B, and m:f/a is exported to application B, but there is a  
call to it from M, should that be allowed? It has never been clear to me what  
makes a process “belong to” an application and whether that property can change,  
but it does invite the question whether “application X may use m:f/a” is a  
statement about MODULES belonging to application X (which is all I thought of  
in 2007) or to PROCESSES belonging to application X.

How do I edit an EEP?

---

<div class="post-metadata">

**Author:** ![holger](https://erlangforums.com/user_avatar/erlangforums.com/holger/32/831_2.png) [@holger](https://erlangforums.com/u/holger)\
**Post date:** [September 23, 2022, 10:58am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/7 "2022-09-23T10:58:34Z")

</div>

> [@nzok](#):
>
> It has never been clear to me what  
> makes a process “belong to” an application

I would’ve thought conceptually, given a process `P` who’s `pid()` was returned by application `A`’s [`start/2` callback](https://www.erlang.org/doc/man/application.html#Module:start-2), a process belongs to `A` if it’s either `P` or a descendant of `P` (i.e., if it’s “part of `A`’s supervision tree”), no?

This [includes](https://www.erlang.org/doc/design_principles/included_applications.html) processes spawned from code of included applications (or any other modules, for that matter):

> when running, an included application is in fact part of the primary application, and a process in an included application considers itself belonging to the primary application.

> [@nzok](#):
>
> and whether that property can change

As far as I can see, there’s currently no supported mechanism to change that property. Child process `C` is marked as a descendet of parent `P` by (ab)using the [group leader](https://www.erlang.org/doc/man/erlang.html#group_leader-0) mechanism, but that seems to be an undocumented implementation detail, so I’d assume fiddling with group leaders to be unsupported.

(I doubt I’m telling you news here, so maybe I missed your point?)

---

<div class="post-metadata">

**Author:** ![bsanyi](https://erlangforums.com/letter_avatar_proxy/v4/letter/b/7c8e57/32.png) [@bsanyi](https://erlangforums.com/u/bsanyi)\
**Post date:** [September 27, 2022, 7:44am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/8 "2022-09-27T07:44:57Z")

</div>

> [@mmin](#):
>
> Or on the other hand, are there some scenarios when you want to directly call callback functions?

I sometimes do that from tests.

---

<div class="post-metadata">

**Author:** ![juhlig](https://erlangforums.com/user_avatar/erlangforums.com/juhlig/32/837_2.png) [@juhlig](https://erlangforums.com/u/juhlig)\
**Post date:** [September 27, 2022, 7:56am UTC](https://erlangforums.com/t/some-thoughts-on-callbacks/1851/9 "2022-09-27T07:56:58Z")

</div>

> [@nzok](#):
>
> How do I edit an EEP?

By making a PR to [GitHub - erlang/eep: Erlang Enhancement Proposals](https://github.com/erlang/eep) I think.
