Erlang for C, C++, and Java Programmers - tamale.

net

http://tamale.net/erlang/tutorial.shtml

This tutorial was written by Sean Hinde (a.k.a. Earlyriser) and originally appeared at http://www.earlyriser.org /Erlang_tutorial.html. I retrieved it from The Internet Archive on 2005-12-21 and updated it. Thanks to Anthony D'Agostino for giving me the author's information. Thanks to Shannon -jj Behrens for pointing out a typo.

Erlang for C, C++ and Java Programmers
This brief tutorial aims to cover the main concepts and syntax of Erlang in a way which programmers of C type languages can relate to. It is not a complete description of the language by any means but it does try to give a feel for the main conceptual differences in Erlang. All comments are welcome – with feedback from readers this might even end up being useful!

1. Erlang is a small and easy to learn language
Erlang was designed from the beginning to be small and easy to learn – Ericsson had to train many C/C++ programmers in Erlang so it was part of the core brief to make it as easy as possible. There are only a small number of concepts to master and most will already be familiar to C programmers.

2. Fundamental differences in approach
The biggest difference between programming in C and Erlang is in how programs are structured and in the fact that data is immutable – that is once created, you can't change it. You can only copy it and make required changes as you copy. (If you don't need the original any more, it is up to the garbage collector to discover this and reclaim memory.) This makes the typical way of programming in C — using arrays, whose entries you keep changing, or records, with pointers to things that you keep changing — either wrong or potentially very inefficient. So what does a program like Wings3D do, for structures (such as the winged-edge data structure) that have constantly changing subpieces? It would be too slow to copy the entire structure every time, say, you moved a vertex. The answer: extensive use of gb_trees and gb_sets. These are binary trees for holding dictionaries and sets, with the very useful property that when you copy them (in order to modify, add, or delete entries), you only change about log(number of elements) pieces of data; the rest of the trees are unchanged and can share the old data without copying. So, for instance, where a C programmer might have a pointer to an edge struct inside a face struct, wings puts an integer index for the edge there, and has a separate gb_trees dictionary to map edge# -> edge record. While this is no doubt still slower than the equivalent functionality in C or C++, there are benefits, the main ones being that you avoid a whole class of bugs, and that "Undo" becomes very easy to implement.

3. Data Types
Erlang has obvious basic data types such as floats, integers etc. There is no need to explicitly type data as Erlang variables carry the type of data round with them.

4. Compound data types
Erlang has a small selection of compound data types some of which will be familiar and some not. Mostly where a C program would use a large or variable sized array (or a linked list), an Erlang program uses a linked list. Many (most?) Erlang functions and programs simply iterate over data held in linked lists (or other more complex data structures like gb_trees). Fortunately Erlang has special syntax for lists and provides nice ways to move around them. A linked list might be:
[1, 1.5, "Wings3D"]

1 de 7

11/05/2011 11:53

z = 1. Variables and Matching. it means "match with".5} 5. This idea of "matching" is one of the very few important new concepts to get the hang of as it crops up everywhere and gives Erlang much of its elegance. 2 de 7 11/05/2011 11:53 . This is a fixed size compound data type typically used to group small amounts of data together. case ERROR: var = 0. They are used in places where in C one might define a constant: #define OK 1 #define ERROR 2 switch result { case OK: var = 1.net http://tamale. {x . After that attempts to change it will result in a runtime exception (useful for asserts amongst other things). A=1. and the = operator doesn't in fact mean assign. and Java Programmers . This is similar to a struct in C. Atoms. Variable assignment looks pretty much the same as in other languages but there is one very useful conceptual difference.C) The useful difference is that variables are only assigned to once within any function. io:format("~p". They normally start with a lower case letter so: ok error vec are all atoms.shtml An empty list looks like: [] There is another basic way to group data together and that is the tuple. B=2.net/erlang/tutorial.0 .. %The equivalent of printf("%d". 2. They must be declared before use in a compiler directive (starts with .): -record(vec.y .y = 2. C++. Variable names must start with a capital letter (this is not it – patience!) so the following snippet works fine: . If a variable is fresh (or unbound) then matching it with some data has the effect of irreversably binding the variable to that value.0 .Erlang for C. Creating a record at runtime is done like: #vec{x = 1. Atoms are a feature not found in many languages but they are very useful in Erlang. } 6.. C=A + B.0.0. For example the obvious representation of a 3D vector in Erlang is: {1. break.tamale. An atom may be though of as a fixed label. 1.[C]).5} The final way of grouping data together is the record.0.z}).0.

