浏览 4601 次
锁定老帖子 主题:erlang的模块参数化及其实现
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-09-25
请参考这篇文章 http://ftp.sunet.se/pub/lang/erlang/workshop/2003/paper/p29-carlsson.pdf 我这里讲述的重点是如何实现的。先看代码: root@nd-desktop:~/test/m# cat main.erl % File: main.erl -module(main). -export([start/0]). start() -> M1 = print:new("Humpty"), M2 = print:new("Dumpty"), M1:message("Hello!"), M2:message("Hi!"), ok. root@nd-desktop:~/test/m# cat print.erl % File: print.erl -module(print, [Name]). -export([message/1]). message(Text) -> io:fwrite("~s: '~s'~n", [Name, Text]), ok. 编译运行 root@nd-desktop:~/test/m# erlc *.erl root@nd-desktop:~/test/m# erl -noshell -s main -s erlang halt Humpty: 'Hello!' Dumpty: 'Hi!' 在使用上是模拟面向对象的, 面向对象的同学会感到很亲切。但是erlang如何做到这个魔术的呢? 我们来分析下: root@nd-desktop:~/test/m# erlc +"'S'" *.erl root@nd-desktop:~/test/m# cat main.S {module, main}. %% version = 0 {exports, [{module_info,0},{module_info,1},{start,0}]}. {attributes, []}. {labels, 7}. {function, start, 0, 2}. {label,1}. {func_info,{atom,main},{atom,start},0}. {label,2}. {allocate_zero,1,0}. {move,{literal,"Humpty"},{x,0}}. {call_ext,1,{extfunc,print,new,1}}. {move,{x,0},{y,0}}. {move,{literal,"Dumpty"},{x,0}}. {call_ext,1,{extfunc,print,new,1}}. {move,{x,0},{x,3}}. {move,{y,0},{x,1}}. {move,{atom,message},{x,2}}. {move,{literal,"Hello!"},{x,0}}. {move,{x,3},{y,0}}. {apply,1}. {move,{y,0},{x,1}}. {move,{atom,message},{x,2}}. {trim,1,0}. {move,{literal,"Hi!"},{x,0}}. {apply,1}. {move,{atom,ok},{x,0}}. {deallocate,0}. return. {function, module_info, 0, 4}. {label,3}. {func_info,{atom,main},{atom,module_info},0}. {label,4}. {move,{atom,main},{x,0}}. {call_ext_only,1,{extfunc,erlang,get_module_info,1}}. {function, module_info, 1, 6}. {label,5}. {func_info,{atom,main},{atom,module_info},1}. {label,6}. {move,{x,0},{x,1}}. {move,{atom,main},{x,0}}. {call_ext_only,2,{extfunc,erlang,get_module_info,2}}. root@nd-desktop:~/test/m# cat print.S {module, print}. %% version = 0 {exports, [{instance,1},{message,2},{module_info,0},{module_info,1},{new,1}]}. {attributes, [{abstract,[true]}]}. {labels, 11}. {function, new, 1, 2}. {label,1}. {func_info,{atom,print},{atom,new},1}. {label,2}. {call_only,1,{f,4}}. {function, instance, 1, 4}. {label,3}. {func_info,{atom,print},{atom,instance},1}. {label,4}. {test_heap,3,1}. {put_tuple,2,{x,1}}. {put,{atom,print}}. {put,{x,0}}. {move,{x,1},{x,0}}. return. {function, message, 2, 6}. {label,5}. {func_info,{atom,print},{atom,message},2}. {label,6}. {test,is_tuple,{f,5},[{x,1}]}. {test,test_arity,{f,5},[{x,1},2]}. {allocate_heap,0,4,2}. {get_tuple_element,{x,1},1,{x,2}}. {put_list,{x,0},nil,{x,0}}. {put_list,{x,2},{x,0},{x,1}}. {move,{literal,"~s: '~s'~n"},{x,0}}. {call_ext,2,{extfunc,io,fwrite,2}}. {move,{atom,ok},{x,0}}. {deallocate,0}. return. {function, module_info, 0, 8}. {label,7}. {func_info,{atom,print},{atom,module_info},0}. {label,8}. {move,{atom,print},{x,0}}. {call_ext_only,1,{extfunc,erlang,get_module_info,1}}. {function, module_info, 1, 10}. {label,9}. {func_info,{atom,print},{atom,module_info},1}. {label,10}. {move,{x,0},{x,1}}. {move,{atom,print},{x,0}}. {call_ext_only,2,{extfunc,erlang,get_module_info,2}}. 先看 print.S 这个模块导出的函数除了module_info外还有3个导出 new/1, instance/1, 更重要的是 message在源码里面是/1, 但是导出是/2,很奇怪是吗? 我们再看下 new 和 instance 返回一个tuple{print, Arg}. message函数呢? {test,is_tuple,{f,5},[{x,1}]}. %% 判断第二个参数是否是tuple {test,test_arity,{f,5},[{x,1},2]}. %%tuple的个数是不是2 {allocate_heap,0,4,2}. {get_tuple_element,{x,1},1,{x,2}}. %%取出tuple的第二个参数, 这个就是源码里面的Name模块参数 {put_list,{x,0},nil,{x,0}}. {put_list,{x,2},{x,0},{x,1}}. 我演示下: root@nd-desktop:~/test/m# erl Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.7.3 (abort with ^G) 1> m(print). Module print compiled: Date: September 25 2009, Time: 07.23 Compiler options: [{cwd,"/root/test/m"},{outdir,"/root/test/m"}] Object file: /root/test/m/print.beam Exports: instance/1 message/2 module_info/0 module_info/1 new/1 ok 2> print:new(tag1). {print,tag1} 3> print:instance(tag2). {print,tag2} 4> print:message("hello", print:new(tag1)). tag1: 'hello' ok main.S 就是这么调用我们的print模块的。 {move,{literal,"Dumpty"},{x,0}}. {call_ext,1,{extfunc,print,new,1}}. {move,{x,0},{x,3}}. {move,{y,0},{x,1}}. {move,{atom,message},{x,2}}. {move,{literal,"Hello!"},{x,0}}. {move,{x,3},{y,0}}. {apply,1}. 压入的参数正是 (Message, print:new(tag)), 然后是apply opcode. 我们看下apply opcode: OpCase(i_apply): { Eterm* next; SWAPOUT; next = apply(c_p, r(0), x(1), x(2), reg); SWAPIN; if (next != NULL) { r(0) = reg[0]; SET_CP(c_p, I+1); SET_I(next); Dispatch(); } I = handle_error(c_p, I, reg, apply_3); goto post_error_handling; } static Uint* apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) { int arity; Export* ep; Eterm tmp, this; /* * Check the arguments which should be of the form apply(Module, * Function, Arguments) where Function is an atom and * Arguments is an arity long list of terms. */ if (is_not_atom(function)) { /* * No need to test args here -- done below. */ error: p->freason = BADARG; error2: reg[0] = module; reg[1] = function; reg[2] = args; return 0; } /* The module argument may be either an atom or an abstract module * (currently implemented using tuples, but this might change). */ this = THE_NON_VALUE; if (is_not_atom(module)) { Eterm* tp; if (is_not_tuple(module)) goto error; tp = tuple_val(module); if (arityval(tp[0]) < 1) goto error; this = module; module = tp[1]; if (is_not_atom(module)) goto error; } /* * Walk down the 3rd parameter of apply (the argument list) and copy * the parameters to the x registers (reg[]). If the module argument * was an abstract module, add 1 to the function arity and put the * module argument in the n+1st x register as a THIS reference. */ tmp = args; arity = 0; while (is_list(tmp)) { if (arity < (MAX_REG - 1)) { reg[arity++] = CAR(list_val(tmp)); tmp = CDR(list_val(tmp)); } else { p->freason = SYSTEM_LIMIT; goto error2; } } if (is_not_nil(tmp)) { /* Must be well-formed list */ goto error; } if (this != THE_NON_VALUE) { reg[arity++] = this; } ... } 上面的代码就是干我们上面解释的事情的。 结论: 模块参数化完全是个语法糖, 没有任何magic。所以这个特性在hipe下也可以放心大胆用。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-09-25
哈哈,不错,本来只知其然,现在知道一点所以然了
|
|
返回顶楼 | |
发表时间:2010-08-18
在这儿我知道了,这种方法如何应用,而且是可以应用的。后面具体的解释以后看,貌似有点麻烦。先知其然吧。
|
|
返回顶楼 | |