Showing posts with label erlang. Show all posts
Showing posts with label erlang. Show all posts

Tuesday, July 23, 2013

Using 3rd-party Erlang modules in Elixir


Calling into other people's Erlang from Elixir is pretty straightforward, but there are a couple things to be aware of. Let's start with some sample Erlang code that uses the epgsql module.


-module(pgdemo).
-compile(export_all).

-define(EPG_PATH, "/Users/alh/src/epgsql/ebin").

main() ->
    setup_paths(),
    {ok, PGConn} = pgsql:connect("localhost", "dba", [{database, "users"}]),
    {ok, Columns, Rows} = pgsql:squery(PGConn, "SELECT * FROM auth_user").

setup_paths() ->
    code:add_patha(?EPG_PATH).
Here's the same code written in Elixir:


defmodule PgDemo do
  @epg_path "/Users/alh/src/epgsql/ebin"

  def main do
    setup_paths
    {:ok, pg_conn} = :pgsql.connect('localhost', 'dba', [{:database, 'users'}])
    {:ok, columns, rows} = :pgsql.squery(pg_conn, 'SELECT * FROM auth_user')
  end

  defp setup_paths do
    Code.append_path(@epg_path)
  end
end
So what's different?
  • Because the module naming conventions are different between Elixir and Erlang, Elixir imports Erlang module names as atoms, e.g. :pgsql
  • Again because of naming conventions, Erlang atoms like database become :database and a local variable like PgConn in the Erlang version becomes pg_conn in Elixir.
  • Most (all?) Erlang functions that take a string as an argument are going to expect that string to be a char list, a list of 8-bit values ... but a typical double-quoted string in Elixir is UTF-8! We need to single-quote string literals when they are arguments to an Erlang function. If you have a UTF-8 string stored in an Elixir variable, you can convert it to a char list with the binary_to_list/1 function. For more about Elixir strings see the Getting Started Guide section 2.3.

Also, there doesn't seem to be an exact equivalent in Elixir to Erlang's -define() for defining a constant. You can use module attributes (Section 3.6) for defining string constants and they will be inlined at compile-time.


Wednesday, January 04, 2012

A Concurrency Programming Kata in Erlang


Write an Erlang program that spawns two processes. Each process should:
  1. Send a unique (pseudo-random) key/value pair to the CouchDB database. Remember the value in-process so it can be confirmed later (see Step 6.) Don't use process dictionaries for this.
  2. Send the Id of the created CouchDB record to the other process.
  3. Listen for Ids being sent to it by the other process.
  4. On receiving an Id, retrieve the Id from CouchDB.
  5. Send the retrieved value back to the other process to confirm the retrieval is correct.
  6. Confirm any values sent to it by the other process. Don't re-fetch the record from CouchDB. Don't use process dictionaries.
  7. Sleep for an interval.
  8. Goto (1).
This kata helps us to explore Erlang's concurrency primitives, which are Erlang's best, most distinctive feature.

If you're using Homebrew on OS X:


~$ brew install erlang
~$ brew install couchdb
~$ couchdb # Will run in the foreground, switch to a new Terminal for the rest
To get started using Erlang to communicate with CouchDB you'll need a couple modules, installed like this:


~$ git clone git://github.com/ngerakines/erlang_couchdb.git ; cd erlang_couchdb ; make
~$ svn checkout http://mochiweb.googlecode.com/svn/trunk/ mochiweb ; cd mochiweb ; make
Here's some sample code to load the module paths, demonstrate the CouchDB API, and verify all of those pieces are working:


-module(kata_couch).
-compile(export_all).

% Path to your erlang_couchdb clone + "/ebin"
-define(ERLANG_COUCHDB_PATH, "/Users/alh/src/erlang_couchdb/ebin").
% Path to your mochiweb checkout + "/ebin"
-define(MOCHIWEB_PATH, "/Users/alh/src/mochiweb/ebin").
-define(DBSERVER, {"localhost", 5984}).

main() ->
    setup_paths(),
    db_demo(),
    init:stop().

db_demo() ->
    erlang_couchdb:create_database(?DBSERVER, "test1"),
    {json, {struct, [{_,_}, {<<"id">>,Cid}, {_,_}]}} =
        erlang_couchdb:create_document(?DBSERVER, "test1", [{<<"keyA">>, <<"valA">>}]),
    Retr1 = erlang_couchdb:retrieve_document(?DBSERVER, "test1", binary_to_list(Cid)),
    {json, {struct, [{_,_}, {_,_}, {K,V}]}} = Retr1,
    io:format("~p : ~p~n", [K, V]).

setup_paths() ->
    code:add_patha(?ERLANG_COUCHDB_PATH),
    code:add_patha(?MOCHIWEB_PATH).
And an idiomatic sleep/1 function, taken from the Armstrong book:


sleep(T) ->
    receive
        after T ->
            true
    end.