Lazy Evaluation and infinite streams in Erlang

The term “lazy evaluation” stems from the notion of deferring the computation of an expression to the point when it’s actually needed. Haskell, for example, supports lazy evaluation natively, in contrast to languages that evaluate expressions instantly. This is called “eager evaluation”, and it is the default for most programming languages, including functional programming languages like Lisp and Erlang.

Lazy evaluation is usually implemented by encapsuling the expression in a parameterless anonymous function, called a thunk. For example, let’s take a function when_null(A, B, C) that returns B if A equals the null atom, otherwise C. Like in an if statement we want B only be evaluated when A equals null otherwise we want to get C. A first draft in Erlang:

when_null(null, B, _) -> B;
when_null(_, _, C) -> C.

Now we call this function with the following arguments:

NewSalary = when_null(get_id(User),
    log:error("User not found: ", User), % log:error returns ok
    increase_salary(User, 100))

Obviously this is not what we intended, since both log:error and increase_salary are executed before stepping into when_null. The result in NewSalary is correct, after all, but with the side effect of executing log:error.

This is where Erlang’s Funs come into play. We can use them to model thunks explicitly:

when_null(null, B, _) -> B(); 
when_null(_, _, C) -> C().

when_null now excepts to be B and C to be Funs with arity 0. We then call when_null by wrapping the arguments in Funs:

NewSalary = when_null(get_id(User),
    fun() -> log:error("User not found", User) end,
    fun() -> increase_salary(User, 100) end)

This looks better now. The evaluation of the arguments is deferred and depending on the value of A only one of the arguments will be executed. All well, you might say, but a simple case statement would have just done it. That’s true, but with lazy evaluation you are able to model data structures that would be hard to implement otherwise. Note that we have to implement lazy evaluation explicitly in Erlang, so compared to Haskell the code is more verbose, since we have to wrap the lazy part in Funs.

Streams

One nice example for lazy data structures are streams. You can imagine streams as infinite lists, where the elements are evaluated lazily. Only the first element, called head, is present, the rest of the stream is represented by a Fun that describes how the following elements are computed. Abelson et al (see [1]) give a well written introduction to streams and implement them in Scheme. There are three fundamental operations: Construction (cons), getting the first element (head) and advancing the stream by one element (next). They must fulfill these properties:

head(cons(<a>, <b>)) = <a>
next(cons(<a>, <b>)) = <b>

Where <a> is some kind of value and <b> is a new stream. The implementation is straightforward:

cons(Head, NextStream) -> {Head, NextStream}.
head({Head, _}) -> Head.
next({_, NextStream}) -> NextStream().

Note that we introduced laziness by assuming that the tail of the stream is a parameterless Fun. That means we have to call cons always like this cons(<...>, fun() -> <...> end), constructing the stream out of a head element and a Fun. When requesting the next stream, the Fun is evaluated and expected to return the new stream. The stream object is nothing more than a tuple of the current head and Fun that “unpacks” the next stream. You can imagine it like a packet; upon retrieving the next element, we unpack it and get the stream advanced by one element.

A useful stream is the set of all integers. It has the following properties:

1 = head(integers()),
2 = head(next(integers())),
3 = head(next(next(integers()))),
...

Accessing an individual element this way is somewhat verbose. It would be nice if we can get it directly:

% Returns nth element of stream, starting from 1.
nth(1, Stream) -> head(Stream);
nth(N, Stream) -> nth(N - 1, next(Stream)).

% The above code get's a bit simpler:
1 = nth(1, integers()),
2 = nth(2, integers()),
3 = nth(3, integers()),
...

Before defining integers/0, let’s introduce some auxiliary functions to construct streams. advance/2 takes an initial start value and a Fun that calculates the next element from the previous one. This function makes it easy to create streams where each element depends on the previous one.

advance(Start, Next) ->
    cons(Start, fun() -> advance(Next(Start), Next) end).

Now we can define integers/0 right away:

integers() -> advance(1, fun(N) -> N + 1 end).

Filter and Map

We are used to operate on lists with functions like lists:filter and lists:map. We can define the same operations on streams, with the difference that they return a stream itself. Let’s look at the filter operation. Instead of going through all the elements of the stream and check if a certain predicate applies (which would be an impractical operation for mortal humans), we create a new stream that returns only the filtered elements.

OddIntegers = filter(fun(X) -> X rem 2 == 1 end, integers()),

1 = nth(1, OddIntegers),
3 = nth(2, OddIntegers),
5 = nth(3, OddIntegers),
...

Likewise works map. It returns a new stream with the mapped values.

