如何在Erlang R17中使用-extends

如何在Erlang R17中使用-extends,erlang,extends,Erlang,Extends,在最近的Erlang版本中删除了-extends特性 我有一些遗留模块,它们大量使用了-extends 如何让它在R17中工作 这是一个在R17中被删除的实验特征 因此,如果您真的必须使用R17,则必须在所有子模块中添加每个继承函数的定义: inherited_function (Param) -> parent:inherited(Param). 我编写了一个简单的代码,插入所需的函数并直接导出到现有代码中。它需要在src目录下工作,并且可以访问ebin目录(调用Module:Modu

在最近的Erlang版本中删除了-extends特性

我有一些遗留模块,它们大量使用了-extends


如何让它在R17中工作

这是一个在R17中被删除的实验特征

因此,如果您真的必须使用R17,则必须在所有子模块中添加每个继承函数的定义:

inherited_function (Param) -> parent:inherited(Param).
我编写了一个简单的代码,插入所需的函数并直接导出到现有代码中。它需要在src目录下工作,并且可以访问ebin目录(调用Module:Module_info(exports))-因此我会在项目的副本上使用它:o)。它对extend指令做了一些假设(没有空白字符),并且没有将添加的export指令拆分成几行,这可能是一个问题,但它在我的示例中起作用

要修改的代码示例: 根模块

-module (gd_father).

-export([gdf1/0,gdf2/1,gdf2/2]).

gdf1() -> gd_father.

gdf2(P) -> {gd_father,P}.

gdf2(P1,P2) when is_list(P2) -> [gd_father,P1|P2];
gdf2(P1,P2) -> [gd_father,P1,P2].
儿童1级

-module (father).

-extends(gd_father).

-export([ft1/1,ft2/0]).

-export([gdf2/1]).

ft1(X) -> {father,X}.

ft2() -> father.

gdf2(P1) -> {ovl_father,P1}.
二级儿童

-module (child1).

-extends(father).

-export ([cd1/0]).

-export ([ft1/1]).

cd1() -> child1.

ft1(X) -> {ovl_child1,X}.

一个验证其工作的测试模块(使用R17编译时,在使用-extend指令时不会出现错误!)

转换模块:

-module (transform).

-export([transform_dir/0,transform_file/1]).


transform_dir() ->
    {ok,AllFiles} = file:list_dir("."),
    Files = [list_to_atom(lists:sublist(X,length(X)-4)) || X <- AllFiles, is_src(lists:reverse(X))],
    transform_file(Files).

transform_file([]) -> ok;
transform_file([H|Q]) ->
    {_,_,Add,Father,Lines} = transform_file(H),
    mod_file(H,Add,Father,Lines),
    transform_file(Q);
transform_file(Name) ->
    FileName = atom_to_list(Name) ++ ".erl",
    {ok,Bin} = file:read_file(FileName),
    List = binary_to_list(Bin),
    Lines = string:tokens(List,"\n"),
    Father = to_atom([string:strip(X) || X <- Lines, is_extend(X)]),
    OrExp = Name:module_info(exports),
    case Father of
        none -> {OrExp,OrExp,[],none,[]};
        Father ->   {_,Fa_Tot,_,_,_} = transform_file(Father),
                Or = lists:usort(OrExp),
                Tot = lists:usort(Fa_Tot ++ OrExp),
                Add = lists:usort(lists:subtract(Tot,Or)),
                {Or,Tot,Add,Father,Lines}
    end.

is_extend([$-,$e,$x,$t,$e,$n,$d,$s|_]) -> true;
is_extend(_) -> false.

is_src([$l,$r,$e,$.|_]) -> true;
is_src(_) -> false.

to_atom([]) -> none;
to_atom([L]) ->
    list_to_atom(tl(lists:takewhile(fun(X) -> X =/= $) end , lists:dropwhile(fun(X) -> X =/= $( end,L)))).

mod_file(_,[],_,_) -> ok;
mod_file(F,L,Father,Lines) ->
    Export = lists:flatten(["\n%Replace expends directive by export\n-export([",
              tl(lists:flatten([", " ++ atom_to_list(X) ++ "/" ++ integer_to_list(N) || {X,N} <- L])),
              "]).\n"]), 
    Def = lists:flatten(["\n\n%Insert relay functions to replace the expends directive\n" |[add_def(X,Father) || X <- L]]),
    NewLines = insert(Lines,Export,Def,[]),
    file:write_file(atom_to_list(F)++".erl",NewLines,[write]).

insert([],_,Def,R) -> lists:reverse([Def|R]);
insert([H|Q],Export,Def,R) ->
    Line = case is_extend(H) of
        true -> Export;
        false -> H
    end,
    insert(Q,Export,Def,[Line|R]).

add_def({N,A},F) -> 
    Args = args(A,[]),
    atom_to_list(N) ++ Args ++ " -> " ++ atom_to_list(F) ++ ":" ++ atom_to_list(N) ++ Args ++ ".\n".

args(0,[]) -> "()";
args(0,R) -> "(" ++ lists:reverse(tl(R)) ++ ")";
args(A,R) -> args(A-1,[$,,A-1+$A,$P|R]).
您可以编写一个函数,在每个非限定函数调用之前插入父模块的名称;2) 未引用当前模块中的函数;3) 不引用内置函数


