From 68d53c01b0b8e9a007a6a30158c19e34b2d2a34e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?=
Date: Wed, 18 May 2016 15:53:35 +0200
Subject: Update STDLIB documentation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Language cleaned up by the technical writers xsipewe and tmanevik
from Combitech. Proofreading and corrections by Björn Gustavsson
and Hans Bolinder.
---
lib/stdlib/doc/src/ms_transform.xml | 958 +++++++++++++++++++++---------------
1 file changed, 549 insertions(+), 409 deletions(-)
(limited to 'lib/stdlib/doc/src/ms_transform.xml')
diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml
index 84712486ea..0a05fa37c5 100644
--- a/lib/stdlib/doc/src/ms_transform.xml
+++ b/lib/stdlib/doc/src/ms_transform.xml
@@ -28,65 +28,81 @@
1Bjarne Däcker
- 99-02-09
+ 1999-02-09C
- ms_transform.sgml
+ ms_transform.xmlms_transform
- Parse_transform that translates fun syntax into match specifications.
+ A parse transformation that translates fun syntax into match
+ specifications.
-
This module implements the parse_transform that makes calls to
- ets and dbg:fun2ms/1 translate into literal
- match specifications. It also implements the back end for the same
- functions when called from the Erlang shell.
-
The translations from fun's to match_specs
- is accessed through the two "pseudo
- functions" ets:fun2ms/1 and dbg:fun2ms/1.
-
Actually this introduction is more or less an introduction to the
- whole concept of match specifications. Since everyone trying to use
- ets:select or dbg seems to end up reading
- this page, it seems in good place to explain a little more than
- just what this module does.
-
There are some caveats one should be aware of, please read through
- the whole manual page if it's the first time you're using the
- transformations.
-
Match specifications are used more or less as filters.
- They resemble usual Erlang matching in a list comprehension or in
- a fun used in conjunction with lists:foldl etc. The
- syntax of pure match specifications is somewhat awkward though, as
- they are made up purely by Erlang terms and there is no syntax in the
- language to make the match specifications more readable.
-
As the match specifications execution and structure is quite like
- that of a fun, it would for most programmers be more straight forward
- to simply write it using the familiar fun syntax and having that
- translated into a match specification automatically. Of course a real
- fun is more powerful than the match specifications allow, but bearing
- the match specifications in mind, and what they can do, it's still
+
This module provides the parse transformation that makes calls to
+ ets and
+ dbg:fun2ms/1
+ translate into literal match specifications. It also provides the back end
+ for the same functions when called from the Erlang shell.
+
+
The translation from funs to match specifications
+ is accessed through the two "pseudo functions"
+ ets:fun2ms/1 and
+ dbg:fun2ms/1.
+
+
As everyone trying to use
+ ets:select/2 or
+ dbg seems to end up
+ reading this manual page, this description is an introduction to the
+ concept of match specifications.
+
+
Read the whole manual page if it is the first time you are using
+ the transformations.
+
+
Match specifications are used more or less as filters. They resemble
+ usual Erlang matching in a list comprehension or in a fun used with
+ lists:foldl/3, and so on.
+ However, the syntax of pure match specifications is awkward, as
+ they are made up purely by Erlang terms, and the language has no
+ syntax to make the match specifications more readable.
+
+
As the execution and structure of the match specifications are like
+ that of a fun, it is more straightforward
+ to write it using the familiar fun syntax and to have that
+ translated into a match specification automatically. A real fun is
+ clearly more powerful than the match specifications allow, but bearing
+ the match specifications in mind, and what they can do, it is still
more convenient to write it all as a fun. This module contains the
- code that simply translates the fun syntax into match_spec terms.
-
Let's start with an ets example. Using ets:select and
- a match specification, one can filter out rows of a table and construct
- a list of tuples containing relevant parts of the data in these
- rows. Of course one could use ets:foldl instead, but the
- select call is far more efficient. Without the translation, one has to
- struggle with writing match specifications terms to accommodate this,
- or one has to resort to the less powerful
- ets:match(_object) calls, or simply give up and use
- the more inefficient method of ets:foldl. Using the
- ets:fun2ms transformation, a ets:select call
- is at least as easy to write as any of the alternatives.
-
As an example, consider a simple table of employees:
+ code that translates the fun syntax into match specification
+ terms.
+
+
+
+ Example 1
+
Using ets:select/2
+ and a match specification, one can filter out rows of
+ a table and construct a list of tuples containing relevant parts
+ of the data in these rows.
+ One can use ets:foldl/3
+ instead, but the ets:select/2 call is far more efficient.
+ Without the translation provided by ms_transform,
+ one must struggle with writing match specifications terms
+ to accommodate this.
+
+
Consider a simple table of employees:
+
-record(emp, {empno, %Employee number as a string, the key
surname, %Surname of the employee
givenname, %Given name of employee
- dept, %Department one of {dev,sales,prod,adm}
- empyear}). %Year the employee was employed
+ dept, %Department, one of {dev,sales,prod,adm}
+ empyear}). %Year the employee was employed
+
Now, the amount of data in the table is of course to small to justify
- complicated ets searches, but on real tables, using select to get
- exactly the data you want will increase efficiency remarkably.
-
Lets say for example that we'd want the employee numbers of
- everyone in the sales department. One might use ets:match
- in such a situation:
+ {emp,"989891","Brown","Gabriel",prod,1999}]
+
+
Assuming that we want the employee numbers of everyone in the sales
+ department, there are several ways.
Even though ets:match does not require a full match
- specification, but a simpler type, it's still somewhat unreadable, and
- one has little control over the returned result, it's always a list of
- lists. OK, one might use ets:foldl or
- ets:foldr instead:
+[["011103"],["076324"]]
+
+
ets:match/2 uses a simpler type of match specification,
+ but it is still unreadable, and one has little control over the
+ returned result. It is always a list of lists.
+
+
ets:foldl/3 or
+ ets:foldr/3 can be used to avoid the nested lists:
Running that would result in ["011103","076324"]
- , which at least gets rid of the extra lists. The fun is also quite
+ emp_tab).
+
+
The result is ["011103","076324"]. The fun is
straightforward, so the only problem is that all the data from the
- table has to be transferred from the table to the calling process for
- filtering. That's inefficient compared to the ets:match
+ table must be transferred from the table to the calling process for
+ filtering. That is inefficient compared to the ets:match/2
call where the filtering can be done "inside" the emulator and only
- the result is transferred to the process. Remember that ets tables are
- all about efficiency, if it wasn't for efficiency all of ets could be
- implemented in Erlang, as a process receiving requests and sending
- answers back. One uses ets because one wants performance, and
- therefore one wouldn't want all of the table transferred to the
- process for filtering. OK, let's look at a pure
- ets:select call that does what the ets:foldr
- does:
+ the result is transferred to the process.
+
+
Consider a "pure" ets:select/2 call that does what
+ ets:foldr does:
Even though the record syntax is used, it's still somewhat hard to
+ets:select(emp_tab, [{#emp{empno = '$1', dept = sales, _='_'},[],['$1']}]).
+
+
Although the record syntax is used, it is still hard to
read and even harder to write. The first element of the tuple,
- #emp{empno = '$1', dept = sales, _='_'} tells what to
- match, elements not matching this will not be returned at all, as in
- the ets:match example. The second element, the empty list
- is a list of guard expressions, which we need none, and the third
+ #emp{empno = '$1', dept = sales, _='_'}, tells what to
+ match. Elements not matching this are not returned, as in
+ the ets:match/2 example. The second element, the empty list,
+ is a list of guard expressions, which we do not need. The third
element is the list of expressions constructing the return value (in
- ets this almost always is a list containing one single term). In our
- case '$1' is bound to the employee number in the head
- (first element of tuple), and hence it is the employee number that is
- returned. The result is ["011103","076324"], just as in
- the ets:foldr example, but the result is retrieved much
- more efficiently in terms of execution speed and memory consumption.
-
We have one efficient but hardly readable way of doing it and one
- inefficient but fairly readable (at least to the skilled Erlang
- programmer) way of doing it. With the use of ets:fun2ms,
- one could have something that is as efficient as possible but still is
- written as a filter using the fun syntax:
+ ETS this is almost always a list containing one single term).
+ In our case '$1' is bound to the employee number in the head
+ (first element of the tuple), and hence the employee number is
+ returned. The result is ["011103","076324"], as in
+ the ets:foldr/3 example, but the result is retrieved much
+ more efficiently in terms of execution speed and
+ memory consumption.
+
+
Using ets:fun2ms/1, we can combine the ease of use of
+ the ets:foldr/3 and the efficiency of the pure
+ ets:select/2 example:
+
-include_lib("stdlib/include/ms_transform.hrl").
-% ...
-
ets:select(emp_tab, ets:fun2ms(
fun(#emp{empno = E, dept = sales}) ->
E
- end)).
-
This may not be the shortest of the expressions, but it requires no
- special knowledge of match specifications to read. The fun's head
- should simply match what you want to filter out and the body returns
- what you want returned. As long as the fun can be kept within the
- limits of the match specifications, there is no need to transfer all
- data of the table to the process for filtering as in the
- ets:foldr example. In fact it's even easier to read then
- the ets:foldr example, as the select call in itself
- discards anything that doesn't match, while the fun of the
- foldr call needs to handle both the elements matching and
- the ones not matching.
-
It's worth noting in the above ets:fun2ms example that one
- needs to include ms_transform.hrl in the source code, as this is
- what triggers the parse transformation of the ets:fun2ms call
- to a valid match specification. This also implies that the
- transformation is done at compile time (except when called from the
- shell of course) and therefore will take no resources at all in
- runtime. So although you use the more intuitive fun syntax, it gets as
- efficient in runtime as writing match specifications by hand.
-
Let's look at some more ets examples. Let's say one
- wants to get all the employee numbers of any employee hired before the
- year 2000. Using ets:match isn't an alternative here as
- relational operators cannot be expressed there. Once again, an
- ets:foldr could do it (slowly, but correct):
+ end)).
+
+
This example requires no special knowledge of match
+ specifications to understand. The head of the fun matches what
+ you want to filter out and the body returns what you want
+ returned. As long as the fun can be kept within the limits of the
+ match specifications, there is no need to transfer all table data
+ to the process for filtering as in the ets:foldr/3
+ example. It is easier to read than the ets:foldr/3 example,
+ as the select call in itself discards anything that does not
+ match, while the fun of the ets:foldr/3 call needs to
+ handle both the elements matching and the ones not matching.
+
+
In the ets:fun2ms/1 example above, it is needed to
+ include ms_transform.hrl in the source code, as this is
+ what triggers the parse transformation of the ets:fun2ms/1
+ call to a valid match specification. This also implies that the
+ transformation is done at compile time (except when called from
+ the shell) and therefore takes no resources in runtime. That is,
+ although you use the more intuitive fun syntax, it gets as
+ efficient in runtime as writing match specifications by hand.
+
+
+
+ Example 2
+
Assume that we want to get all the employee numbers of employees
+ hired before year 2000. Using ets:match/2 is not
+ an alternative here, as relational operators cannot be
+ expressed there.
+ Once again, ets:foldr/3 can do it (slowly, but correct):
The result will be
- ["052341","076324","535216","789789","989891"], as
- expected. Now the equivalent expression using a handwritten match
- specification would look something like this:
+
+
The result is ["052341","076324","535216","789789","989891"],
+ as expected. The equivalent expression using a handwritten match
+ specification would look like this:
+
-
This gives the same result, the is in
- the guard part and therefore discards anything that does not have a
- empyear (bound to '$2' in the head) less than 2000, just as the guard
- in the foldl example. Lets jump on to writing it using
- ets:fun2ms
+
+
This gives the same result. is in
+ the guard part and therefore discards anything that does not have an
+ empyear (bound to '$2' in the head) less than 2000, as
+ the guard in the foldr/3 example.
+
+
We write it using ets:fun2ms/1:
+
- E
+ E
end)). ]]>
-
Obviously readability is gained by using the parse transformation.
-
I'll show some more examples without the tiresome
- comparing-to-alternatives stuff. Let's say we'd want the whole object
- matching instead of only one element. We could of course assign a
- variable to every part of the record and build it up once again in the
- body of the fun, but it's easier to do like this:
+
+
+
+ Example 3
+
Assume that we want the whole object matching instead of only one
+ element. One alternative is to assign a variable to every part
+ of the record and build it up once again in the body of the fun, but
+ the following is easier:
+
Obj
- end)). ]]>
-
Just as in ordinary Erlang matching, you can bind a variable to the
- whole matched object using a "match in then match", i.e. a
- =. Unfortunately this is not general in fun's translated
- to match specifications, only on the "top level", i.e. matching the
- whole object arriving to be matched into a separate variable,
- is it allowed. For the one's used to writing match specifications by
- hand, I'll have to mention that the variable A will simply be
- translated into '$_'. It's not general, but it has very common usage,
- why it is handled as a special, but useful, case. If this bothers you,
- the pseudo function object also returns the whole matched
- object, see the part about caveats and limitations below.
-
Let's do something in the fun's body too: Let's say
- that someone realizes that there are a few people having an employee
- number beginning with a zero (0), which shouldn't be
- allowed. All those should have their numbers changed to begin with a
- one (1) instead and one wants the
- list ,}]]]> created:
+ end)).]]>
+
+
As in ordinary Erlang matching, you can bind a variable to the
+ whole matched object using a "match inside the match", that is, a
+ =. Unfortunately in funs translated to match specifications,
+ it is allowed only at the "top-level", that is,
+ matching the whole object arriving to be matched
+ into a separate variable.
+ If you are used to writing match specifications by hand, we
+ mention that variable A is simply translated into '$_'.
+ Alternatively, pseudo function object/0
+ also returns the whole matched object, see section
+
+ Warnings and Restrictions.
+
+
+
+ Example 4
+
This example concerns the body of the fun. Assume that all employee
+ numbers beginning with zero (0) must be changed to begin with
+ one (1) instead, and that we want to create the list
+ ,}]]]>:
As a matter of fact, this query hits the feature of partially bound
- keys in the table type ordered_set, so that not the whole
- table need be searched, only the part of the table containing keys
- beginning with 0 is in fact looked into.
-
The fun of course can have several clauses, so that if one could do
- the following: For each employee, if he or she is hired prior to 1997,
- return the tuple }]]>, for each hired 1997
- or later, but before 2001, return }]]>, for all others return }]]>. All except for the ones named Smith as
- they would be affronted by anything other than the tag
- guru and that is also what's returned for their numbers;
- }]]>:
+ end)).
+
+
This query hits the feature of partially bound
+ keys in table type ordered_set, so that not the whole
+ table needs to be searched, only the part containing keys
+ beginning with 0 is looked into.
+
+
+
+ Example 5
+
The fun can have many clauses. Assume that we want to do
+ the following:
+
+
+
+
If an employee started before 1997, return the tuple
+ }]]>.
+
+
+
If an employee started 1997 or later, but before 2001, return
+ }]]>.
+
+
+
For all other employees, return
+ }]]>, except for those
+ named Smith as they would be affronted by anything other
+ than the tag guru and that is also what is returned for their
+ numbers: }]]>.
So, what more can you do? Well, the simple answer would be; look
- in the documentation of match specifications in ERTS users
- guide. However let's briefly go through the most useful "built in
- functions" that you can use when the fun is to be
- translated into a match specification by ets:fun2ms (it's
- worth mentioning, although it might be obvious to some, that calling
- other functions than the one's allowed in match specifications cannot
- be done. No "usual" Erlang code can be executed by the fun being
- translated by fun2ms, the fun is after all limited
+ {rookie,"989891"}]
+
+
+
+ Useful BIFs
+
What more can you do? A simple answer is: see the documentation of
+ match specifications
+ in ERTS User's Guide.
+ However, the following is a brief overview of the most useful "built-in
+ functions" that you can use when the fun is to be translated into a match
+ specification by
+ ets:fun2ms/1. It is not
+ possible to call other functions than those allowed in match
+ specifications. No "usual" Erlang code can be executed by the fun that
+ is translated by ets:fun2ms/1. The fun is limited
exactly to the power of the match specifications, which is
- unfortunate, but the price one has to pay for the execution speed of
- an ets:select compared to ets:foldl/foldr).
-
The head of the fun is obviously a head matching (or mismatching)
- one parameter, one object of the table we select
+ unfortunate, but the price one must pay for the execution speed of
+ ets:select/2 compared to ets:foldl/foldr.
+
+
The head of the fun is a head matching (or mismatching)
+ one parameter, one object of the table we select
from. The object is always a single variable (can be _) or
- a tuple, as that's what's in ets, dets and
- mnesia tables (the match specification returned by
- ets:fun2ms can of course be used with
- dets:select and mnesia:select as well as
- with ets:select). The use of = in the head
- is allowed (and encouraged) on the top level.
+ a tuple, as ETS, Dets, and Mnesia tables include
+ that. The match specification returned by ets:fun2ms/1 can
+ be used with dets:select/2 and mnesia:select/2, and
+ with ets:select/2. The use of = in the head
+ is allowed (and encouraged) at the top-level.
+
The guard section can contain any guard expression of Erlang.
- Even the "old" type test are allowed on the toplevel of the guard
- (integer(X) instead of is_integer(X)). As the new type tests (the
- is_ tests) are in practice just guard bif's they can also
- be called from within the body of the fun, but so they can in ordinary
- Erlang code. Also arithmetics is allowed, as well as ordinary guard
- bif's. Here's a list of bif's and expressions:
+ The following is a list of BIFs and expressions:
+
- The type tests: is_atom, is_float, is_integer,
- is_list, is_number, is_pid, is_port, is_reference, is_tuple,
- is_binary, is_function, is_record
- The boolean operators: not, and, or, andalso, orelse
- The relational operators: >, >=, <, =<, =:=, ==, =/=, /=
- Arithmetics: +, -, *, div, rem
- Bitwise operators: band, bor, bxor, bnot, bsl, bsr
- The guard bif's: abs, element, hd, length, node, round, size, tl,
- trunc, self
- The obsolete type test (only in guards):
- atom, float, integer,
- list, number, pid, port, reference, tuple,
- binary, function, record
+
+
Contrary to the fact with "handwritten" match specifications, the
is_record guard works as in ordinary Erlang code.
-
Semicolons (;) in guards are allowed, the result will be (as
- expected) one "match_spec-clause" for each semicolon-separated
- part of the guard. The semantics being identical to the Erlang
+
+
Semicolons (;) in guards are allowed, the result is (as
+ expected) one "match specification clause" for each semicolon-separated
+ part of the guard. The semantics is identical to the Erlang
semantics.
-
The body of the fun is used to construct the
- resulting value. When selecting from tables one usually just construct
+
+
The body of the fun is used to construct the
+ resulting value. When selecting from tables, one usually construct
a suiting term here, using ordinary Erlang term construction, like
- tuple parentheses, list brackets and variables matched out in the
- head, possibly in conjunction with the occasional constant. Whatever
- expressions are allowed in guards are also allowed here, but there are
- no special functions except object and
+ tuple parentheses, list brackets, and variables matched out in the
+ head, possibly with the occasional constant. Whatever
+ expressions are allowed in guards are also allowed here, but no special
+ functions exist except object and
bindings (see further down), which returns the whole
- matched object and all known variable bindings respectively.
+ matched object and all known variable bindings, respectively.
+
The dbg variants of match specifications have an
- imperative approach to the match specification body, the ets dialect
- hasn't. The fun body for ets:fun2ms returns the result
- without side effects, and as matching (=) in the body of
+ imperative approach to the match specification body, the ETS
+ dialect has not. The fun body for ets:fun2ms/1 returns the result
+ without side effects. As matching (=) in the body of
the match specifications is not allowed (for performance reasons) the
- only thing left, more or less, is term construction...
-
Let's move on to the dbg dialect, the slightly
- different match specifications translated by dbg:fun2ms.
-
The same reasons for using the parse transformation applies to
- dbg, maybe even more so as filtering using Erlang code is
- simply not a good idea when tracing (except afterwards, if you trace
- to file). The concept is similar to that of ets:fun2ms
- except that you usually use it directly from the shell (which can also
- be done with ets:fun2ms).
-
Let's manufacture a toy module to trace on
+ only thing left, more or less, is term construction.
+
+
+
+ Example with dbg
+
This section describes the slightly different match specifications
+ translated by
+ dbg:fun2ms/1.
+
+
The same reasons for using the parse transformation apply to
+ dbg, maybe even more, as filtering using Erlang code is
+ not a good idea when tracing (except afterwards, if you trace
+ to file). The concept is similar to that of ets:fun2ms/1
+ except that you usually use it directly from the shell
+ (which can also be done with ets:fun2ms/1).
During model testing, the first test bails out with a
+ [{Key, Value}] = ets:lookup(toy_table, Key),
+ Value.
+
+
During model testing, the first test results in
{badmatch,16} in {toy,start,1}, why?
-
We suspect the ets call, as we match hard on the return value, but
- want only the particular new call with
- toy_table as first parameter.
- So we start a default tracer on the node:
+
+
We suspect the ets:new/2 call, as we match hard on the
+ return value, but want only the particular new/2 call with
+ toy_table as first parameter. So we start a default tracer
+ on the node:
+
1> dbg:tracer().
{ok,<0.88.0>}
-
And so we turn on call tracing for all processes, we are going to
- make a pretty restrictive trace pattern, so there's no need to call
- trace only a few processes (it usually isn't):
+
+
We turn on call tracing for all processes, we want to
+ make a pretty restrictive trace pattern, so there is no need to call
+ trace only a few processes (usually it is not):
As can be seen, the fun's used with
- dbg:fun2ms takes a single list as parameter instead of a
+{ok,[{matched,nonode@nohost,1},{saved,1}]}
+
+
As can be seen, the fun used with
+ dbg:fun2ms/1 takes a single list as parameter instead of a
single tuple. The list matches a list of the parameters to the traced
- function. A single variable may also be used of course. The body
- of the fun expresses in a more imperative way actions to be taken if
- the fun head (and the guards) matches. I return true here, but it's
- only because the body of a fun cannot be empty, the return value will
- be discarded.
-
When we run the test of our module now, we get the following trace
- output:
+ function. A single variable can also be used. The body
+ of the fun expresses, in a more imperative way, actions to be taken if
+ the fun head (and the guards) matches. true is returned here,
+ only because the body of a fun cannot be empty. The return value
+ is discarded.
+
+
The following trace output is received during test:
+
) call ets:new(toy_table,[ordered_set]) ]]>
-
Let's play we haven't spotted the problem yet, and want to see what
- ets:new returns. We do a slightly different trace
- pattern:
Resulting in the following trace output when we run the test:
+
+
The following trace output is received during test:
+
) call ets:new(toy_table,[ordered_set])
(<0.86.0>) returned from ets:new/2 -> 24 ]]>
-
The call to return_trace, makes a trace message appear
+
+
The call to return_trace results in a trace message
when the function returns. It applies only to the specific function call
triggering the match specification (and matching the head/guards of
- the match specification). This is the by far the most common call in the
+ the match specification). This is by far the most common call in the
body of a dbg match specification.
-
As the test now fails with {badmatch,24}, it's obvious
- that the badmatch is because the atom toy_table does not
- match the number returned for an unnamed table. So we spotted the
- problem, the table should be named and the arguments supplied by our
- test program does not include named_table. We rewrite the
- start function to:
+
+
The test now fails with {badmatch,24} because the atom
+ toy_table does not match the number returned for an unnamed table.
+ So, the problem is found, the table is to be named, and the arguments
+ supplied by the test program do not include named_table. We
+ rewrite the start function:
With the same tracing turned on, the following trace output is
+ received:
+
) call ets:new(toy_table,[named_table,ordered_set])
(<0.86.0>) returned from ets:new/2 -> toy_table ]]>
-
Very well. Let's say the module now passes all testing and goes into
- the system. After a while someone realizes that the table
- toy_table grows while the system is running and that for some
- reason there are a lot of elements with atom's as keys. You had
- expected only integer keys and so does the rest of the system. Well,
- obviously not all of the system. You turn on call tracing and try to
- see calls to your module with an atom as the key:
+
+
Assume that the module now passes all testing and goes into
+ the system. After a while, it is found that table
+ toy_table grows while the system is running and that
+ there are many elements with atoms as keys. We expected
+ only integer keys and so does the rest of the system, but
+ clearly not the entire system. We turn on call tracing and try to
+ see calls to the module with an atom as the key:
We use dbg:tpl here to make sure to catch local calls
- (let's say the module has grown since the smaller version and we're
- not sure this inserting of atoms is not done locally...). When in
- doubt always use local call tracing.
-
Let's say nothing happens when we trace in this way. Our function
- is never called with these parameters. We make the conclusion that
- someone else (some other module) is doing it and we realize that we
- must trace on ets:insert and want to see the calling function. The
- calling function may be retrieved using the match specification
- function caller and to get it into the trace message, one
- has to use the match spec function message. The filter
- call looks like this (looking for calls to ets:insert):
+
+
We use dbg:tpl/3 to ensure to catch local calls
+ (assume that the module has grown since the smaller version and we are
+ unsure if this inserting of atoms is not done locally). When in
+ doubt, always use local call tracing.
+
+
Assume that nothing happens when tracing in this way. The function
+ is never called with these parameters. We conclude that
+ someone else (some other module) is doing it and realize that we
+ must trace on ets:insert/2 and want to see the calling function.
+ The calling function can be retrieved using the match specification
+ function caller. To get it into the trace message, the match
+ specification function message must be used. The filter
+ call looks like this (looking for calls to ets:insert/2):
+
4> dbg:tpl(ets,insert,dbg:fun2ms(fun([toy_table,{A,_}]) when is_atom(A) ->
message(caller())
end)).
-{ok,[{matched,nonode@nohost,1},{saved,2}]}
-
The caller will now appear in the "additional message" part of the
- trace output, and so after a while, the following output comes:
+{ok,[{matched,nonode@nohost,1},{saved,2}]}
+
+
The caller is now displayed in the "additional message" part of the
+ trace output, and the following is displayed after a while:
You have found out that the function evil_fun of the
- module evil_mod, with arity 2, is the one
- causing all this trouble.
-
This was just a toy example, but it illustrated the most used
- calls in match specifications for dbg The other, more
- esotheric calls are listed and explained in the Users guide of the ERTS application, they really are beyond the scope of this
- document.
-
To end this chatty introduction with something more precise, here
- follows some parts about caveats and restrictions concerning the fun's
- used in conjunction with ets:fun2ms and
- dbg:fun2ms:
+
+
You have realized that function evil_fun of the
+ evil_mod module, with arity 2, is causing all this trouble.
+
+
+
This example illustrates the most used calls in match specifications for
+ dbg. The other, more esoteric, calls are listed and explained in
+ Match specifications in Erlang
+ in ERTS User's Guide, as they are beyond
+ the scope of this description.
+
+
+
+ Warnings and Restrictions
+
+
The following warnings and restrictions apply to the funs used in
+ with ets:fun2ms/1 and dbg:fun2ms/1.
+
-
To use the pseudo functions triggering the translation, one
- has to include the header file ms_transform.hrl
- in the source code. Failure to do so will possibly result in
- runtime errors rather than compile time, as the expression may
+
To use the pseudo functions triggering the translation,
+ ensure to include the header file ms_transform.hrl
+ in the source code. Failure to do so possibly results in
+ runtime errors rather than compile time, as the expression can
be valid as a plain Erlang program without translation.
+
-
The fun has to be literally constructed inside the
- parameter list to the pseudo functions. The fun cannot
+
The fun must be literally constructed inside the
+ parameter list to the pseudo functions. The fun cannot
be bound to a variable first and then passed to
- ets:fun2ms or dbg:fun2ms, i.e this
- will work: ets:fun2ms(fun(A) -> A end) but not this:
- F = fun(A) -> A end, ets:fun2ms(F). The later will result
- in a compile time error if the header is included, otherwise a
- runtime error. Even if the later construction would ever
- appear to work, it really doesn't, so don't ever use it.
+ ets:fun2ms/1 or dbg:fun2ms/1. For example,
+ ets:fun2ms(fun(A) -> A end) works, but not
+ F = fun(A) -> A end, ets:fun2ms(F). The latter results
+ in a compile-time error if the header is included, otherwise a
+ runtime error.
-
Several restrictions apply to the fun that is being translated
- into a match_spec. To put it simple you cannot use anything in
- the fun that you cannot use in a match_spec. This means that,
+
+
Many restrictions apply to the fun that is translated into a match
+ specification. To put it simple: you cannot use anything in the fun
+ that you cannot use in a match specification. This means that,
among others, the following restrictions apply to the fun itself:
+
- Functions written in Erlang cannot be called, neither
- local functions, global functions or real fun's
- Everything that is written as a function call will be
- translated into a match_spec call to a builtin function, so that
- the call is_list(X) will be translated to {'is_list', '$1'} ('$1' is just an example, the numbering may
- vary). If one tries to call a function that is not a match_spec
- builtin, it will cause an error.
- Variables occurring in the head of the fun will be
- replaced by match_spec variables in the order of occurrence, so
- that the fragment fun({A,B,C}) will be replaced by
- {'$1', '$2', '$3'} etc. Every occurrence of such a
- variable later in the match_spec will be replaced by a
- match_spec variable in the same way, so that the fun
- fun({A,B}) when is_atom(A) -> B end will be translated into
- [{{'$1','$2'},[{is_atom,'$1'}],['$2']}].
-
Variables that are not appearing in the head are imported
- from the environment and made into
- match_spec const expressions. Example from the shell:
+
Functions written in Erlang cannot be called, neither can
+ local functions, global functions, or real funs.
+
+
+
Everything that is written as a function call is translated
+ into a match specification call to a built-in function, so that
+ the call is_list(X) is translated to {'is_list', '$1'}
+ ('$1' is only an example, the numbering can vary).
+ If one tries to call a function that is not a match specification
+ built-in, it causes an error.
+
+
+
Variables occurring in the head of the fun are replaced by
+ match specification variables in the order of occurrence, so
+ that fragment fun({A,B,C}) is replaced by
+ {'$1', '$2', '$3'}, and so on. Every occurrence of such a
+ variable in the match specification is replaced by a match
+ specification variable in the same way, so that the fun
+ fun({A,B}) when is_atom(A) -> B end is translated into
+ [{{'$1','$2'},[{is_atom,'$1'}],['$2']}].
+
+
+
Variables that are not included in the head are imported
+ from the environment and made into match specification
+ const expressions. Example from the shell:
1> X = 25.
25
@@ -523,7 +644,7 @@ start(Args) ->
Matching with = cannot be used in the body. It can only
- be used on the top level in the head of the fun.
+ be used on the top-level in the head of the fun.
Example from the shell again:
1> ets:fun2ms(fun({A,[B|C]} = D) when A > B -> D end).
@@ -534,106 +655,125 @@ match_spec
{error,transform_error}
3> ets:fun2ms(fun({A,[B|C]}) when A > B -> D = [B|C], D end).
Error: fun with body matching ('=' in body) is illegal as match_spec
-{error,transform_error}
-
All variables are bound in the head of a match_spec, so the
- translator can not allow multiple bindings. The special case
- when matching is done on the top level makes the variable bind
- to '$_' in the resulting match_spec, it is to allow a more
- natural access to the whole matched object. The pseudo
- function object() could be used instead, see below.
- The following expressions are translated equally:
+{error,transform_error}
+
All variables are bound in the head of a match specification, so
+ the translator cannot allow multiple bindings. The special case
+ when matching is done on the top-level makes the variable bind
+ to '$_' in the resulting match specification. It is to allow
+ a more natural access to the whole matched object. Pseudo
+ function object() can be used instead, see below.
+
The following expressions are translated equally:
ets:fun2ms(fun({a,_} = A) -> A end).
ets:fun2ms(fun({a,_}) -> object() end).
-
The special match_spec variables '$_' and '$*'
+
The special match specification variables '$_' and '$*'
can be accessed through the pseudo functions object()
(for '$_') and bindings() (for '$*').
- as an example, one could translate the following
- ets:match_object/2 call to a ets:select call:
+ As an example, one can translate the following
+ ets:match_object/2 call to a ets:select/2 call:
ets:match_object(Table, {'$1',test,'$2'}).
-
(This was just an example, in this simple case the former
- expression is probably preferable in terms of readability).
- The ets:select/2 call will conceptually look like this
+
In this simple case, the former
+ expression is probably preferable in terms of readability.
+
The ets:select/2 call conceptually looks like this
in the resulting code:
Matching on the top level of the fun head might feel like a
+
Matching on the top-level of the fun head can be a
more natural way to access '$_', see above.
- Term constructions/literals are translated as much as is
- needed to get them into valid match_specs, so that tuples are
- made into match_spec tuple constructions (a one element tuple
- containing the tuple) and constant expressions are used when
- importing variables from the environment. Records are also
- translated into plain tuple constructions, calls to element
- etc. The guard test is_record/2 is translated into
- match_spec code using the three parameter version that's built
- into match_specs, so that is_record(A,t) is translated
- into {is_record,'$1',t,5} given that the record size of
- record type t is 5.
- Language constructions like case, if,
- catch etc that are not present in match_specs are not
- allowed.
- If the header file ms_transform.hrl is not included,
- the fun won't be translated, which may result in a
- runtime error (depending on if the fun is valid in a
- pure Erlang context). Be absolutely sure that the header is
- included when using ets and dbg:fun2ms/1 in
- compiled code.
- If the pseudo function triggering the translation is
- ets:fun2ms/1, the fun's head must contain a single
- variable or a single tuple. If the pseudo function is
- dbg:fun2ms/1 the fun's head must contain a single
- variable or a single list.
+
+
Term constructions/literals are translated as much as is needed to
+ get them into valid match specification. This way tuples are made
+ into match specification tuple constructions (a one element tuple
+ containing the tuple) and constant expressions are used when
+ importing variables from the environment. Records are also
+ translated into plain tuple constructions, calls to element,
+ and so on. The guard test is_record/2 is translated into
+ match specification code using the three parameter version that is
+ built into match specification, so that is_record(A,t) is
+ translated into {is_record,'$1',t,5} if the record
+ size of record type t is 5.
+
+
+
Language constructions such as case, if, and
+ catch that are not present in match specifications are not
+ allowed.
+
+
+
If header file ms_transform.hrl is not included,
+ the fun is not translated, which can result in a
+ runtime error (depending on whether the fun is
+ valid in a pure Erlang context).
+
Ensure that the header is included when using ets and
+ dbg:fun2ms/1 in compiled code.
+
+
+
If pseudo function triggering the translation is
+ ets:fun2ms/1, the head of the fun must contain a single
+ variable or a single tuple. If the pseudo function is
+ dbg:fun2ms/1, the head of the fun must contain a single
+ variable or a single list.
+
-
The translation from fun's to match_specs is done at compile
+
The translation from funs to match specifications is done at compile
time, so runtime performance is not affected by using these pseudo
- functions. The compile time might be somewhat longer though.
-
For more information about match_specs, please read about them
- in ERTS users guide.
-
+ functions.
+
For more information about match specifications, see the
+ Match specifications in Erlang
+ in ERTS User's Guide.
+
+
-
- Transforms Erlang abstract format containing calls to ets/dbg:fun2ms into literal match specifications.
- Option list, required but not used.
+
+ Error formatting function as required by the parse transformation interface.
-
Implements the actual transformation at compile time. This
- function is called by the compiler to do the source code
- transformation if and when the ms_transform.hrl header
- file is included in your source code. See the ets and
- dbg:fun2ms/1 function manual pages for
- documentation on how to use this parse_transform, see the
- match_spec chapter in ERTS users guide for a
- description of match specifications.
+
Takes an error code returned by one of the other functions
+ in the module and creates a textual description of the
+ error.
+
-
- Used when transforming fun's created in the shell into match_specifications.
- List of variable bindings in the shell environment.
+
+ Transforms Erlang abstract format containing calls to
+ ets/dbg:fun2ms/1 into literal match specifications.
+ Option list, required but not used.
+
-
Implements the actual transformation when the fun2ms
- functions are called from the shell. In this case the abstract
- form is for one single fun (parsed by the Erlang shell), and
- all imported variables should be in the key-value list passed
- as BoundEnvironment. The result is a term, normalized,
- i.e. not in abstract format.
+
Implements the transformation at compile time. This
+ function is called by the compiler to do the source code
+ transformation if and when header file ms_transform.hrl
+ is included in the source code.
+
For information about how to use this parse transformation, see
+ ets and
+
+ dbg:fun2ms/1.
+
For a description of match specifications, see section
+
+ Match Specification in Erlang in ERTS User's Guide.
+
-
- Error formatting function as required by the parse_transform interface.
+
+ Used when transforming funs created in the shell into
+ match_specifications.
+ List of variable bindings in the
+ shell environment.
-
Takes an error code returned by one of the other functions
- in the module and creates a textual description of the
- error. Fairly uninteresting function actually.
+
Implements the transformation when the fun2ms/1
+ functions are called from the shell. In this case, the abstract
+ form is for one single fun (parsed by the Erlang shell).
+ All imported variables are to be in the key-value list passed
+ as BoundEnvironment. The result is a term,
+ normalized, that is, not in abstract format.