SquaredOddIntegers = map(fun(X) -> X * X end, OddIntegers),

1 = nth(1, SquaredOddIntegers),
9 = nth(2, SquaredOddIntegers),
25 = nth(3, SquaredOddIntegers),
...

This is how filter/2 and map/2 are implemented:

% Returns a new stream with filtered values.
filter(Pred, Stream) ->
    case Pred(head(Stream)) of
         true ->
              cons(head(Stream), fun() -> filter(Pred, next(Stream)) end);
         false ->
              filter(Pred, next(Stream))
    end.

filter/2 takes a predicate Pred, which is a Fun with arity 1 that returns true or false for a given stream element and a stream as the second argument. In case of true it returns a new stream with the current head and wraps the tail in the filter. Otherwise it continues filtering the stream until it finds a head element that is accepted by the predicate.

		
% Returns a new stream with mapped values.
map(MapFun, Stream) ->
    cons(MapFun(head(Stream)), fun() -> map(MapFun, next(Stream)) end).

map/2 works similar; it takes a Fun/1 as first argument, which maps a given stream element to a new value and a stream and constructs a new stream with the mapped head element and wraps the tail in the MapFun.

We can use map to define another way of constructing streams, by calculating the value of an element from it’s position:

		
sequence(Fun) -> sequence(1, Fun).
sequence(Start, Fun) ->
    cons(Fun(Start), fun() -> map(Fun, integers(Start + 1)) end).

The sequence of the powers of 2, for example, is defined this way.

powers_of_2() -> sequence(1, fun(N) -> round(math:pow(2, N)) end).

% Example
2 = nth(1, powers_of_2()),
4 = nth(2, powers_of_2()),
128 = nth(7, powers_of_2())
...

Instead of using filter and map we could define SquaredOddIntegers directly by using sequence:

squared_odd_integers() ->
    sequence(1, fun (N) -> K = (2*N-1), K*K end).

Reduce

Let’s look at the reduce operation. It accumulates N elements of the stream, and returns a scalar. This is done by a Fun that takes the i. element and the accumulator and returns a new accumulator.

% Reduces N elements of a stream to a single value by applying
% ReduceFun to the first N elements.
%
% ReduceFun :: fun(Value, Acc0) -> Acc1
reduce(0, _, Result, _) -> Result;
reduce(N, ReduceFun, Acc0, Stream) ->
    reduce(N-1, ReduceFun, ReduceFun(head(Stream), Acc0), next(Stream)).

A stream-inspired implementation of the factorial exploits this function:

factorial(N) ->
    reduce(N, fun(V, Fac) -> V * Fac end, 1, integers()).

% Examples
6 = factorial(3),
24 = factorial(4),
120 = factorial(5)

No blog post on functional programming languages without Fibonacci numbers. I’m presenting the approach from Abelson et al [1, p. 329], since it’s a very clever recursive solution and worth to think about. The idea is to define the stream of Fibonacci numbers by adding a shifted version of the stream to itself. We state that the stream begins with 0 and 1 and then every successive Fibonacci number is the sum of two previous elements of the same stream. To do this elegantly we need an auxiliary function that creates a new stream by adding two streams element-wise:

% Returns a new stream where each elements are the sum of the
% corresponding values of Stream1 and Stream2.
add_streams(Stream1, Stream2) ->
    cons(head(Stream1) + head(Stream2),
        fun() -> add_streams(next(Stream1), next(Stream2)) end).

The Fibonacci numbers are defined by adding the stream of Fibonacci numbers to the tail of itself:

fibs() ->
    cons(0,                        % First element is 0
        fun() -> cons(1,           % Second element is 1
            fun() -> add_streams(  % Recursion kicks in
                next(fibs()),
                fibs()
            ) end)
        end).

If this makes your mind spin, a visual explanation may help (again, of Abelson et al fame):

           1   1   2   3   5   8  13  next(fibs)
           0   1   1   2   3   5   8  fibs()
   --------------------------------------------
   0   1   1   2   3   5   8  13  21  fibs()

The main idea of streams in the context in pure functional programming languages is to introduce a notion of time and state. We advance in “stream-time” by calling next, which, in all of our cases, changes the state of the stream by calculating a new head element. Note that with this approach the time of a stream is decoupled from the real-time. As a variable changes its state over time in the imperative paradigm, so does the stream when we advance through its elements.

Reversable streams

We can push streams even further by introducing reversable streams, which allow us to go back in time. We can achive this by simply adding another Fun that computes the previous stream:

cons(A, B, C) -> {A, B, C}.
head({A, _, _}) -> A.
next({_, B, _}) -> B().
prev({_, _, C}) -> C(). % Calcs the previous stream 

