Tuesday, June 23, 2009

Erlang for Java programmer - Design patterns, p.1

The Gamma et al. "Design patterns" book formulates common desing patterns that could be applied to any object-oriented language. When we move to functional language domain though, many OO design patterns simply don't apply. This is hardly surprising, because functional programmers by definition don't do OO design. Some of the problems that OO design patterns are supposed to solve still have their counterparts in functional programming.

We are going to walk through the book's pattern catalog and try to show a matching Erlang approach for the OO patterns, where possible.

Going forward, I will be referring to "Design patterns" book as DP. In (unlikely) case you'll want to follow, it'll be helpful to have this book handy.




Adapter (Wrapper)



Intention(DP): Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.



Let's just substitute "class" to "function", and we'll have it for Erlang:



Convert the interface of a function into another interface clients expect. Adapter lets functions work together that couldn't otherwise because of incompatible interfaces.



Now, function's interface obviously being its arguments, in most cases we can easily create adapter for that function, which is another function having desired set of arguments.



Example:



Trying to stick closely to DP example, let's assume that we are working on drawing editor and want to implement text drawing capabilities in module textshape. The behavior that we have decided to use for all shape kinds contains bounding_box/1 function that returns bottom left and top right coordinates for any shape. So we are now concerned with task of writing bounding_box() flavour for text shapes. We have 3rd party module textview at our disposal, and we want to reuse it for our purpose. It happens that textview exports (in Java terms, has public) functions:



get_origin(TextView) that returns origin point of the text view in form of tuple {X, Y}, and

get_extent(TextView) that returns width and height of the text view in form of tuple {Width, Height}.



Our bounding_box/1 function then might look as follows:




# Calculates bounding box for text drawing;
# returns tuple {TopLeftX, TopLeftY, BottomRightX, BottomRightY}




bounding_box(TextShape) ->
TextView = convert_to_textview(TextShape),
{X, Y} = textview:get_origin(TextView),
{Width, Height} = textview:get_extent(TextView),
{X, Y, X + Width, Y + Height).









What about convert_to_textview/1 function? Not to worry, it should be easy. Remember, TextView and TextShape are not objects, but rather data structures, so conversion is normally just a matter of knowing what these structures are and matching parts of them. Below is a sample implementation, just to give an idea:




# In this case, we assume that TextShape is a list of properties, such as:
# [{text, "Desing patterns"}, {font, "Arial"}, {color, "red"}, .....];
# TextView is a dictionary with keys viewtext, viewfont, viewcolor, viewstyle etc.




convert_to_textview(TextShape) ->
lists:foldl(fun(Prop, Acc) ->
{Key, Value} = convert_prop(Prop),
case Key of
not_present ->
Acc;
_Other ->
dict:store(Key, Value, Acc)
end
end, dict:new(), TextShape).


convert_prop({"text", Value}) ->
{"viewtext", Value};
convert_prop({"font", Value}) ->
{"viewfont", Value};
%% Conversions for other properties
...................................
%% Properties that don't have counterparts in TextView structure
convert_prop({_, _}) -> not_present.










That's it, we have Adapter implementation blueprint for Erlang. Looks kinda trivial, don't you think? That's what you're gonna like once you start Erlang coding - many things are easier and definitely less verbose compared to Java.

Thursday, June 18, 2009

Erlang for Java programmer - power of functions

I have been using Java for more than 10 years now, and at the time I had come across Erlang, while I was excited about what Erlang has to offer, I was a bit worried on how to survive in absence of beloved OO features, such as abstract classes, polymorphism, inheritance etc. It turned out that these questions were somewhat irrelevant, instead I should have asked:



How the problems that OOP (Java, in particular) solves using feature "X" can be solved by functional language (Erlang)?




Polymorhysm vs. Higher-order functions



I'd like to show a practical example where Java programmer would use polymorphism, and Erlang programmer would use higher-order functions.



One of my Jabber/XMPP projects required message filtering based on some set of conditions. The customer wanted to implement some kind of censorship for their chat rooms. If incoming message fails any of those conditions, it has to be dropped. Let's assume that for this task we will maintain a list of pairs {condition, text}, where condition is a boolean string function that applies to the message text, for example the list could look like:

{"contains", "@$#*%!"}, {"equals", "This chatroom sucks"}, {"contains", "morons"}

etc.



So to pass the "appropriateness" test, the incoming message should fail each condition in a condition list.

Now, let's limit ourseleves to 2 functions (contains and equals) and see how we go about coding this in Java:




package com.teamhand.messaging.utils;



import java.util.ArrayList;

import java.util.List;



public class Censorship {

List <Condition> conditions = new ArrayList<Condition<();

public Censorship() {

super();

}



public void addCondition(Condition condition) {

conditions.add(condition);

}



public boolean checkMessage(String message) {

for (Condition condition : conditions) {

if (condition.check(message)) return false; // message has been censored

}

return true; // message has passed the censorship

}



public static void main(String[] args) {

ContainsCondition c1 = new ContainsCondition("@$#*%!");

EqualsCondition c2 = new EqualsCondition("This chatroom sucks");

ContainsCondition c3 = new ContainsCondition("morons");



Censorship c = new Censorship();

c.addCondition(c1);

c.addCondition(c2);

c.addCondition(c3);

String message1 = "I'm a good message";

String message2 = "Are you gonna listen, you morons?";

System.out.println(c.checkMessage(message1));

System.out.println(c.checkMessage(message2));

}

}



// Condition class

package com.teamhand.messaging.utils;



public abstract class Condition {

public abstract boolean check(String message);

}



//Implementation classes

//

//

package com.teamhand.messaging.utils;



// ContainsCondition class

public class ContainsCondition extends Condition {

private String template;

public ContainsCondition(String template) {

this.template = template;

}



@Override

public boolean check(String message) {

return message.contains(template);

}



}



// EqualsCondition class

package com.teamhand.messaging.utils;



public class EqualsCondition extends Condition{



private String template;



public EqualsCondition(String template) {

this.template = template;

}



public boolean check(String message) {

return message.equals(template);

}



}









The implementation is typical - we have a polymorphic list of Condition instances, whose classes implement condition-specific check() method.



Now, it's Erlang's turn:




-module(censorship).

-export([check_message/2, test/0]).



condition({"contains", Phrase}) ->

fun(MsgBody) ->

string:str(MsgBody, Phrase) > 0

end;



condition({"equals", Phrase}) ->

fun(MsgBody) ->

(MsgBody == Phrase)

end;



condition(Other) ->

throw({error, {not_supported, Other}}).



%% Returns false is message should be censored, true otherwise

check_message(Message, Conditions) ->

not lists:any(fun(Condition) ->

Condition(Message) end, Conditions).



test() ->

C1 = condition({"contains", "@$#*%!"}),

C2 = condition({"equals", "This chatroom sucks"}),

C3 = condition({"contains", "morons"}),

CondList = [C1, C2, C3],

{check_message("I'm a good message", CondList), check_message("Are you gonna listen, you morons?", CondList)}.





Note how condition/1 function returns another function, so in check_message/2 we have a list of functions, each one representing a condition. As you may have expected, the solutions are very similar, except the Erlang one bears significantly less code.



To conclude, this post is not to start another flame war on merits of languages, but rather for those OOP programmers who have decided to try Erlang and may need some help in finding common ground while exploring functional style.