Как получить экспортированные типы модуля erlang?

У меня была причина проверить типы, экспортируемые модулем, и я сразу подумал: «Хорошо, тогда module_info», но был удивлен, столкнувшись с несколькими трудностями. Я обнаружил, что могу получить экспортированные типы из модулей, которые я компилирую, но не из, скажем, модулей в stdlib.

Мои (три) вопроса: как мне надежно получить экспортированные типы модуля, почему экспортированные типы в атрибутах бит информации о модуле для некоторых модулей и почему некоторые модули, а не другие?

Я обнаружил, что если я создам этот модуль:

-module(foo).
-export([bar/0]).
-export_types([baz/0]).
bar() -> bat .

И затем используйте foo:module_info/0, я получаю это:

[{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"}]}]

Отлично, в «атрибутах» скрыто «export_types». Почему это в атрибутах, я не совсем уверен, но... что угодно...

Теперь я знаю, что это сработает:

4> lists:keyfind(export_types, 1, foo:module_info(attributes)).
{export_types,[{baz,0}]}

Отлично. Итак, теперь я знаю, что это сработает:

5> lists:keyfind(export_types, 1, ets:module_info(attributes)).
false

Ах... это не так.

Я знаю, что есть экспортированные типы, конечно, если документация недостаточно хороша, источник ets показывает:

-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).

На самом деле информации об экспортируемом типе для модуля ets нет нигде в информации о модуле:

6> 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

Я довел дело до крайности и запустил это, записав вывод в файл:

rp(beam_disasm:file("/usr/lib/erlang/lib/stdlib-2.1/ebin/ets.beam")).

Не то чтобы я не считал это абсурдом... но в любом случае это около 5000 строк вывода, но я нигде не нахожу экземпляр строки "tid".


person Michael    schedule 22.10.2015    source источник
comment
export_types просто недействителен. Тип экспорта выполняется с помощью export_type. export_types — это просто определяемый пользователем атрибут, очень похожий на -export_lulz([some_lulz/9000])   -  person Lol4t0    schedule 22.10.2015
comment
Дох! Да, я немного споткнулся из-за этой опечатки, которая объясняет несоответствие и почему оно выглядит неуместно с атрибутами и т. Д., И теперь есть один ответ, говорящий, что в основном вы не можете легко получить экспортированные типы.   -  person Michael    schedule 22.10.2015


Ответы (1)


До Erlang 18 эта информация недоступна.

Dialyzer, например, извлекает его из абстрактного синтаксического дерева основной версии модуля Erlang (см., например, dialyzer_utils:get_record_and_type_info/1, используемый, например, dialyzer_analysis_callgraph:compile_byte/5)

Относительно этой части:

почему экспортируемые типы в атрибутах бит информации о модуле для некоторых модулей, и почему некоторые модули, а не другие?

это из-за плохого определения в вашем модуле. Атрибут должен быть -export_type, а не -export_types. Если вы используете правильный (и определяете тип baz/0 и используете его где-нибудь, чтобы модуль скомпилировался), экспортированные типы... исчезают, как и ожидалось.

person aronisstav    schedule 22.10.2015