A morning with elixir
Saturday, 1st June, 2013
After reading Joe Armstrong’s recent blog post on elixir, and the ensuing discussion there and on twitter, I’ve thought a bit about why I don’t like the language. I can’t spend a week with elixir, so the three observations below are after a morning’s reading and watching.
My overall impression is that elixir is a language that makes it easy for people with a ruby background to dabble with erlang. However, after a morning I’ve found at least three things about elixir that would make my own programming life less pleasant (see below). Elixir contains apparently powerful new features (e.g., macros and protocols), but the examples I’ve seen (e.g. in José Valim’s Erlang Factory talk) are not very exciting.
word-like forms as delimiters
# elixir [1] def name ( arglist ) do code end % erlang [2] name ( arglist ) -> code .
I fail to see how [1] is an improvement on [2]. [2] is shorter by a handful of characters but, mainly, [1] uses word-like forms as delimiters, which I think is a very bad idea.
A human reader will read those word-like forms as words (e.g., the English words “do” and “end”), which they’re not. The delimiters “def”, “do”, and “end” delimit the function definition in the same way that “(” and “)” delimit the argument list.
Using word-like forms as delimiters will either/both (a) slow down the human reader as they read these forms as words, or/and (b) make the code harder to read, as the human reader must explicitly remember not to interpret certain word-like forms as words.
cf also lc and inlist or inbits used to delimit comprehensions.
n.b.: the same arguments apply to erlang’s use of “end” as a delimiter for fun and case blocks. Presumably erlang’s excuse was that they ran out of delimiters borrowed from English punctuation, and they didn’t want to overload “.”. I wonder whether some kind of list delimiter might be appropriate (for case at least), e.g.:
R = case f() of
[this -> 1;
that -> 2],
g(R).
The pipeline operator |>
The pipeline operator strikes me as being halfway between useful and troublesome. It would probably be very useful in cases similar to the example Joe gives (repeated below for convenience) — where a series of functions each take and produce a single item of data.
capitalize_atom(X) ->
V1 = atom_to_list(X),
V2 = list_to_binary(V1),
V3 = capitalize_binary(V2),
V4 = binary_to_list(V3),
binary_to_atom(V4).
def capitalize_atom(X) do
X |> atom_to_list
|> list_to_binary
|> capitalize_binary
|> binary_to_list
|> binary_to_atom
end
However, I think if any of the functions in the series take more than one argument, things could quickly get cumbersome. Witness the discussion on Joe’s blog, Joe’s recent tweets suggesting improvements, and the caveat in the elixir documentation.
The simple case above could be done in erlang with a fold:
capitalize_atom(X) ->
lists:foldl(fun(F, Acc) -> F(Acc) end, X,
[fun atom_to_list/1,
fun list_to_binary/1,
fun capitalize_binary/1,
fun binary_to_list/1,
fun binary_to_atom/1]
).
Granted, this is possibly even yuckier than Joe’s version, but using a fold or, more generally, writing a function that walks through a list of funs, gives the possibility of handling errors, using some kind of context dictionary as the passed argument, etc.
I think elixir’s “|>” looks more general than it usefully is.
atoms
In erlang, variables must begin with a capital letter; atoms need special marking only if they start with a capital letter, or contain certain characters, in which case the atom is enclosed in single quotes. In erlang, module names and function names are atoms.
In elixir, variables don’t seem to need any special marking. Atoms /sometimes/ need to be marked with an initial colon. Unless the atom is a function or module name. Unless the module/function is from the erlang standard library. I might have that wrong.
Ord and Enum type classes: what’s the difference?
Wednesday, 15th May, 2013
Learn you a Haskell describes these two type classes like this:
Ord is for types that have an ordering.
…
Enum members are sequentially ordered types.
I didn’t find this especially clear.
Real World Haskell failed (yet again). It [the printed book] gives no definition of Enum, although it seems to think it does (p. 472).
Mostly for my own benefit, this is what I’ve found:
The GHC documentation describes the two type classes like this (emphasis added):
The Ord class is used for totally ordered datatypes.
…
Class Enum defines operations on sequentially ordered types.
So both classes represent ordered types (both are instances of the Ordering data type). The difference is in the kind of ordering.
A clue is in the methods provided: Ord provides >, <, max and min; Enum provides succ and pred (and, interestingly, nothing similar to max and min).
Finally, the best explanation I found was in Chapter 8: Standard Haskell Classes of A Gentle Introduction to Haskell:
8.2 The Enumeration Class
Class Enum has a set of operations that underlie the syntactic sugar of arithmetic sequences; for example, the arithmetic sequence expression [1,3..] stands for enumFromThen 1 3. We can now see that arithmetic sequence expressions can be used to generate lists of any type that is an instance of Enum. This includes not only most numeric types, but also Char, so that, for instance, [‘a’..’z’] denotes the list of lower-case letters in alphabetical order. Furthermore, user-defined enumerated types like Color can easily be given Enum instance declarations. If so:
[Red..Violet] => [Red, Green, Blue, Indigo, Violet]
Note that such a sequence is arithmetic in the sense that the increment between values is constant, even though the values are not numbers. Most types in Enum can be mapped onto integers; for these, the fromEnum and toEnum convert between Int and a type in Enum.
Note however, that for some reason the Ord type class includes “All Prelude types except IO, (->), and IOError”, so a simple mathematical interpretation won’t do.
Conclusion
So! Actually I’m going to ignore that last caveat.
I think the comfiest way for me to understand these type classes is using the available methods: Ord types are those for which it makes sense to talk about relationships like “greater than” and “less than”; Enum types are those for which it makes sense to talk about relationships like “next” and “previous”. Days of the week would be Enum; Dates would be Ord.
queue:split/2 unsafe!? => queue_split_at_most/2
Tuesday, 9th April, 2013
[updated after discussion on erlang-questions, starting here]
I’ve just discovered that queue:split(N, Queue) causes a crash if N is larger than Queue has items:
1> self().
<0.37.0>
2> Q1 = queue:new().
{[],[]}
3> Q2 = queue:in(a, Q1).
{[a],[]}
4> Q3 = queue:in(b, Q2).
{[b],[a]}
5> Q4 = queue:in(c, Q3).
{[c,b],[a]}
6> queue:split(4, Q4).
** exception error: bad argument
in function queue:split/2
called as queue:split(4,{[c,b],[a]})
7> self().
<0.45.0>
Here’s a safe split:
queue_split_at_most(N, Q) ->
case queue:len(Q) >= N of
true ->
queue:split(N,Q);
false ->
{Q, queue:new()}
end.
A Content-less PUT that returns 201 or 409
Thursday, 14th March, 2013
Thanks to people on the webmachine mailing-list, wmtrace, and the webmachine source (it really does implement the diagram!).
This webmachine resource accepts a PUT request to create a new resource. No content and no content headers are required in the request. A successful request returns 201, and the new resource is accessible at the same url as the PUT. If the resource already exists a 409 is returned.
-module(dragon_resource).
-export([init/1,
allowed_methods/2,
content_types_accepted/2,
accept_content/2,
resource_exists/2
]).
-include_lib("webmachine/include/webmachine.hrl").
init([]) ->
{ok, undefined}.
allowed_methods(ReqData, Context) ->
{['PUT'], ReqData, Context}.
content_types_accepted(ReqData, Context) ->
{[{"application/octet-stream", accept_content}], ReqData, Context}.
accept_content(ReqData, Context) ->
{false, ReqData, Context}.
resource_exists(ReqData, Context) ->
Name = wrq:path_info(name, ReqData),
case dragon:create(Name) of
ok ->
NewReqData = wrq:set_resp_header("Location",
wrq:path(ReqData),
ReqData),
{false, NewReqData, Context};
error ->
{{halt, 409}, ReqData, Context}
end.
The relevant dispatch.conf line is:
{["here", "be", "dragons", name], dragon_resource, []}.
Building Web Applications with Erlang
Monday, 20th August, 2012
Building Web Applications with Erlang: Working with REST and Web Sockets on Yaws
By Zachary Kessin
This is a lovely little book. 133 pages long, it’s slim, readable, modest, concrete and to the point. It doesn’t insist on being comprehensive for the sake of filling shelf inches. The author has a simple story to tell, and he tells it simply.
The book introduces the erlang web server Yaws, and covers the Yaws approach to serving dynamic content, templating (with ErlyDTL), streaming, ReST, WebSockets, and so on.
The book is light enough to be worth reading if you’re mildly interested in Yaws, or in erlang for web development, and it’s concrete enough to have one or two exciting new ideas (at least it did for me).
It’s also just a nice read. I’d like to see a lot more computer books like this one.
Unfortunately, the text is marred by O’Reilly’s usual incompetent or negligent editing, littered with typos, language errors and code inconsistencies.
Putting that aside, especially nice for me were the chapter on file upload, showing how the web application can start processing a file even before the file has been fully uploaded, and the appendix on emacs, with its brief introduction to Distel.
Baby steps with a nif
Sunday, 14th August, 2011
simple_nif is an erlang NIF which takes a list of integers and returns a record, called params, containing the sum, the mean, and the quartiles of the input list:
1> simple:get_params([1,2,3,4,5,6,7]).
{params,28,4.0,{2.0,4.0,6.0}}
The main point of the exercise was the C interface between erlang and the C functions. The file simple_nif.c shows how to parse the input list from erlang into a C array, and how to assemble the results into an erlang tuple to return.
More details in the README.
I am releasing the code under the ISC license.
References
- Erlang NIF documentation
- Erlang NIF tutorial
- pytherl_utils.c: usage of enif_get_list_cell
- Erlang and OTP in Action: Chapter 12 has a section on NIFs
Open an Eclipse project in Eclipse
Wednesday, 6th July, 2011
What could be simpler? Not.
I am developing an Android project using Eclipse. I’m working on several machines, with the project source kept in version control. Eclipse seems to generate a ton of metadata files. So far I haven’t been keeping these under version control, but it looks like I might have to.
Often when I launch Eclipse it doesn’t find the project. To gently remind Eclipse where your project is:
- Choose File | Import
- Select General | Existing Projects into Workspace
- Click next and then browse to the directory contain the project directory.
(source)
Eclipse mitigates the pain of having to write Java, but Eclipse brings pains of its own. Today I’m looking into developing for Android using my usual IDE, emacs.
tsung, django, and cross-site request forgery protection
Wednesday, 22nd June, 2011
Tsung is an excellent tool for stress-testing websites. With tsung-recorder you can record different visits (called sessions) to the target website, and later run many randomised versions of the visits.
One complication with testing a Django website, is that forms are generally protected against cross-site request forgery attacks by a hidden field in the form (see Cross Site Request Forgery protection).
Thanks to help from a respondent on django-users, we can overcome this complication: using dyn_variable, tsung can find values in a requested webpage and store them for use in later requests. The simplified session config below shows this in action.
<session name='login_with_csrf' probability='100' type='ts_http'> <request> <dyn_variable name="csrfmiddlewaretoken" ></dyn_variable> <http url='http://mysite.com/' method='GET'></http> </request> <request subst="true"> <http url='/home/' contents='csrfmiddlewaretoken=%%_csrfmiddlewaretoken%%&csrfmiddlewaretoken=%%_csrfmiddlewaretoken%%&username=xxxxxx&password=xxxxxx&next=%2F' content_type='application/x-www-form-urlencoded' method='POST'></http> </request> </session>
BeatBullying’s campaign The Big March collects awards
Friday, 17th June, 2011
[updated 061111: added another award]
[updated 290911: added another award]
Congratulations to BeatBullying! Six awards — so far.
MAAW Globe Awards
MAAW = Marketing Agencies Association Worldwide
Third Sector Excellence Awards
Institute of Promotional Marketing
- Digital Promotions (Gold)
- Not for Profit (Silver)
UTalk Marketing
For more on the Big March:
- The Big March itself
- BeatBullying’s page about the campaign
I was the main server-side developer for the campaign, weaving together technologies including Google’s App Engine, Django (non-rel), gaem, nginx, and Crisp‘s community management platform.
iScheme, with little iPhone, something beginning with (
Friday, 27th May, 2011
I bought iScheme a while ago, purely for the novelty value, and thought little more of it. The other day I was browsing through The Little Schemer with my son, and we came across an exercise to write a function that adds two numbers, using only operations for add 1, subtract 1, and a test for zero (p. 60).
After taking some time to express our mind-bogglement, we decided that the problem would become more accessible if we thought of the two numbers to be added as two piles of coins, and the operations as “take a coin”, “put a coin”, and “is this pile empty?”
Later that night I couldn’t resist trying it out on my phone:
iScheme: this little schemer is a perfect companion to The Little Schemer!
I scheme, you scheme, we all scheme on iScheme!
etc.
Immodest as it sounds, I have to say I prefer my implementation to the one in the book (reformatted for exposition):
; my version ; (define pls (lambda (x y) ; (cond ((z0 x) y) ; (else (pls (s1 x)(a1 y)) ; )))) ; book version (define pls (lamdba (x y) (cond ((z0 y) x) (else (a1 (pls x (s1 y))) ))))
Why is the book’s version better?