To “undo” a next operation, we call prev. This executes the third element of the tuple, which is expected to return the predecessor of the current stream. Our functions to create new streams need just a little rewrite to support reversable streams:

% Next :: Fun(a_i) -> a_{i+1}
% Prev :: Fun(a_i) -> a_{i-1}
advance(Start, Next, Prev) ->
    cons(Start, 
        fun() -> advance(Next(Start), Next, Prev) end,
        fun() -> advance(Prev(Start), Next, Prev) end).

sequence(Start, Fun) ->
    cons(Fun(Start),
        fun() -> sequence(Start + 1, Fun) end,
        fun() -> sequence(Start - 1, Fun) end).

Note that advance now needs two Funs, Next and Prev: Next returns the successor of a given element, while Prev returns the predecessor. The interface of sequence stays the same, since we can compute each element of the stream from it’s position directly. Hence, the reversable stream of integers looks like this:

integers() ->
    sequence(1, fun(M) -> M end).

Our function to access the Nth element needs a modification. The parameter N is always relative to the current stream, so nth(M + 1, stream) == nth(M, next(stream)) and nth(M - 1, stream) == nth(M, prev(stream)).

% Returns nth element of stream.
nth(1, Stream) -> head(Stream);
nth(N, Stream) when N < 1 -> nth(N + 1, prev(Stream));
nth(N, Stream) -> nth(N - 1, next(Stream)).