A}.5}. 1. B) -> 2.0.0. Case stements are similar in form to C switch statements but are much more generic..0. Z1 +1} end The case statement tries to match {X. The first one which matches both form and content is selected. XXXXX 8. and 1.Z} against our vector. If statements work very much the same but they are more limited.0. 3.net/erlang/tutorial. the -> construct should be read as "evaluates to".5} 7.Erlang for C. For example study the following code snippet: . z=Z} = #vec{x=1. An equivalent example with records would be #vec{x=X. and assuming X.5} as all the values are bound) against each case clause in turn. and Java Programmers .0.A. Then it tries to match it against {A. C++.0. first of all it tries to match {1. % so is all_the_same {X1. 2.0.0. Here we also see another radical departure from C like langauges: a function in Erlang may have multiple definitions. Case and If Now we have grasped the concept of matching we can see how exactly the same rules apply in two further Erlang constructs. 2. The final value in the function is the equivalent of the return value in C so the first one might look like: test(int a) { return 1 }.0.. 2. Z1} -> {X1 + 1.shtml Matching is very powerful and also covers compound data types. So.0.0. X=1.Y. This one looks a little odd – A is not yet bound so we might expect that A will match each of the values 1.net http://tamale. test(A.5} against the zero vector and fails. But this would break the rule that a variable can only hold one value. Y. Y=2. What happens is the variables are matched left to right – The first A is matched with 1.1. Finally we try to match against the fresh variables X1.2. 0} -> empty_vector. Y1 + 1. so you can do: {X. Functions You might think it odd to leave functions until now but they take advantage of the matching concept in a very powerful way. In other words we have extracted the 3 values from our Vector. y=Y.0) is matched against 2. so the following are two different Erlang functions with the same name. test(A) -> 1. Y. 2. z=1. y=2. Z=1.. then the second A (now bound to 1. 0.0.0. and Z1 – this succeeds and the result of the case is a new vector {2. after this statement they will each be bound to the value in the matching position. Z} = {1.5.and Z were fresh variables beforehand.5}. The first level of matching is based on the number of parameters. % empty_vector is an atom {A. .5.Y. A} -> all_the_same. A. case {X.Z} (which in this case is the same as saying {1.0 and thus bound to this value.0. and the one to be executed is selected by exactly the same matching rules as we saw in the case statement. 3 de 7 11/05/2011 11:53 . which fails and therefore this whole case clause fails. Here we match the tuple {X. and the whole case statement evaluates to what comes after the -> (We'll do a bit more on this later).Y.. Z} of {0. Y1. Y1.tamale. 1.0.

