“People got OO all wrong, its not about classes or objects. The big idea is messaging” (from Allen Kay)

Just a gentle reminder that I took some pains at the last OOPSLA to try to remind everyone that Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea.

The big idea is “messaging” — that is what the kernal of Smalltalk/Squeak is all about (and it’s something that was never quite completed in our
Xerox PARC phase).

from Kay, Allen. “prototypes vs classes was: Re: Sun’s HotSpot”

Kay is one of the fathers of the idea of object-oriented programming, inventor of Smalltalk.


How to build and package Erlang OTP applications (using rebar)

Rerbar is an Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. Its a self-contained binary.

Using rebar

Either install from distribution repo (if available), use prebuild binary, or compile from the source.

# requirements, see
$ sudo apt-get install erlang

# either from repo (not recomended, too old)
$ sudo apt-get install rebar
# or compile from source
# or pre-build binary (recomended)
$ wget ; chmod +x rebar

from rebar@github

Use a template to create new application that follows OTP Design Principles.

$ mkdir rebar-helloworld ; cd rebar-helloworld
$ ../rebar create-app appid=app1
==> app1 (create-app)
Writing src/ # Application descriptor
Writing src/app1_app.erl # Application callback module
Writing src/app1_sup.erl # Supervisor callback module

Next add a generic server to the application. A gen_server is the server implementation of a client-server. You have to fill in the pre-defined set of function in a callback module.

