Hidden Features of Erlang [closed]

2019-01-12 14:05发布

问题:

In the spirit of:

  • Hidden Features of C#
  • Hidden Features of Java
  • Hidden Features of ASP.NET
  • Hidden Features of Python
  • Hidden Features of HTML
  • and other Hidden Features questions

What are the hidden features of Erlang that every Erlang developer should be aware of?

One hidden feature per answer, please.

回答1:

The magic commands in the shell. The full list is in the manual, but the ones I use most are:

  • f() - forget all variables
  • f(X) - forget X
  • v(42) - recall result from line 42
  • v(-1) - recall result from previous line
  • e(-1) - reexecute expression on previous line
  • rr(foo) - read record definitions from module foo
  • rr("*/*") - read record definitions from every module in every subdirectory
  • rp(expression) - print full expression with record formating


回答2:

Inheritance! http://www.erlang.se/euc/07/papers/1700Carlsson.pdf

Parent

-module(parent).
-export([foo/0, bar/0]).

foo() ->
    io:format("parent:foo/0 ~n", []).

bar() ->
    io:format("parent:bar/0 ~n", []).

Child

-module(child).
-extends(parent).
-export([foo/0]).

foo() ->
    io:format("child:foo/0 ~n", []).

Console

23> parent:foo().
parent:foo/0 
ok
24> parent:bar().
parent:bar/0 
ok
25> child:foo().
child:foo/0 
ok
26> child:bar().
parent:bar/0 
ok


回答3:

Parameterized Modules! From http://www.lshift.net/blog/2008/05/18/late-binding-with-erlang and http://www.erlang.se/euc/07/papers/1700Carlsson.pdf

-module(myclass, [Instvar1, Instvar2]).
-export([getInstvar1/0, getInstvar2/0]).
getInstvar1() -> Instvar1.
getInstvar2() -> Instvar2.

And

Eshell V5.6  (abort with ^G)
1> Handle = myclass:new(123, 234).
{myclass,123,234}
2> Handle:getInstvar1().
123
3> Handle:getInstvar2().
234


回答4:

user_default.erl - you can build your own shell builtins by having a compiled user_default.beam in your path which can be pretty nifty



回答5:

beam_lib:chunks can get source code from a beam that was compiled with debug on which can be really usefull

{ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(Beam,[abstract_code]).
  io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).


回答6:

Ports, external or linked-in, accept something called io-lists for sending data to them. An io-list is a binary or a (possibly deep) list of binaries or integers in the range 0..255.

This means that rather than concatenating two lists before sending them to a port, one can just send them as two items in a list. So instead of

"foo" ++ "bar"

one do

["foo", "bar"]

In this example it is of course of miniscule difference. But the iolist in itself allows for convenient programming when creating output data. io_lib:format/2,3 itself returns an io list for example.

The function erlang:list_to_binary/1 accepts io lists, but now we have erlang:iolist_to_binary/1 which convey the intention better. There is also an erlang:iolist_size/1.

Best of all, since files and sockets are implemented as ports, you can send iolists to them. No need to flatten or append.



回答7:

That match specifications can be built using ets:fun2ms(...) where the Erlang fun syntax is used and translated into a match specification with a parse transform.

1> ets:fun2ms(fun({Foo, _, Bar}) when Foo > 0 -> {Foo, Bar} end).
[{{'$1','_','$2'},[{'>','$1',0}],[{{'$1','$2'}}]}]

So no fun-value is ever built, the expression gets replaced with the match-spec at compile-time. The fun may only do things a match expression could do.

Also, ets:fun2ms is available for usage in the shell, so fun-expressions can be tested easily.



回答8:

.erlang_hosts gives a nice way to share names across machines



回答9:

Not necessarily "hidden", but I don't see this often. Anonymous functions can have multiple clauses, just like module functions, i.e.

-module(foo).
-compile(export_all).

foo(0) -> "zero";
foo(1) -> "one";
foo(_) -> "many".

anon() ->
    fun(0) ->
            "zero";
       (1) ->
            "one";
       (_) ->
            "many"
    end.


1> foo:foo(0).
"zero"
2> foo:foo(1).
"one"
3> foo:foo(2).
"many"

4> (foo:anon())(0).
"zero"
5> (foo:anon())(1).
"one"
6> (foo:anon())(2).
"many"


回答10:

The gen___tcp and ssl sockets have a {packet, Type} socket option to aid in decoding a number of protocols. The function erlang:decode_packet/3 has a good description on what the various Type values can be and what they do.

Together with a {active, once} or {active, true} setting, each framed value will be delivered as a single message.

Examples: the packet http mode is used heavily for iserve and the packet fcgi mode for ifastcgi. I can imagine that many of the other http servers use packet http as well.



回答11:

.erlang can preload libraries and run commands on a shells startup, you can also do specific commands for specific nodes by doing a case statement on node name.



回答12:

If you want to execute more than one expression in a list comprehension, you can use a block. For example:

> [begin erlang:display(N), N*10 end || N <- lists:seq(1,3)].
1
2
3
[10,20,30]


回答13:

It is possible to define your own iterator for QLC to use. For example, a result set from an SQL query could be made into a QLC table, and thus benefit from the features of QLC queries.

Besides mnesia tables, dets and ets have the table/1,2 functions to return such a "Query Handle" for them.



回答14:

Not so hidden, but one of the most important aspects, when chosing Erlang as platform for development:

  • Possibility of enhanced tracing on live nodes (in-service) and being one of the best in debugging!


回答15:

You can hide an Erlang node by starting it with:

erl -sname foo -hidden

You can still connect to the node, but it won't appear in the list returned by nodes/0.



回答16:

Matching with the append operator:

"pajamas:" ++ Color = "pajamas:blue"

Color now has the value "blue". Be aware that this trick has it’s limitations - as far as I know it only works with a single variable and a single constant in the order given above.



回答17:

Hot code loading. From wiki.

Code is loaded and managed as "module" units, the module is a compilation unit. The system can keep two versions of a module in memory at the same time, and processes can concurrently run code from each.

The versions are referred to the "new" and the "old" version. A process will not move into the new version until it makes an external call to its module.