2. This is the last complicated thing we really need to understand to write complex Erlang expressions.3]. otherwise it means "insert item at start of list". Y1 + 1. add([{X. Our result is 4 de 7 11/05/2011 11:53 . {10. So when we call add([]) the first defintiion is evaluated which results in [] and breaks the recursion. {20. There is no need to pass in pointers to a set of output variables to an Erlang function if you want to return multiple values – you just return a tuple. This matches and as we enter the function X is 1. Z+1}|add(T)]. There is one new feature of lists we need to understand first though. test({X1.Erlang for C. and T is the list [{10.12}. {20.3}. and the rest of the list". In a matching context this means "split a list up into two parts: the first element. Y.23} followed by add([]).21. In this type of function all the definitions must appear straight after one another in the source code file and be separated by semicolons. C++. This would be the idiomatic way to write this in Erlang.22. {20.shtml The second level of matching is between multiple function definitions with the same number of parameters. We can re-write an exact equivalent of our case statement using a single function with multiple definitions: test({0.3] Ok.3] Then if we did: L = [Head|Tail]. Z1 +1}. Y is 2. so lets look in detail at our add function by working through an example. Iteration and Recursion Now we get to the meat and gravy (or dhal and rice) of the Erlang programming model.net/erlang/tutorial. Head would be 1 and Tail would be [2. A}) -> all_the_same. This is classic recursion – next time though we get {11.21. A.3. L would be [1. 0}) -> empty_vector. Z1}) -> {X1 + 1. Z}|T]) -> [{X+1.11.12. That is the | operator.22}]).22}] This evaluates to the construction of a list with {2.2.4}.11. We also see here how to return multiple values from a function. (In fact you can't affect the value of any variable passed into the function – Erlang functions are "side effect free" apart from one case we will touch on briefly when we talk about threads and message passing). The final one is terminated by a full stop. Y+1.12}.12}. similarly if you make a list by appending the empty list to a list you just get the list. We will call our function with: add([{1.21. % empty_vector is an atom test({A. 0. It is this which allows us to extract values from lists and make new lists.4} at the head and the result of add(T) appended afterwards – it is starting to look like the result we want – a list starting with {2.21.3. Let us say now that we have a list of vectors and we wish to add 1 to all the values.2. 9. so much for that diversion. Y1.11. So for example after a match: [Head|Tail] = [1.22}] .tamale. and Java Programmers . Z is 3.13} followed by the result of add([{20. next time {21. Short aside: if you take all the entries out of a list you get left with the empty list. and in fact (in R8B) is evaluated more quickly than the case statement. followed by the result of add([{10.22}]) The first time through add([]) doesn't match so it uses the second definition. In Erlang we could use a recursive function like the following: add([]) -> [].net http://tamale.

3. Y. Odds and Sods It is possible to augment matching with guards. thread(New_state).12.shtml [{2. quit -> quitted end.13}. wait for it.. All threads have a Process ID or they can be registered with a name (which must be an atom). 10. Z+1} | Acc]). {11. type(A) when it_tuple(A) -> its_a_tuple. Guard expressions must return either the atom true or false and must not have side effects. Key} -> New_state = handle_keypress(Key. This pattern creates the list backwards so at the end we need to reverse the list.21.12.. add([{X. Global Data. Acc) -> add(T. {20. C++..tamale. There is a full list of valid guard expressions in the Erlang documentation There is also a set of comparison operators including == which also return the one of the atoms true or false. type(A) when is_float(A) -> its_a_float. State).22} | [] ] which by the above rules is simply [{2.. The state is held as the parameter(s) of the function. .3. In this way the state of an erlang system is distributed around all the threads which make up the system. The message sending statement looks like: 5 de 7 11/05/2011 11:53 . [{X+1. add([].Erlang for C. These may be used in function headers. The clever part is that it can be made event driven so it does not use CPU capacity while it is waiting. Z} | T].4}.13} | {20. case and if statements and are placed before the ->. You may have been wondering how a program maintains state and how it is possible to have global data in an Erlang program when Erlang functions cannot change any data outside their own execution context. The short answer is that Erlang programs cannot have global variables in the same way a C program can. Threads communicate by sending messages which will be matched by the receive statement of the receiving thread. 11. They can however maintain state. for example type(A) when is_integer(A) -> its_an_int. There are a number of other iteration patterns or ways to write the same function.net/erlang/tutorial. Acc) -> lists:reverse(Acc).21. A thread might look like: thread(State) -> receive {keypress. Y+1. and the structure in which state is maintained is.net http://tamale.22}] It is worth experimenting with the | operator at the Erlang shell to get a handle on what it does. and Java Programmers . One very common version of this (which has the advantage that it executes in constant memory space) uses an accumulator parameter to build the result: add(A) -> add(A. a thread! An Erlang thread is modelled as a recursive function which just keeps on recursing.4} | {11. []). While keypresses are being received by the thread it carries on handling the keypresses and going back to wait at the receive statement for the next event.

Funs are also useful in iterating over lists and other data types. There are a huge range of modules which come with the Erlang system but one is special.tamale. lists:map(Add. Z}) -> {X+1. Y. and Java Programmers . Module names have the same syntax as atoms. Y+1. %The value of N from outside the fun is captured by the fun.g make_add_fun(N) -> fun(Num) -> Num + N end. This is tricky stuff. List_of_vectors). This process would decode the raw data and send the application thread the nice message {keypress. enter} So for example the Erlang system might have some process receiving raw binary data from the operating system upon each keypress. The module erlang has a bunch of functions which are globally scoped and may be called from any module using the local form. So: add(List_of_vectors) -> Add = fun({X. Z+1} end. We can re-write our vector adding function using a standard function from the lists module which does the iteration for us. Summary 6 de 7 11/05/2011 11:53 . Funs Erlang has a feature where a generic function can be defined and assigned to a variable. C++. 12.net http://tamale. definition in the file.erl and have a -module(module_name). It may be called any time later and when it is it 'remembers' the state of the variables at the time it was defined. An example of where we could see that a fun remembers variables would be this function which makes a fun to add any number to the parameter.shtml Pid ! {keypress.Erlang for C. This is exactly the sort of thing the esdl application does for Wings3D. e. The description in the Erlang docs is pretty good: Erlang/OTP Documentation (click on Erlang Reference Manual. To call a function in another module the format is: module_name:function(Par1. and is used in Wings3D in a quite advanced way to keep track of which mode the gui is in. Modules Each Source code file makes up one module. For example to define a function to add 1 to a number we could do: Add = fun(Num) -> Num + 1 end.. It must be named module_name. This is another way to maintain state. List Comprehensions List comprehensions are perhaps one of the most incomprehensible newer features of Erlang! I never use them but it is important to have a basic understanding to read other peoples code. enter}. Wings3D hold a list of funs which it uses as a stack. These include the guard expressions so is_integer/1 is the same as erlang:is_integer/1 Some useful modules are maths and gb_trees.net/erlang/tutorial. 14. When you right click on a menu the menu fun is added to the head of the list which is called to do it's stuff and afterwards removed from the top of the list revealing the previous state. find List Comprehensions in Section 6. 13.22) 15. % Why not try it in the erlang shell Then to use the function it is just: Add(10). Par2).

Copyright © 1999-2007 Michael Leonhard 7 de 7 11/05/2011 11:53 . and Java Programmers . Earlyriser) and originally appeared at http://www.shtml There are a small number of powerful concepts which once understood run all through Erlang programming.tamale.org /Erlang_tutorial. This tutorial was written by Sean Hinde (a.k.net/erlang/tutorial.Erlang for C. C++.a.net http://tamale. Pattern Matching Function Recursion Multiple return values Threads to hold state and receive events (messages) Funs Immutable data (single assignment variables) Programs such as Wings3d use these concepts in some very advanced ways but even so they are still just these few concepts.html.earlyriser.

Sign up to vote on this title
UsefulNot useful