# either create file
$ cat src/app1_srv.erl
-export([start_link/0, say_hello/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
    {ok, []}.
say_hello() ->
    gen_server:call(?MODULE, hello).
%% callbacks
handle_call(hello, _From, State) ->
    io:format("Hello from server!~n", []),
    {reply, ok, State};
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.
handle_cast(_Msg, State) ->
    {noreply, State}.
handle_info(_Info, State) ->
    {noreply, State}.
terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

# or use template
$ rebar create template=simplesrv srvid=app1_srv
==> app1 (create)
Writing src/app1_srv.erl

# and add say_hello/0 function
-export([start_link/0, say_hello/0, stop/0]).
%% API Function Definitions
say_hello() ->
    gen_server:call(?MODULE, hello).
stop() ->
    gen_server:cast(?MODULE, stop).
%% callbacks (gen_server Function Definitions)
handle_call(hello, _From, State) ->
    io:format("Hello from srv!~n", []),
    {reply, ok, State};
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.
handle_cast(stop, State) ->
    {stop, normal, State};

We could compile now, but lets create another application lib1 and compile both.

# move both apps to '/apps'
$ mkdir -p apps/{app1,lib1}
$ mv src apps/app1/
$ cd apps/lib1
$ rebar create-app appid=lib1
$ cat src/hello.erl
hello() ->
    io:format("Hello for lib!", []).

# compile both
$ cd ../..
$ cat rebar.config
{sub_dirs, ["apps/app1", "apps/lib1"] }.
$ tree
├── apps
│   ├── app1
│   │   └── src
│   │       ├── app1_app.erl
│   │       ├──
│   │       ├── app1_srv.erl
│   │       └── app1_sup.erl
│   └── lib1
│       └── src
│           ├── hello.erl
│           ├── lib1_app.erl
│           ├──
│           └── lib1_sup.erl
└── rebar.config
$ rebar compile
==> app1 (compile)
==> src (compile)
==> lib1 (compile)
Compiled src/hello.erl
==> src (compile)
==> app1 (compile)

# test (in development)
$ erl -pa apps/*/ebin
1> app1_srv:start_link().
2> app1_srv:say_hello().
Hello from server!
3> app1_srv:stop().
4> hello:hello().
Hello from lib!

How can I call a library function from lib1 in a app1 ?

$ cat apps/app1/src/app1_srv.erl
%% callbacks
handle_call(hello, _From, State) ->
    io:format("~nHello from srv!~n", []),
    {reply, ok, State}.
$ cat apps/app1/src/app1_sup.erl
init([]) ->
    {ok, {{one_for_one, 1, 60}, [?CHILD(app1_srv, worker)]}}.

# recompile and test
$ rebar clean compile
$ erl -pa apps/*/ebin
1> app1_sup:start_link().
2> app1_srv:say_hello().
Hello for lib!Hello from server!

To make the application work like a service (start, stop, console, …), create release. Its a complete system consisting of these applications and a subset of the Erlang/OTP applications. Including a way to make application work like a service (start, stop, console, …).

$ mkdir rel; cd rel
$ rebar create-node nodeid=app1
==> rel (create-node)
Writing reltool.config
Writing files/erl
Writing files/nodetool
Writing files/app1
Writing files/sys.config
Writing files/vm.args
Writing files/app1.cmd
Writing files/start_erl.cmd
Writing files/install_upgrade.escript
$ cd -

$ cat rel/reltool.config
{lib_dirs, ["../apps"]},

$ cat rebar.config
{sub_dirs, ["apps/app1", "apps/lib1", "rel"] }.

# compile and generate release
$ rebar clean compile generate
# if "ERROR: Unable to generate spec: read file info /usr/lib/erlang/man/man1/XPTO.gz" failed then "sudo rm /usr/lib/erlang/man/man1/XPTO.gz"
# ignore "WARN:  'generate' command does not apply to directory", see
$ ls rel/app1
bin  erts-6.1  etc  lib  log  releases

# test using console
$ ./rel/app1/bin/app1 console
# if "...'cannot load',elf_format,get_files}}" then add to 'reltool.config'
{app, hipe, [{incl_cond, exclude}]},
mysample@> application:which_applications().
 {sasl,"SASL  CXC 138 11","2.4"},
 {stdlib,"ERTS  CXC 138 10","2.1"},
 {kernel,"ERTS  CXC 138 10","3.0.1"}]
(mysample@> app1_srv:say_hello().
Hello for lib!Hello from server!

# start and attach to get console
$ ./rel/app1/bin/app1 start ; ./rel/app1/bin/app1 attach

# deploy/export
$ tar -C rel -czvf app1.tar.gz app1

from release-handling@github

Rebar makes building Erlang releases easy. One of the advantages of using OTP releases is the ability to perform hot-code upgrades. To do this you need to build a upgrade package that contains the built modules and instructions telling OTP how to upgrade your application.

# generate first release
$ rebar clean compile generate
$ mv rel/app1 rel/app1_1.0

# change 'hello' function
$ cat apps/app1/src/app1_srv.erl
handle_call(hello, _From, State) ->
    {_,{Hour,Min,Sec}} = erlang:localtime(),
    io:format("Hello from server at ~2w:~2..0w:~2..0w!~n", [Hour,Min,Sec]),
    {reply, ok, State};

# bump version and generate new release
$ cat rel/reltool.config
       {rel, "app1", "2",
$ cat ../apps/app1/src/
  {vsn, "2"},
$ rebar clean compile generate
$ tree rel -d -L 2
├── app1
│   ├── bin
│   ├── erts-6.1
│   ├── lib
│   ├── log
│   └── releases
│       └── 1
├── app1_1.0
│   ├── bin
│   ├── erts-6.1
│   ├── lib
│   ├── log
│   └── releases
│       └── 2
└── files

In order to make an upgrade, you must have a valid .appup file. This tells the erlang release_handler how to upgrade and downgrade between specific versions of your application.

# generate '.appup' upgrade instructions
$ cd rel ; rebar generate-appups previous_release=app1_1.0
==> rel (generate-appups)
Generated appup for app1
Appup generation complete
# see './app1/lib/app1-2/ebin/app1.appup'
% appup generated for app1 by rebar ("2015/01/23 16:03:24")
{"2", [{"1", [{update,app1_srv,{advanced,[]},[]}]}], [{"1", []}]}.

# now create the upgrade package
$ cd rel ; rebar generate-upgrade previous_release=app1_1.0
==> rel (generate-upgrade)
app1_2 upgrade package created
$ ls rel
app1  app1_1.0  app1_2.tar.gz  files  reltool.config

# install upgrade using 'release_handler'
$ mv rel/app1_2.tar.gz rel/app1_1.0/releases
$ ./rel/app1_1.0/bin/app1 console
1> release_handler:which_releases().
2> release_handler:unpack_release("app1_2").
3> release_handler:install_release("2").
4> release_handler:make_permanent("2").
5> app1_srv:say_hello().
Hello for lib!Hello from server at 16:15:24!
6> release_handler:which_releases().

# generating a v3
$ mv rel/app1 rel/app1_2.0
# make code change ... and compile/generate upgrade package
$ rebar clean compile generate
$ cd rel ; generate-appups previous_release=app1_2.0
$ rebar generate-upgrade previous_release=app1_2.0
$ ls
app1  app1_1.0  app1_2.0  app1_3.tar.gz  files  reltool.config

from upgrades@github and rebar tutorial.

Rebar can fetch and build projects including source code from external sources (git, hg, etc.). See erlang-libs.

$ cat rebar.config
deps, [
    {'erlcloud', ".*", { git, ""}},
    {'lager', ".*", { git, "git://"} }
$ rebar update-deps
$ cat src/
    {applications, [
        ..., erlcloud, lager

from [](dependency management)

All code is available in erlang-otp-helloworld@github.

Using rebar3

Rebar3 is an experimental branch that tries to solve some issues, see annoucement.

$ wget ; chmod +x rebar3

It comes with templates for creating applications, library applications (with no start/2), releases and plugins. Use the new command to create a project with from a template. It accepts lib, app, release and plugin as the first argument and the name for each as the second argument.

# create new application and release
$ rebar3 new release app1
===> Writing app1/apps/app1/src/app1_app.erl
===> Writing app1/apps/app1/src/app1_sup.erl
===> Writing app1/apps/app1/src/
===> Writing app1/rebar.config
===> Writing app1/config/sys.config
===> Writing app1/config/vm.args
===> Writing app1/.gitignore
===> Writing app1/LICENSE
===> Writing app1/

# optionally add dependencies
$ cat rebar.config
{deps, [{cowboy, {git, "git://", {tag, "1.0.1"}}}]}.

# add host to nodename otherwise you get "Can't set long node name" when starting console
$ cat config/vm.args
-name app1@

# and release (uses relx instead of reltool)
$ rebar3 release
===> Resolved app1-0.1.0
===> Dev mode enabled, release will be symlinked
===> release successfully created!
# if "Missing beam file elf_format ... elf_format.beam" then 'sudo apt-get install erlang-base-hipe'

# test using console
$ ./_build/rel/app1/bin/app1-0.1.0 console
1> app1_srv:say_hello().
Hello from server!

# deploy/export
$ REBAR_PROFILE=prod rebar3 tar
===> tarball .../_build/rel/app1/app1-0.1.0.tar.gz successfully created!

# upgrading
$ cat apps/app1/src/
,{vsn, "0.2.0"}
$ cat rebar.config
{relx, [{release, {'app1', "0.2.0"},
$ cat apps/app1/src/app1_srv.erl
    io:format("Hello from server v2!~n"),
$ mv _build/rel _build/rel_0.1.0
$ REBAR_PROFILE=prod ../rebar3 tar
===> tarball .../_build/rel/app1/app1-0.2.0.tar.gz successfully created!
$ cp _build/rel/app1/app1-0.2.0.tar.gz _build/rel_0.1.0/app1/releases/app1_0.2.0.tar.gz
$ _build/rel_0.1.0/app1/bin/app1 start
$ _build/rel_0.1.0/app1/bin/app1 upgrade 0.2.0
# you will get "noent ... reup" because '.appup' is missing, see

from basic usage