% Example
-4 = nth(-4, integers())
-3 = nth(-4, next(integers())

Likewise, implementing map is straightforward:

map(Fun, Stream) ->
    cons(Fun(head(Stream)),
       fun() -> map(Fun, next(Stream)) end,
       fun() -> map(Fun, prev(Stream)) end).

Implementing filter needs some clarification about moving forward and backward. Our current implementation of filter moves the stream silently forward until it’s head matches the predicate. This means filter itself implicitly contains a move operation we have to make explicit when dealing with reversable stream. Thus we have to create two filter functions, one that moves the stream forward on a non-matching head and one that moves it backwards.

% Helper function. Constructs a filtered stream.
% Invariant: Pred(head(Stream)) == true.
filter_cons(Pred, Stream) ->
    cons(head(Stream),
        fun() -> filter_next(Pred, next(Stream)) end,
        fun() -> filter_prev(Pred, prev(Stream)) end).
	
filter_next(Pred, Stream) ->
     case Pred(head(Stream)) of
         true -> filter_cons(Pred, Stream);
         false -> filter_next(Pred, next(Stream))
     end.

filter_prev(Pred, Stream) ->
     case Pred(head(Stream)) of
         true -> filter_cons(Pred, Stream);
         false -> filter_prev(Pred, prev(Stream)) 
     end. 

% filter moves forward by default.
filter(Pred, Stream) -> filter_next(Pred, Stream).

When we call prev on a filtered stream, filter_prev is executed recursively until a head element matches the predicate. Likewise works next, just in the opposite direction.

An example: digital signals

With this toolset we can model digital signals. Erlang is definitly not the language of choice for doing DSP stuff, but the conceptual similarity between digital signals and streams is too alluring. Imagine a sine wave that goes on infinitely with a certain frequency:

sine(Time, Frequency) -> math:sin(2*math:pi()*Frequency*Time).

The parameter Time is a continuous value, ranging from -∞ to +∞. We want to work with different signals, where each signal is a function depending only on time. The standard pitch A is such a signal.

sine_440Hz(Time) -> sine(Time, 440).
sine_1Hz(Time) -> sine(Time, 1).

To make signals compatible with streams we have to transfrom the continuous parameter Time to a discrete one by sampling the signal with a certain frequency.

sampled_signal(Signal, SampleFrequency) ->
    sequence(0, fun(N) -> Signal(1.0/SampleFrequency * N) end).

By using sampled_signal we transform a continuous-time signal to a discrete stream, where each call to head returns the current sample and we are free to move back and forth on the sampled signal with next and prev. Lets look at some values:

% Sampling a 1Hz sine with 10Hz sample frequency.
SampledSignal = sampled_signal(fun sine_1Hz/1, 10) 

0 = nth(1, SampledSignal)
0.951 = round(nth(3, SampledSignal)*1000)/1000
0.587 = round(nth(5, SampledSignal)*1000)/1000
-0.587 = round(nth(7, SampledSignal)*1000)/1000
-0.951 = round(nth(9, SampledSignal)*1000)/1000
0 = nth(11, SampledSignal)

Which is what we expected:

References

  1. Abelson, H.; Sussman, G.; Sussman, J. (1996): Structure and Interpretation of Computer Programs. Cambridge, Mass.: MIT Press.
Comments Off

Wellness Music

I’m quite interested in Ambient Music since a while, so I was happy to get an invitation to present my own music at Club Moozak. Below is a cut from the concert.

Comments Off

Announcing BitLift

BitLift is an upload tool for web projects. I made this simple but helpful tool for myself, but i’m quite sure that there are people who faced the same problems as I did, so i’m releasing it as a small side-project. BitLift focuses on uploading to different environments, but it feels like the version control system that you usually fire up to commit your changes. It does exactly what I need, but I’m sure there are many ways to make BitLift more useful for others. I have an open ear for ideas, so feel free to contribute.

Comments Off

My self made edition of Nietzsche’s works

Several years ago I tried to make books by myself. These attempts led to a self made edition of the works of Friedrich Nietzsche. I downloaded the texts from Project Gutenberg, did the layout, cut and bound the pages and finally wrapped them in nice hard covers. Since then I learned a great deal about typography and typesetting, so I see a lot of mistakes in those early tries. But I’m still happy with it, since it’s a complete piece of work.

Comments Off

A map of my interests

This is a map of the main topics of my interests and how they are interconnected. I drew this to figure out for myself how the topics I found myself being busy on are related to each other. My knowledge of each topic varies, of course, from very basic to a somewhat graduate level.

Surprisingly it happened that the map has the shape of a birdy.

Comments Off

Binder clips are a Good Thing

Binder clips are the best invention for a office since the pencil. They compete only with Index cards. Here are some ideas how to use this global optimum of office tidiness.

This is the cheapest way to have the all the USB cables you need for cameras, scanners, etc. on top of your desk all the time (as seen on Lifehacker).

I always have some index cards around with stuff I want to learn. Binder clips provide a smart way of keeping them always in sight.

This one is very handy. A multiple socket outlet on top of your desk for the rescue. You don’t want to crawl under your desk for every external hard drive you have to plug in, don’t you? I fix them on the desk with UHU patafix.

Comments Off

Generic programming, containers and iterators in brief

When you start with programming you will often hear this terms. The are very, very basic thus very important. I want to shed some light on them:

Algorithms and data structures are defined in a generic way, independent of concrete data types. For example a double linked list is described by its layout of data and the operations that are possible and efficient on it. For the definition of this data structure the concrete data type is of no importance: it could be an integer, a string or—why not—a double linked list again. It’s the same with algorithms: The heapsort algorithm is described as a set of actions to sort a set of data. The only property of the data is that it must be comparable; we need to judge if element a is greater, equal or smaller as element b. The algorithm is generic, in the sense that we can use it to sort integers, a deck of cards, coins, or or books by their heights. Generic algorithms and generic data structures are schemata that are independent of the concrete data they are working with (see [1]).

Generic programming is the attempt to express data types and algorithms independent of a concrete type in a statically typed language. Usually it is desired to retain the type checking at compile time. What does that mean? Let’s look at one way to do generic programming in C++:

We could express a generic sorting algorithm in an OOP language by using a common base class Comparable and write the algorithm in terms of that common base class. In the case of a sorting algorithm the class Comparable must provide a method to compare two instances of the class and compute their order. Polymorphism ensures that the proper methods of the inherited object are executed inside the generic algorithm, although just the interface of the class Comparable is visible inside. Let’s see actual C++ source code:

// Define abstract base class. We use a struct so the
// abstract methods are public by default.
struct Comparable
{
    virtual bool operator > (const Comparable& obj) const = 0;
    virtual bool operator == (const Comparable& obj) const = 0;
    virtual bool operator < (const Comparable& obj) const = 0;
};

// Define concrete class.
class Coin : public Comparable
{
    /* Implements virtual abstract methods 
     * of class Comparable. */
};

// Generic algorithm that returns the smaller object.
// We need pointers or references to ensure polymorphism.
Comparable* min(const Comparable* a, const Comparable *b)
{ return (*a > *b)? b : a; }

// Use the algorithm.
void func()
{
      Coin a(10); Coin b(20);
      Coin* c = static_cast<Coin*>(min(&a, &b));
      // c points now to the smaller coin.
}

As you can see here, there are two problems with this approach: 1) Our algorithm is just usable for subclasses of Comparable which limits its use arbitrarily (for example, we can’t use plain integers with it, altought the algorithm will be just the same for integers) 2) We have to cast the return value properly. This may be no big deal in our example but in a more complex situation it’s annoying. Inside the algorithm we just see a smaller subset of the original object and the type information of the object is reduced to the base class.

