title: How do I get the exported types of an erlang module?
body: <p>I had cause to check the types exported by a module, and I immediately thought "right, module_info then" but was surprised to run into a few difficulties. I found I can get the exported types from modules I compile, but not from say modules in stdlib.</p>
  
  <p>My (three) questions are, how do I reliably get the exported types of a module, why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others?</p>
  
  <p>I discovered that if I build this module:</p>
  
  <pre><code>-module(foo).
  -export([bar/0]).
  -export_types([baz/0]).
  bar() -&gt; bat .
  </code></pre>
  
  <p>And then use foo:module_info/0, I get this:</p>
  
  <pre><code>[{exports,[{bar,0},{module_info,0},{module_info,1}]},
   {imports,[]},
   {attributes,[{vsn,[108921085595958308709649797749441408863]},
                {export_types,[{baz,0}]}]},
   {compile,[{options,[{outdir,"/tmp"}]},
             {version,"5.0.1"},
             {time,{2015,10,22,10,38,8}},
             {source,"/tmp/foo.erl"}]}]
  </code></pre>
  
  <p>Great, hidden away in 'attributes' is 'export_types'. Why this is in attributes I'm not quite sure, but... whatever...</p>
  
  <p>I now know this will work:</p>
  
  <pre><code>4&gt; lists:keyfind(export_types, 1, foo:module_info(attributes)).
  {export_types,[{baz,0}]}
  </code></pre>
  
  <p>Great. So, I now know this will work:</p>
  
  <pre><code>5&gt; lists:keyfind(export_types, 1, ets:module_info(attributes)).
  false
  </code></pre>
  
  <p>Ah... it doesn't.</p>
  
  <p>I know there are exported types of course, if the documentation isn't good enough the ets source shows:</p>
  
  <pre><code>-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).
  </code></pre>
  
  <p>In fact the exported type information for the ets module doesn't seem to be anywhere in the module info:</p>
  
  <pre><code>6&gt; rp(ets:module_info()).                                      
  [{exports,[{match_spec_run,2},
         {repair_continuation,2},
         {fun2ms,1},
         {foldl,3},
         {foldr,3},
         {from_dets,2},
         {to_dets,2},
         {test_ms,2},
         {init_table,2},
         {tab2file,2},
         {tab2file,3},
         {file2tab,1},
         {file2tab,2},
         {tabfile_info,1},
         {table,1},
         {table,2},
         {i,0},
         {i,1},
         {i,2},
         {i,3},
         {module_info,0},
         {module_info,1},
         {tab2list,1},
         {match_delete,2},
         {filter,3},
         {setopts,2},
         {give_away,3},
         {update_element,3},
         {match_spec_run_r,3},
         {match_spec_compile,1},
         {select_delete,2},
         {select_reverse,3},
         {select_reverse,2},
         {select_reverse,1},
         {select_count,2},
         {select,3},
         {select,2},
         {select,1},
         {update_counter,3},
         {slot,2},
         {safe_fixtable,2},
         {rename,2},
         {insert_new,2},
         {insert,2},
         {prev,2},
         {next,2},
         {member,2},
         {match_object,3},
         {match_object,2},
         {match_object,1},
         {match,3},
         {match,2},
         {match,1},
         {last,1},
         {info,2},
         {info,1},
         {lookup_element,3},
         {lookup,2},
         {is_compiled_ms,1},
         {first,1},
         {delete_object,2},
         {delete_all_objects,1},
         {delete,2},
         {delete,1},
         {new,2},
         {all,0}]},
   {imports,[]},
   {attributes,[{vsn,[310474638056108355984984900680115120081]}]},
   {compile,[{options,[{outdir,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../ebin"},
                   {i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../include"},
                   {i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../../kernel/include"},
                   warnings_as_errors,debug_info]},
         {version,"5.0.1"},
         {time,{2014,7,25,16,54,59}},
         {source,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/ets.erl"}]}]
  ok
  </code></pre>
  
  <p>I took things to extremes now and ran this, logging the output to a file:</p>
  
  <pre><code>rp(beam_disasm:file("/usr/lib/erlang/lib/stdlib-2.1/ebin/ets.beam")).
  </code></pre>
  
  <p>Not that I don't consider this absurd... but anyway, it's about 5,000 lines of output, but nowhere do I find an instance of the string "tid".</p>