Erlang Notes

hello world
Login

hello world

Too many 'hello world's

First, at the repl:

1> io:fwrite("Hello, world!~n").
Hello, world!
ok
2> erlang:display('hello world').
'hello world'
true
3> io:fwrite(<<"Hello, ~s!\n">>, [<<"world">>]).
Hello, world!
ok

Second, at the command line:

$ erl -eval 'io:fwrite("Hello, world!~n"), halt()' -noshell
Hello, world!

And then,

  1. a module with a function that does proper I/O
  2. printing a term ... potentially really fast
  3. an escript
  4. a rebar3 escript

a module with a function that does proper I/O

-module(h1).
-export([hello/0, hello/1]).

hello() -> hello("world").
hello(Name) -> io:fwrite("Hello, ~s!~n", [Name]).

This can be used interactively:

1> c(h1).
{ok,h1}
2> h1:hello().
Hello, world!
ok
3> h1:hello("something else").
Hello, something else!
ok

Or by slowly spawning an Erlang node just to call this function:

$ getr 1 erl -noinput -s h1 hello -s init stop
Hello, world!
User time      : 0 s, 287410 us
System time    : 0 s, 89129 us
Time           : 376 ms (376.000 ms/per)
Max RSS        : 47.1 MB
Page reclaims  : 8625
Page faults    : 0
Block inputs   : 0
Block outputs  : 0
vol ctx switches   : 1952
invol ctx switches : 3846

You can shave a bit off the VM off:

$ getr 1 erl +S 1 +SDio 1 +P 1024 +Q 1024 -mode minimal -noinput -s h1 hello -s init stop
Hello, world!
User time      : 0 s, 70231 us
System time    : 0 s, 21882 us
Time           : 92 ms (92.000 ms/per)
Max RSS        : 32.4 MB
Page reclaims  : 5883
Page faults    : 0
Block inputs   : 0
Block outputs  : 0
vol ctx switches   : 538
invol ctx switches : 0

Those flags are explained by erl -man erl:

printing a term ... potentially really fast

-module(h2).
-export([start/0]).

start() ->
    erlang:display('Hello world!').

This can be used just like the last example, but what makes it interesting is that AtomVM can use this but not the last example. This is a tiny Erlang VM, an alternative to the BEAM machine, that targets embedded devices.

$ erlc h2.erl
$ ~/erlang/AtomVM/build/tools/packbeam/PackBEAM h2.avm h2.beam
$ getr 1 ~/erlang/AtomVM/build/src/AtomVM h2.avm
Hello world!
Return value: true
User time      : 0 s, 1199 us
System time    : 0 s, 0 us
Time           : 1 ms (1.000 ms/per)
Max RSS        : 2.9 MB
Page reclaims  : 99
Page faults    : 0
Block inputs   : 0
Block outputs  : 0
vol ctx switches   : 1
invol ctx switches : 0

Hyperfine says that's about 2266.99 +/- 1666.11 times faster than erl -noinput -s h2 start -s init stop.

an escript

#! /usr/bin/env escript
main(_) -> io:fwrite("Hello, world!~n").

As used:

$ chmod +x h3
$ ./h3
Hello, world!

There are no performance benefits to using an escript, but this has all the usual subtle administrative benefits of a script:

  1. it's very easy to invoke: you just run it. There's no separate command to run that starts it.
  2. it's very easy to investigate: you just open it. The source is right there, and possibly even the documentation. You do not have to go hunting for the source code.

a rebar3 escript

$ rebar3 new escript h4
$ cd h4
$ rebar3 escriptize
$ ./_build/default/bin/h4 hello world
Args: ["hello","world"]

The 'h4' file in this case is binary, containing a zip archive of the project's .app and .beam files, but a value of a rebar3 escript is that you can include multiple files into the script. Let's demonstrate that by editing src/h4.erl,

-module(h4).

-export([main/1]).

main(_) ->
    greeter:greet(world),
    erlang:halt(0).

and adding a new src/greeter.erl,

-module(greeter).

-export([greet/1]).

greet(X) -> io:fwrite("Hello, ~p!\n", [X]).

With these changes, the usage is the same:

$ rebar3 escriptize
$ ./_build/default/bin/h4 hello world
Hello, world!

Another value of a rebar3 escript is that it's always compiled, which can enormously improve Erlang performance, but as of Erlang/OTP 27 and #7348 all escripts are compiled by default. Now, rebar3 is only saving you some compile-time.