Templates and Containers

In C++ the answer to this issues are templates. They are a way of parametrize source code which the compiler instantiates into object code of a concrete type at compile-time. As the name suggests templates are just “templates” of code where one or more parameters are left open. When you use the template, you provide the necessary information for the compiler to instantiate the template into real object code. A basic example of templates are containers: They are parametrized data structures that are defined independently of the concrete data type. When you instantiate the template later you tell the compiler which type it should use to create the object out of the template. Here’s an example:

template<typename T>
class MyContainer
{
    // Container that deals with an arbitrary type T
    // Implementation details omitted.
};

void main() 
{
    // Instantiate MyContainter with type int.
    MyContainer<int> intContainer;
}

Templates are generic because the compiler translates the template code into object code for each instantiated type. Note that in the case you don’t instantiate your template class no code will be generated for it at all. On the other hand, if you intantiate the template with different types, for example MyContainer<int>, a MyContainer<float>, and MyContainer<String> the compiler will create three versions of your container class, one for each type, thus creating three new types. There will be optimizations but basically your template code will be instantianted to three new distinct types.

Iterators

A way to access and traverse the elements of a container are Iterators. They are a design pattern that were popularized in the seminal book Design Patterns by Gamma et al (see [2]). It’s a pattern to traverse the contents of a container and hides the internals of the container. When using iterators, you don’t have to care if your container is a list, an array or a hash table because iterators unify the access to their elements. There are various types of iterators (see [3, 4] for a more thorough explanation), but their common raison d’être is abstracting the access to the elements of a container from its internal data mangement. The Standard Template Library makes heavy use of iterators.

Example of Iterator in C++

// Instanciate template QList with parameter int.
QList<int> myList;

// Put some ints into myList
myList.append(1);
myList.append(2);
myList.append(3); 

// Copyconstruct an iterator that points to the
// first element of myList.
QList<int>::iterator i = myList.begin();

// Iterate through the list and print each value.
while (i != myList.end()) {
    // Accessing the member with the * operator.
    std::cout << *i << std::endl;
    i++; // Move the iterator to the next element.
}

In this C++ example I’m instantiating a template QList with type int. QList is a container class that stores a list of objects. In this example I use it to store integers.

Then I create an iterator i to traverse through the list. myList.begin() returns an iterator that points to the first element of the list. We can compare the iterator with another iterator myList.end() that points after the last element of the list. If both iterators are the same, we know that we have passed the last element. In the loop I am printing the element by accessing it via the * operator and move the iterator to the next element with i++.

Note that in this example * and ++ are overloaded operators and reimplemented by the iterator class. In a programming language without operator overloading there could be methods like i.element() or i.next() that do the same. It’s important to see that i is not a pointer but a whole class that just mimics the behaviour of a pointer. Note that pointers to array members are itself valid iterators.

What’s the benefit of iterators over a simple for-loop you might ask? They provide a unified way to access the members of a container class, completely independent on how the container class is implemented internally. Another benefit is that iterators itself can be defined in a generic way that work nicely together with every container class that provides a certain interface. No matter if your want to traverse a list, map or tree, the iterator classes (should) always work the same way.

References

  1. Dos Reis, G.; Järvi, J. (2005): What is Generic Programming? LCSD 2005.
  2. Gamma, E.; Helm, R.; Johnson, R.; Vlissides, J. (1995): Design Pattern. Elements of Reusable Object-Oriented Software. Boston: Addison-Wesley. p. 257ff
  3. Wikipedia: Iterator
  4. Wikipedia: Iterator pattern

Acknowledgements to Martin Stettner for remarks that tremendously increased the quality of this post.

Comments Off

A little puzzle from the game “Set”

I really like combinatorical problems. This little puzzle came to my mind when I was playing the game “Set” with my friends.

This is what the game is about: Imagine a set of cards, where each card has 1, 2 or 3 elements printed on it that differ in their fill pattern, color and shape. Each of these properties can have one of three characteristics:

  • Number of Elements: 1, 2 or 3
  • Fill pattern: empty, dashed or solid
  • Color: red, green or violet
  • Shape: diamond, oval or wave

A card looks like this for example:

This card shows 3 elements, with dashed fill pattern, in green color, and the shape is a wave. Note that there only can be one characteristic at a time for a card. So there’s no card which has, let’s say, dashed and solid elements printed on it. It’s either dashed or solid. The characteristics are mutual exclusive.

Your deck of cards contains all possible combinations of cards.

