What is the specific syntax of @derive module attribute and where is it documented explicitly?

Viewed 497

I expected it to be documented in Module, probably with references to structs, but no joy. Seen it used with a single or a list of arguments. All the variations I could find so far:

The only places I found mentions of @derive:


Wasn't sure whether I'm not just overlooking something, therefore didn't open an issue or pull request.

1 Answers

Documentation is in defstruct there:

For each protocol in the @derive list, Elixir will assert there is an implementation of that protocol for any (regardless if fallback to any is true) and check if the any implementation defines a __deriving__/3 callback (via Protocol.derive/3).

And Protocol.derive/3:

If your implementation passes options or if you are generating custom code based on the struct, you will also need to implement a macro defined as __deriving__(module, struct, options) to get the options that were passed.

So in other words, @derive:

  • Accepts a list of tuples in form {protocol, options} where protocol is protocol on which will be called __deriving__/3 and options is term that will be passed as 3rd argument
  • protocol (where protocol is defined as above - atom describing the protocol module) is the same as {protocol, []}
  • In case of single derived module you can omit wrapping everything in list and use definition directly

So your examples can all be rewritten to "more descriptive" like that:

  1. List of module names

    @derive [MyProtocol, Another]
    

    Is the same as

    @derive [{MyProtocol, []}, {Another, []}]
    
  2. Module name

    @derive Inspect
    

    Is the same as

    @derive [Inspect]
    

    Which is the same as

    @derive [{Inspect, []}]
    
  3. Tuple

    @derive {Protocol, key1: :val1, key2: val2}
    

    Is the same as

    @derive [{Protocol, [key1: :val1, key2: val2]}]
    
  4. List of tuples is the "canonical" form

I hope that this clarifies everything a little.

Related