Tuesday, November 27, 2012

Sorting a vector of pointers to objects using STL and C++11 lambdas

One year ago I posted about how to sort a vector of pointers to objects using STL and functors
As I said then, in C++11 we don't need to use functors, we can use lambdas instead. To show how, we'll use the example from that post again.

We have a stl::vector container that contains pointers to objects of some class, and we'd like to sort them based on the value of some member variable using a STL algorithm.
Let's use the Chocolate class again:
#ifndef __CHOCOLATE_H__
#define __CHOCOLATE_H__

#include <string>

class Chocolate {
  public:
    Chocolate(std::string name, double cocoaPercentage, double price)
    {
      this->cocoaPercentage = cocoaPercentage;
      this->price = price;
      this->name = name;
    };
    ~Chocolate();

    double getCocoaPercentage() { return this->cocoaPercentage; };
    double getPrice() { return this->price; };
    std::string getName() { return this->name; };

  private:
    double cocoaPercentage; 
    double price;
    std::string name;
};
#endif /* __CHOCOLATE_H__ */

We'd like to sort the following vector:
vector<Chocolate*> chocolates;
using the STL sort algorithm and two different sorting criteria: by price and by cocoa percentage.

We'll use the version of the sort algorithm that accepts, besides first and last, a third parameter, comp, which according to sort's C++ reference is a:
"Comparison function object that, taking two values of the same type than those contained in the range, returns true if the first argument goes before the second argument in the specific strict weak ordering it defines, and false otherwise."
The only difference is that, this time, instead of sorting our chocolates vector using functors, we'll use C++11 lambdas or anonymous functions (one for each sorting criterion).
According to wikipedia:
"...an anonymous function (also function constant, function literal, or lambda function) is a function (or a subroutine) defined, and possibly called, without being bound to an identifier."
So now we just need to pass a lambda function (the sorting criterion) to the sort function as its third parameter.

Let's see the sorting in action:
#include "Chocolate.h"
#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

void showChocolates(vector<Chocolate*> & chocolates);

int main(int argc, char **argv)
{
  vector<Chocolate*> chocolates;
  chocolates.push_back(new Chocolate("ChocoKoko", 80., 20.));
  chocolates.push_back(new Chocolate("ChocoLolo", 70., 30.));
  chocolates.push_back(new Chocolate("ChocoBebo", 25., 10.));
  chocolates.push_back(new Chocolate("ChocoBrian", 24., 15.));
  chocolates.push_back(new Chocolate("ChocoMiko", 30., 45.));
  
  cout<<"Sorted by price:"<<endl;
  sort(chocolates.begin(), chocolates.end(), 
    [] (Chocolate *a, Chocolate *b) {
        return a->getPrice() < b->getPrice();
  });
  showChocolates(chocolates);
  
  cout<<endl<<"Sorted by cocoa percentage:"<<endl;
  sort(chocolates.begin(), chocolates.end(), 
    [] (Chocolate *a, Chocolate *b) {
        return a->getCocoaPercentage() < b->getCocoaPercentage();
  });
  showChocolates(chocolates);
  
  for(unsigned int i=0; i<chocolates.size(); ++i) {
   delete chocolates[i];
  }
  return 0;
}

void showChocolates(vector<Chocolate*> & chocolates) {
  for(unsigned int i=0; i<chocolates.size(); ++i) {
    cout<<chocolates[i]->getName()<< " " 
      <<chocolates[i]->getPrice()<<" "
      <<chocolates[i]->getCocoaPercentage()<<"%"<<endl;
  } 
}
We compile it by doing:
$ g++ -std=c++11 Chocolate.h main.cpp -o sorters
And this is the output we get:
$ ./sorters
Sorted by price:
ChocoBebo 10 25%
ChocoBrian 15 24%
ChocoKoko 20 80%
ChocoLolo 30 70%
ChocoMiko 45 30%

Sorted by cocoa percentage:
ChocoBrian 15 24%
ChocoBebo 10 25%
ChocoMiko 45 30%
ChocoLolo 30 70%
ChocoKoko 20 80%
That's how we can sort a vector of pointers to objects using STL and C++11 lambdas.

My first C++11 program

After several attempts I've just managed to compile the last gcc version from source and to install it in my old Ubuntu.

Now I can start playing with C++11.

This is a Hello world program (that I got from here) to check that g++ is working fine:
#include <iostream>

using namespace std;

int main()
{
  auto func = [] () { 
    cout << "Hello world\n"; 
  };
  
  func();
}
To compile it:
 
$ g++ -std=c++11 -o lambdaHello lambdaHello.cpp
And then I get my "Hello world":
 
$ ./lambdaHello 
Hello world

Saturday, November 24, 2012

How to install an alternative version of Pyhton and use it in a virtual environment

I've decided to learn a bit more of Python. My friend @remosu recommended me to use virtual environments so that I can practice with different versions of Python.