Your task is to make groups of three cards each, where either all characteristics of a property are the same or different. This is a valid group for example:

  • Number of elements: same, 2 on each card
  • Color: same, red on each card
  • Fill pattern: different on each card
  • Shape: same on each card

That’s also a group:

  • Number of elements: different on each card
  • Color: different on each card
  • Filling: different on each card
  • Shape: different on each card

Note that this is not a valid group:

  • Number of elements: different on each card
  • Color: different on each card
  • Filling: same on each card
  • Shape: same just on the first two cards, therefore not valid

The question

How many valid groups are possible with your deck of cards? The order of cards in a group is not significant and a different ordering just counts as one group. After you lay out each group you put the cards back into the deck. That means a card can be part of more than one group.

Feel free to post your answer in the comments!

Solution

Click here to view the solution.

1 Comment

Why computer scientists and sociologists don’t talk to each other

Sometimes on a relaxed sunday I think about how my life has progressed so far and then I inevitably think about how the differents fields of my interests are interwoven. Most people have a strange look on their face when I tell them that I’m currently into programming but have studied a sociology. I understand this strange look since also for me it’s quite obvious that sociologists and programmers usually have no contact whatsoever.

Their are numerous reasons for this, but I think the most important is this: Programmers and computer scientists work in a completely different “brain mode” than sociologists do. Computer scientists work in the domain of logical reasoning, dealing with abstract ideas that can be explained in terms of formal systems whereas sociologists mostly deal with imprecise “ordinary” language. They don’t have the luxury of a formal system in which their object of research can be expressed clearly and then analyzed further.

Computer science: abstract ideas expressable in a formal system

Of course, social theory books are bursting with abstract ideas and concepts, so sociology doesn’t lack of abstract ideas. But there’s no way to express them in a formal system, you have to use the rich but inevitably vague toolset of ordinary language. Think of basic sociological terms like “norms”, “values”, “social conflict”, “trust” or “social system”, which are all abstract concepts, compared to “turing machine”, “recursion”, “visitor pattern”, “red-black tree”, “lambda function”, to name a few. It’s easy to explain the latter ones unambiguosly in a few sentences quite precisely, whilst the first ones can only be explained in terms of a specific school of thought or related to the writings of this or that sociological theorist.

Sociology: abstract ideas expressed in ordinary language

Sociological ideas are mosty vague, subject of interpretation and constantly critized by members of different schools of thought. Sociology is a highly “paradigmatic” discipline with a wide range of competing theories that are also conflicting to each other. If you’re trained in a formal science like maths or computer science and try to figure out how sociology works by digging yourself into contradicting theories, I can tell you this is a guarantee to make your brain hurt badly.

Nonetheless, I want to argue that the “soft sciences” like sociology and philosophy are not isolated islands from the continent of “hard sciences”. I would consider myself the be an inhabitant of both worlds, though it’s not an easy task for me to switch between them. Usually it takes some time for me to get “acclimatized” on either sides, although I have quite a recognizable bias towards the more formal disciplines.

Why is math “hard”?

I find it quite annoying when I hear tech guys boasting about how smart they are by showing off their maths skills. They do nothing else than use the fact that math is socially accepted to be hard. It’s not intrinsically hard, since if you have a talent for math your obviously don’t find it hard at all. Maybe you find it complicated, but solving a complicated problem can actually be a lot of fun. But to be a math genius doesn’t imply at all that you also excel at writing a sociological paper. So if something’s hard or not depends solely on the person and on his or her talents and on nothing else.

The reason for the general thought of math being “hard” is that it is taught at school, so firstly every one gets in contact with it and secondly it is easy to check if you’re right or wrong when doing your tests. The opposite is the case with the social sciences: It is relatively unimportant for your school career (why?) and it is very difficult to judge if your text or project is bad, medium or excellent.

Is sociology “easy”?

As far as I can tell, I found it very hard to write a good sociological paper, one that I could be proud of and where the difference of the quality between the books that I have studied for it and the paper itself is not dizzying. For me it’s much easier to grasp formal ideas than sociological concepts. The object of sociological reasoning makes it quite difficult to be as precise as computer scientists can be on their topics. Sociologists lack the luxury of precisely bounded objects. No matter how bright you are, you will fail to write precisely about a subject that itself lacks of a precise boundary.

Summary

