• Aucun résultat trouvé

creating modules

Dans le document Learn You Some erLang for great good! (Page 58-62)

When writing a module, you can declare two kinds of things: functions and attributes. Attributes are metadata describing the module itself, such as its name, the functions that should be visible to the outside world, the author of the code, and so on. This kind of metadata is useful because it gives hints to the compiler on how it should do its job, and also because it lets people retrieve information from compiled code without needing to consult the source.

A large variety of module attributes is currently used in Erlang code across the world. In fact, you can even declare your own attributes for what-ever you please. Howwhat-ever, some predefined attributes will appear more fre-quently than others in your code.

All module attributes follow the form -Name(Attribute).. Only one of them is necessary for your module to be compilable:

-module(Name).

This is always the first attribute (and statement) of a file, and for good reason: It’s the name of the cur-rent module, where Name is an atom. This is the name you’ll use to call functions from other modules. The calls are made with the form M:F(A), where M is the mod-ule name, F the function, and A the arguments.

Note that the name of the module as defined in the -module attribute and the filename must match.

For example, if the module name is unimaginative_name, then the file should be named unimaginative_name.erl (.erl is the standard Erlang source extension). If the names don’t match, your module won’t compile.

It’s time to code already! Our first module will be very simple and use-less. Open your text editor, type the following line, and then save the file as useless.erl.

-module(useless).

This line of text is actually a valid module. Really! Of course, it’s useless without functions. Let’s first decide which functions will be exported from our useless module. To do this, we will use another attribute:

-export([Function1/Arity, Function2/Arity, ..., FunctionN/Arity]).

This is used to define which functions of a module can be called by the outside world. It takes a list of functions with their respective arity. The arity of a function is an integer representing how many arguments can be passed to the function. This is critical information, because different functions defined within a module can share the same name if, and only if, they have a different arity. The functions add(X,Y) and add(X,Y,Z) would thus be consid-ered different, and written in the form add/2 and add/3, respectively.

n o t e Exported functions represent a module’s interface. It is important to define an inter-face that reveals only the bare minimum of what is necessary to use the module’s func-tions. This lets you fiddle with the internal details of your implementations without breaking code that might depend on your module.

Our useless module will first export a useful function named add, which will take two arguments. Add the following -export attribute after the mod-ule declaration:

-export([add/2]).

BIFs mentioned in Chapter 1, such as hd and tl, actually belong to the erlang

module. All of the arithmetic, logic, and Boolean operators also are in the

erlang module.

BIFs from the erlang module differ from other functions, as they are automatically imported when you use Erlang. Every other function defined in a module needs to be called with the form Module:Function(Arguments), as in this example:

Here, the seq function from the lists module was not automatically imported, while element was. The error “undefined shell command” comes from the shell looking for a shell command like f() and not being able to find it. Some functions from the erlang module are not imported automati-cally, but they are not used very frequently.

Logically, you should put functions that deal with similar things inside a single module. Common operations on lists are kept in the lists module, while functions to do input and output (such as writing to the terminal or in a file) are grouped in the io module or the file module. One of the only modules you will encounter that doesn’t respect that pattern is the erlang

module, which has functions that do math, perform conversions, deal with multiprocessing, fiddle with the VM’s settings, and so on. They have noth-ing in common except benoth-ing BIFs. You should avoid creatnoth-ing modules like

erlang, and instead focus on clean and logical separations.

creating modules

When writing a module, you can declare two kinds of things: functions and attributes. Attributes are metadata describing the module itself, such as its name, the functions that should be visible to the outside world, the author of the code, and so on. This kind of metadata is useful because it gives hints to the compiler on how it should do its job, and also because it lets people retrieve information from compiled code without needing to consult the source.

A large variety of module attributes is currently used in Erlang code across the world. In fact, you can even declare your own attributes for what-ever you please. Howwhat-ever, some predefined attributes will appear more fre-quently than others in your code.

And now we can write the function:

add(A,B) ->

A + B.

The syntax of a function follows the form Name(Args) -> Body., where Name

must be an atom, and Body can be one or more Erlang expressions sepa-rated by commas. The function is ended with a period. Note that Erlang doesn’t use the return keyword as many imperative languages do. A return is useless! Instead, the last logical expression of a function to be executed will have its value returned to the caller automatically, without you needing to mention it.