First I installed an alternative version of Python on my Ubuntu following the first two steps in this great post by Eli Bendersky:
I installed first some required packages:
$ sudo apt-get install libreadline-dev
$ sudo apt-get install libsqlite3-dev
$ sudo apt-get install libbz2-dev
$ sudo apt-get install libssl-dev
Then I downloaded Python from http://www.python.org/, configured and built it:
$ ./configure
$ make -j
Then I stopped following Eli's post because I wanted to keep the version that was already installed on my computer instead of replacing it with a new version.

I started googling how to it and after a while I found this discussion in Stack Exchange Unix & Linux:
In there I found out that the "trick to easier installation of multiple interpreters from source" was using (thaks to vperic's answer):
$ sudo make altinstall
After doing that I had two Python versions living together in the same Ubuntu. Then I only had to use virtualenvwrapper to create my virtual environment.
First I installed virtualenv and virtualenvwrapper using pip:
$ pip install virtualenv
$ pip install virtualenvwrapper
And executed virtualenvwrapper.sh:
$ export WORKON_HOME=~/Envs
$ mkdir -p $WORKON_HOME
$ source /usr/local/bin/virtualenvwrapper.sh
virtualenvwrapper.user_scripts creating /home/myuser/Envs/initialize
virtualenvwrapper.user_scripts creating /home/myuser/Envs/premkvirtualenv
virtualenvwrapper.user_scripts creating /home/myuser/Envs/postmkvirtualenv
virtualenvwrapper.user_scripts creating /home/myuser/Envs/prermvirtualenv
virtualenvwrapper.user_scripts creating /home/myuser/Envs/postrmvirtualenv
virtualenvwrapper.user_scripts creating /home/myuser/Envs/predeactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/postdeactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/preactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/postactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/get_env_details
virtualenvwrapper.user_scripts creating /home/myuser/Envs/premkproject
virtualenvwrapper.user_scripts creating /home/myuser/Envs/postmkproject
virtualenvwrapper.user_scripts creating /home/myuser/Envs/prermproject
virtualenvwrapper.user_scripts creating /home/myuser/Envs/postrmproject
Finally, I created a virtual environment with python 2.7 called learning_env:
$ mkvirtualenv --python python2.7 learning_env
Running virtualenv with interpreter /usr/local/bin/python2.7
New python executable in learning_env/bin/python2.7
Also creating executable in learning_env/bin/python
Installing setuptools............................done.
Installing pip...............done.
virtualenvwrapper.user_scripts creating /home/myuser/Envs/learning_env/bin/predeactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/learning_env/bin/postdeactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/learning_env/bin/preactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/learning_env/bin/postactivate
virtualenvwrapper.user_scripts creating /home/myuser/Envs/learning_env/bin/get_env_details
(learning_env)~$
To check that the virtual environment really had the right version of Python I did:
$ workon learning_env
(learning_env)bscuser@trikitrok:~$ python
Python 2.7.3 (default, Nov 21 2012, 01:38:50) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Then I got out of the virtual environment and checked that I still had the same version of Python on my Ubuntu:
$ workon learning_env
(learning_env)~$ deactivate
$ python
Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Now I have my own learning environment to play with Python 2.7.

Saturday, November 17, 2012

Interesting Talk: "Seventeen Secrets of the Great Legacy Makeover Masters"

I've just watched a very interesting talk by Brian Foote:
Deep reflections on the nature of legacy code and the tools, strategies and techniques to improve its quality.

Wednesday, November 14, 2012

Refactoring Kata Tennis to State Pattern

Last month I posted about the Tennis Kata and the last Katayuno organized by Softonic.
In each of the four iterations, we used TDD and pair programming to develop the exercise from scratch.
We came to understand the tennis game as a state machine, (see the diagram showed below), and created tests for all the transitions.
We didn't have time to finish the exercise, but, once at home, I redid and finished it.
I commited the result to a public Bitbucket repository stating in the initial commit message that I'd like to refactor the code to the State Pattern to see how far the state machine idea could go.
Before refactoring to the pattern, I had to remove some duplication, rename some method and variables and introduce a Player class. Finally this morning, I was able to do it. It was very nice to observe how all the pieces started to fit together and how the code got simpler.
Thinking about the process retrospectively, I'm under the impression that the transition from the TDD resulting code to the version with the state pattern was not very difficult because the idea of the game as a state machine was there all the time. I wonder how much more difficult would have been to refactor to the state pattern, if the code of the initial solution hadn't followed the machine state idea.
This makes me reflect on how TDD is done and how your view about the problem and your knowledge and experience in refactoring and design can make completely different solutions emerge. I think that some of these solutions, even though they pass all the tests, can paint yourself in a corner from where you will need epic refactoring sessions to get out.
I think that the refactoring step is crucial for TDD success. We should not forget that in TDD we're designing not making tests pass, so we need to make a bit of "small design upfront" in each TDD cycle when creating new tests and when refactoring.
Design does not emerge on its own, we make it emerge. To do that we need to have some intuition or idea about where we'd like to go with the next TDD cycle.
I heard Jason Gorman say once that "Refactoring is the fairy dust that makes TDD magic work". The more I practice, the more I think he is right.