I often encounter different types of prejudices towards different branches of science. Computer science is sometimes said to be “hard” and “valuable” because you have a chance of getting a well paid job your studies. Sociology is “easy” and not so “valuable” because it produces no visible and immediate results for the economy. I disapprove 1) a mindset that judges the usefulness of a scientic discipline solely by it’s economical relevance. Obviously, the economy is very important driving force of our society, but there’s more to science than its economical value. 2) I want to encourage everyone in broadening his or her experience with different modes of expressing ideas and different ways of using his or her brain. It’s a life changing experience to dig yourself into complex books, may it be social theory or computer science. Sociology can train you that there are ideas out there which have no definite solution. Which are not just true or false. Which are subject to constant refinements, rearrangements and mutations.

Comments Off

How to integrate custom widgets in Qt Designer

Last time we created a simple widget that expanded a label with a rendering effect. Now we want to integrate this widget into Qt Designer. This involves three steps:

  1. Mark the widget as exportable
  2. Tell Qt Designer about the properties of our widget
  3. create a class EffectLabelPlugin derived from QDesignerCustomWidgetInterface that holds all the meta information for Qt Designer.

Let’s start with the project file:

QT += core gui
TEMPLATE = lib
CONFIG += designer plugin
CONFIG += release
HEADERS += EffectLabel.h
HEADERS += EffectLabelPlugin.h
SOURCES += EffectLabel.cpp
SOURCES += EffectLabelPlugin.cpp
target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target
DEFINES += _DESIGNER_EXPORT

We’re creating a library for Qt Designer, hence TEMPLATE must be set to lib. Then we use CONFIG to tell qmake that the target is a plugin for Qt Designer. To use the widget in Qt Designer it must be compiled in release mode. HEADERS and SOURCES are obvious. Finally, we define a make install action and set the target path of the created library to the designer subdir of the Qt plugins directory. We use the preprocessor variable _DESIGNER_EXPORT as a switch to include needed header files in our widget code.

Our header file of the widget looks much the same as in the first part of this tutorial, but it has two subtle differences:

/**
 * EffectLabel.h
 */
#ifndef EFFECTLABEL_H
#define EFFECTLABEL_H

/* Include QDesignerExportWidget only if we're exporting
   the widget as a designer plugin.
*/
#ifdef _DESIGNER_EXPORT
#include <QDesignerExportWidget>
#else
#define QDESIGNER_WIDGET_EXPORT
#endif

#include <QLabel>
#include <QPaintEvent>
#include <QPainter>
#include <QPoint>

class QDESIGNER_WIDGET_EXPORT EffectLabel : public QLabel
{
	Q_OBJECT

public:

    /* These properties are accessible by Qt Designer*/
    Q_PROPERTY(Effect effect READ effect WRITE setEffect)

    /* Tell Designer about the Enum */
    Q_ENUMS(Effect);

    /* ... unchanged code omitted ...*/
};
#endif

Depending of the presence of _DESIGNER_EXPORT we include QDesignerExportWidget.h, which defines QDESIGNER_WIDGET_EXPORT. Obviously, this macro defines the class as exportable in a dynamic library. If we use the widget in our application project, we don't need this directive (it would produce an error), hence it's depending on _DESIGNER_EXPORT, which is only defined in our project file for the Qt Designer plugin and not the application, where we actually use it.

To make a widget property accessible by the Qt Designer property editor, you use the macro Q_PROPERTY. In it's most basic form it consists of the Type and the name of the property followed by its getter and its setter method. Q_PROPERTY makes a property of a class accessible to Qt's meta object system. It is not only used by Qt Designer but also in various other contexts (see [1], [2]). The wonderful thing about Qt Designer is, that it understands a great bunch of Qt's classes natively and renders the correct edit field in the property editor. It doesn't matter if your property is a QString, QSize, QColor etc. The property gets correct edit fields from Qt Designer.

The source file EffectLabel.cpp hasn't changed at all, so we omit it here.

To tell Qt Designer about our widget, we have to create a wrapper class that provides meta information about it and makes it accessible for Qt Designer via a dynamic library. The plugin class must be inherited from QDesignerCustomWidgetInterface and implement all it's virtual abstract methods. These methods tell Qt Designer the name of our widget, in which group it should be positioned in the widget box and so forth. Let's take a look at the declaration of the plugin class:

/**
 * EffectLabelPlugin.h
 */
#ifndef EFFECTLABELPLUGIN_H
#define EFFECTLABELPLUGIN_H

#include <QDesignerCustomWidgetInterface>

#include "EffectLabel.h"

class EffectLabelPlugin :
    public QObject,
    public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)

    bool initialized_;

public:
    EffectLabelPlugin(QObject *parent = 0);

    bool isContainer() const;
    bool isInitialized() const;
    QIcon icon() const;
    QString domXml() const;
    QString group() const;
    QString name() const;
    QString toolTip() const;
    QString whatsThis() const;
    void initialize(QDesignerFormEditorInterface *);
    QWidget* createWidget(QWidget *parent);
    QString includeFile() const;
};
#endif