这应该不会太难,但我仍然只会在大量使用
扩展时这样做,因为这会降低代码的可理解性,并且在抽象格式发生变化时可能需要维护。

我将更深入地了解解析转换,但是如果不递归地查看父定义以查找所有未修改的继承函数,我不理解这是如何工作的。@Pascal Oops没有考虑到父模块本身可以扩展另一个模块。所以这可能是行不通的。
-module (test).

-export([t/0]).

t() ->
    gd_father = gd_father:gdf1(),
    {gd_father,3} = gd_father:gdf2(3),
    [gd_father,1,2] = gd_father:gdf2(1,2),
    [gd_father,1,2,3] = gd_father:gdf2(1,[2,3]),

    {father,4} = father:ft1(4),
    father = father:ft2(),
    {ovl_father,5} = father:gdf2(5),
    [gd_father,1,2] = father:gdf2(1,2),
    gd_father = father:gdf1(),
    [gd_father,1,2,3] = father:gdf2(1,[2,3]),

    child1 = child1:cd1(),
    {ovl_child1,test} = child1:ft1(test),
    father = child1:ft2(),
    {ovl_father,5} = child1:gdf2(5),
    [gd_father,1,2] = child1:gdf2(1,2),
    gd_father = child1:gdf1(),
    [gd_father,1,2,3] = child1:gdf2(1,[2,3]),

    child2 = child2:cd2(),
    ovl_child2 = child2:ft2(),
    ovl_child2 = child2:gdf1(),
    {father,4} = child2:ft1(4),
    {ovl_father,5} = child2:gdf2(5),
    [gd_father,1,2] = child2:gdf2(1,2),
    [gd_father,1,2,3] = child2:gdf2(1,[2,3]),

    ok.
-module (transform).

-export([transform_dir/0,transform_file/1]).


transform_dir() ->
    {ok,AllFiles} = file:list_dir("."),
    Files = [list_to_atom(lists:sublist(X,length(X)-4)) || X <- AllFiles, is_src(lists:reverse(X))],
    transform_file(Files).

transform_file([]) -> ok;
transform_file([H|Q]) ->
    {_,_,Add,Father,Lines} = transform_file(H),
    mod_file(H,Add,Father,Lines),
    transform_file(Q);
transform_file(Name) ->
    FileName = atom_to_list(Name) ++ ".erl",
    {ok,Bin} = file:read_file(FileName),
    List = binary_to_list(Bin),
    Lines = string:tokens(List,"\n"),
    Father = to_atom([string:strip(X) || X <- Lines, is_extend(X)]),
    OrExp = Name:module_info(exports),
    case Father of
        none -> {OrExp,OrExp,[],none,[]};
        Father ->   {_,Fa_Tot,_,_,_} = transform_file(Father),
                Or = lists:usort(OrExp),
                Tot = lists:usort(Fa_Tot ++ OrExp),
                Add = lists:usort(lists:subtract(Tot,Or)),
                {Or,Tot,Add,Father,Lines}
    end.

is_extend([$-,$e,$x,$t,$e,$n,$d,$s|_]) -> true;
is_extend(_) -> false.

is_src([$l,$r,$e,$.|_]) -> true;
is_src(_) -> false.

to_atom([]) -> none;
to_atom([L]) ->
    list_to_atom(tl(lists:takewhile(fun(X) -> X =/= $) end , lists:dropwhile(fun(X) -> X =/= $( end,L)))).

mod_file(_,[],_,_) -> ok;
mod_file(F,L,Father,Lines) ->
    Export = lists:flatten(["\n%Replace expends directive by export\n-export([",
              tl(lists:flatten([", " ++ atom_to_list(X) ++ "/" ++ integer_to_list(N) || {X,N} <- L])),
              "]).\n"]), 
    Def = lists:flatten(["\n\n%Insert relay functions to replace the expends directive\n" |[add_def(X,Father) || X <- L]]),
    NewLines = insert(Lines,Export,Def,[]),
    file:write_file(atom_to_list(F)++".erl",NewLines,[write]).

insert([],_,Def,R) -> lists:reverse([Def|R]);
insert([H|Q],Export,Def,R) ->
    Line = case is_extend(H) of
        true -> Export;
        false -> H
    end,
    insert(Q,Export,Def,[Line|R]).

add_def({N,A},F) -> 
    Args = args(A,[]),
    atom_to_list(N) ++ Args ++ " -> " ++ atom_to_list(F) ++ ":" ++ atom_to_list(N) ++ Args ++ ".\n".

args(0,[]) -> "()";
args(0,R) -> "(" ++ lists:reverse(tl(R)) ++ ")";
args(A,R) -> args(A-1,[$,,A-1+$A,$P|R]).
-module (child1).

%Replace expends directive by export
-export([ ft2/0, gdf1/0, gdf2/1, gdf2/2]).
-export ([cd1/0]).

-export ([ft1/1]).

cd1() -> child1.

ft1(X) -> {ovl_child1,X}.

%Insert relay functions to replace the expends directive
ft2() -> father:ft2().
gdf1() -> father:gdf1().
gdf2(PA) -> father:gdf2(PA).
gdf2(PB,PA) -> father:gdf2(PB,PA).