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.

Wednesday, August 03, 2011

perlbrew and 32-bit CPAN modules like Mac::Growl


Today I discovered perlbrew, a utility for managing multiple versions of Perl under a non-root account, in the same spirit as rvm or virtualenv. I was forced into discovering perlbrew, because installing XCode 4 onto a Mac breaks the ability to compile many CPAN modules if you stick with the computer's default Perl.

Even with perlbrew, you might still have trouble compiling CPAN modules on a Mac, if those modules need older 32-bit code. This is because perlbrew doesn't build its perls as fat binaries, it builds them as 64-bit only.

I used perlbrew to install Perl 5.14.1, and then I was trying to install Test::Continuous, which has a long chain of dependencies including Mac::Growl, Mac::Growl itself depending on Mac::Carbon. Mac::Carbon is 32-bit. I was able to work around this, but I had to (temporarily) leave the CPAN shell to do it. The steps are:

  1. Install Cocoa::Growl as a 64-bit alternative to Mac::Growl. You can use the CPAN shell for this.
  2. Install Log::Dispatch::MacGrowl. This module will recognize that you
    have Cocoa::Growl installed, but for some reason it still won't install
    via CPAN shell. But it will install if you download the tarball and build manually.
  3. Now via CPAN install Log::Dispatch::DesktopNotification.
  4. Now via CPAN install Test::Continuous.

Friday, June 24, 2011

SEO changes forever (or so I've read)


But you have not, as SEOs, we never really had to think as much or as broadly about, "What is the experience of this website? Is it creating a brand that people are going to love and share and reward and trust?" Now we kind of have to think about that.

How Google's Panda Update Changed SEO Best Practices Forever

This, in a nutshell, is the problem I've always had with SEO. People have seen SEO as a bullet list of things to do, a checklist of fairly mechanical steps that, if you closely follow the steps, your page rank will go higher. I read the above as an admission that the SEO consultants themselves have (until now) viewed SEO the same way. I've had clients ask me if they should spend the money on a dedicated SEO consultant and my answer was always "ehhhhh..." Following the SEO checklist might move your page rank a couple spots, but if you want your site to rank substantially higher, you need to substantially change your site. If Panda transforms "SEO consultants" to become "user experience consultants" that's probably not a bad thing.

Thursday, June 09, 2011

Why Apple is charging you to store non-iTunes music in iCloud


If you own some music that you bought from iTunes and you choose to "upload" it into iCloud, you're not really uploading anything. Apple already has it. You originally bought it from them. They just have to store the fact that you are allowed to access their copy of the song. Six million people can "store" Poker Face in iCloud, Apple has to keep only the one copy. Us nerds call this single-instance storage.

On the other hand, if you ripped some music from a CD that you own, and you want to upload that into iCloud, Apple has to actually accept the song from you and allocate disk space to store it. That costs them money, and everyone knows that Apple doesn't do anything for free, so you can bet they're going to charge that cost back to you.