We inherit it from QObject and QDesignerCustomWidgetInterface and tell the meta object compiler about it via the macros Q_OBJECT and Q_INTERFACES(QDesignerCustomWidgetInterface). The public methods provide the necessary information for Qt Designer and are quite self explanatory. name() returns the name of widgets, group() the group where it belongs to in the widget box and icon() defines its icon. createWidget() returns a pointer to the widget itself. domXml() returns a QString with a little .ui snippet, that just contains the widget. A look at the source file reveals the concrete information.

/**
 * EffectLabelPlugin.cpp
 */
#include <QtPlugin>
#include "EffectLabelPlugin.h"

EffectLabelPlugin::EffectLabelPlugin(QObject *parent) :
    QObject(parent),
    initialized_(false)
{ }

bool EffectLabelPlugin::isContainer() const
{ return false; }

void EffectLabelPlugin::initialize(QDesignerFormEditorInterface *)
{ if (initialized_) return; initialized_ = true; }

bool EffectLabelPlugin::isInitialized() const
{ return initialized_; }

QIcon EffectLabelPlugin::icon() const
{ return QIcon(); }

QString EffectLabelPlugin::domXml() const
{
    return "<ui language=\"c++\">"
           "  <widget class=\"EffectLabel\" "
           "  name=\"effectLabel\" />"
           "</ui>";
}

QString EffectLabelPlugin::group() const
{ return "My Widgets"; }

QString EffectLabelPlugin::name() const
{ return "EffectLabel"; }

QString EffectLabelPlugin::toolTip() const
{ return ""; }

QString EffectLabelPlugin::whatsThis() const
{ return ""; }

QWidget* EffectLabelPlugin::createWidget(QWidget *parent)
{ return new EffectLabel(parent); }

QString EffectLabelPlugin::includeFile() const
{ return "Wallpaper.h"; }

Q_EXPORT_PLUGIN2(EffectLabelPlugin, EffectLabelPlugin)

The code above provides the most necessary information to Qt Designer. The methods in detail:

  • isContainer: Returns false, since the Label doesn't contain other widgets.
  • initialize: This method allows the widget to access the Qt Designer's various windows upon creation by accessing the parameter. We don't need this, so we basically do nothing.
  • icon: Provide your own fancy icon or use the default icon (as we do here).
  • domXml: Composes the widget by returning a sippet of an .ui file (see here for details about domXml).
  • group: The group in the Qt Designer's widget box that the widget belongs to.
  • name: The name of the widget.
  • toolTip: A string to help the widget identify by the user in Qt Designer.
  • whatsThis: A longer description of the widget.
  • createWidget: Returns a pointer to the widget.
  • includeFile: The header file of the class.

Last but not leat we declare the class as exportable with Q_EXPORT_PLUGIN2. The first parameter is the file name, the second one the name of the class.

Compile and install

  1. Compile the plugin in release mode.
  2. Copy the resulting files into to designer subfolder of your Qt's plugin folder. These are on Mac: libEffectLabelPlugin.dylib; on Windows, when compiling with mingw: libEffectLabelPlugin.a and EffectLabelPlugin.dll, when compiling with MSVC: EffectLabelPlugin.lib, EffectLabelPlugin.lib and EffectLabelPlugin.dll.
  3. The easy way to do this is invoking  make install
  4. in the terminal.

Pitfalls

Take care of the following pitfalls when exporting your widgets:

  • I had problems when my widget was encapsulated in a namespace. It seems that there's a bug when using namespaces, since the reference suggests that there should be no problems when using namespaces. It was one in my case. Rule of thumb: Don't place your widget within a namespace.
  • Use Q_PROPERTY to make a widget's property accessible in Qt Designer's property editor. When reading the Qt tutorial you may think that writing your own subclass of QDesignerPropertySheetExtension may be the right way to do this, but you just need this in case you want to make a completely custom layout for the property editor.

References

  1. Qt's Meta object system: http://doc.trolltech.com/4.6/metaobjects.html
  2. Qt's Property system: http://doc.trolltech.com/4.6/properties.html
  3. Creating Custom Widgets for Qt Designer: http://doc.trolltech.com/4.6/designer-creating-custom-widgets.html

Wanna try out this code by yourself?

Fork the project on GitHub:
http://github.com/wplaschg/EffectLabel-Part2

Or download the source as a zip file:
http://github.com/wplaschg/EffectLabel-Part2/zipball/master

Comments Off