Next, add the following function to the file. (Yes, every tutorial needs a “Hello, world” example!) Don’t forget to add it to the -export attribute as well (the -export attribute should then look like -export([add/2, hello/0]).).

%% Shows greetings.

%% io:format/1 is the standard function used to output text.

hello() ->

io:format("Hello, world!~n").

The first thing to notice in this listing is the comments. In Erlang, com-ments are single-line only and begin with a % sign. (In this case, we’ve used

%%, but this is purely a question of style.) The hello/0 function also demon-strates how to call functions from foreign modules inside your own module.

In this case, io:format/1 is the standard function to output text, as written in the comments.

n o t e The convention in the Erlang community is to use three percent signs (%%%) for com-ments that are general to a module (what the module is used for, licenses, and so on) and divisions of different sections of a module (public code, private code, helper functions, and so on). Two percent signs (%%) are used for all other comments that are alone on their own line and at the same level of indentation as the surrounding code.

A single % is used for comments at the end of a line where there is code.

Let’s add one last function to the module, using both functions add/2

and hello/0:

greet_and_add_two(X) ->

hello(), add(X,2).

Again, don’t forget to add greet_and_add_two/1 to the exported function list. The calls to hello/0 and add/2 don’t need to have the module name pre-pended to them, because they were declared in the module itself.

MODULE

IMPORTS

If you wanted to be able to call io:format/1 in the same manner as add/2, or any other function defined within the current module, you could have added the following module attribute at the beginning of the file: -import(io, [format/1]).. Then you could have called format("Hello, World!~n").

directly. More generally, the -import attribute fol-lows this recipe:

-import(Module, [Function1/Arity, ..., FunctionN/Arity]).

Importing a function is a handy shortcut, although most program-mers strongly discourage the use of the -import attribute, as it can reduce the readability of code. For example, in the case of io:format/2, there’s another function in a different library with the same name: io_lib:format/2. Determining which one is used requires going to the top of the file to see from which module it was imported, if it was imported in the first place.

Consequently, including the module name is considered good practice and will help the many Erlang users who love to use grep to find their way across projects. Usually, the only functions you’ll see imported come from the lists module; its functions are used with a higher frequency than those from most other modules.

Your useless module should now look like the following:

-module(useless).

-export([add/2, hello/0, greet_and_add_two/1]).

add(A,B) ->

A + B.

%% Shows greetings.

%% io:format/1 is the standard function used to output text.

hello() ->

io:format("Hello, world!~n").

greet_and_add_two(X) ->

hello(), add(X,2).

We are now finished with the useless module. Save your useless.erl file, and then we can try to compile it.

And now we can write the function:

add(A,B) ->

A + B.

The syntax of a function follows the form Name(Args) -> Body., where Name

must be an atom, and Body can be one or more Erlang expressions sepa-rated by commas. The function is ended with a period. Note that Erlang doesn’t use the return keyword as many imperative languages do. A return is useless! Instead, the last logical expression of a function to be executed will have its value returned to the caller automatically, without you needing to mention it.

Next, add the following function to the file. (Yes, every tutorial needs a “Hello, world” example!) Don’t forget to add it to the -export attribute as well (the -export attribute should then look like -export([add/2, hello/0]).).

%% Shows greetings.

%% io:format/1 is the standard function used to output text.

hello() ->

io:format("Hello, world!~n").

The first thing to notice in this listing is the comments. In Erlang, com-ments are single-line only and begin with a % sign. (In this case, we’ve used

%%, but this is purely a question of style.) The hello/0 function also demon-strates how to call functions from foreign modules inside your own module.

In this case, io:format/1 is the standard function to output text, as written in the comments.

n o t e The convention in the Erlang community is to use three percent signs (%%%) for com-ments that are general to a module (what the module is used for, licenses, and so on) and divisions of different sections of a module (public code, private code, helper functions, and so on). Two percent signs (%%) are used for all other comments that are alone on their own line and at the same level of indentation as the surrounding code.

A single % is used for comments at the end of a line where there is code.

Let’s add one last function to the module, using both functions add/2

and hello/0:

greet_and_add_two(X) ->

hello(), add(X,2).

Again, don’t forget to add greet_and_add_two/1 to the exported function list. The calls to hello/0 and add/2 don’t need to have the module name pre-pended to them, because they were declared in the module itself.

MODULE

IMPORTS

Dans le document Learn You Some erLang for great good! (Page 58-62)