29 grudnia 2013

[python] Dekoratory

Python ma wbudowany mechanizm pozwalający na implementowanie dekoratorów (wzorzec projektowy), dla istniejących metod. W skrócie, przed wywołaniem pożądanej funkcji wołana jest wcześniej zdefiniowana funkcja dekoratora, której argumentem jest pierwotna funkcja. Dekorator zwraca nową funkcję, która ma być wołana w miejsce pierwotnej.

Poniżej przykład dla funkcji obliczającej rekurencyjnie silnię. Stworzone zostały dwa dekoratory. Pierwszy zajmuje się zapamiętywaniem obliczonych już wartości. Druga metoda drukuje na ekranie parametry wywołania funkcji. Fajny sposób na zapewnienie single responsibility principle.
def cache(fun):
    cache_map = {}
    def _f(*args):
        try:
            if args in cache_map:
                return cache_map[args]
            cache_map[args] = result = fun(*args)
            return result
        except:
            # some element of args can't be a dict key
            return fun(args)
    return _f

def log(fun):
    def _f(*args):
        print('log: ' + fun.__name__ + '(' + str(*args) + ')')
        return fun(*args)
    return _f

@cache
@log
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)

assert factorial(3) == 6
assert factorial(1) == 1
Wynik:
log: factorial(3)
log: factorial(2)
log: factorial(1)
log: factorial(0)

22 grudnia 2013

Digital certificate

Rozglądam się w temacie certyfikatów cyfrowych podpisujących strony. Kilka linków i prost zabawa z OpenSSL.
Informacje o certyfikacie i sprawdzenie czy jest wystawiony przez zaufane źródło
# Informacje na temat certyfikatu wyeksportowanego z Firefox-a
$ openssl x509 -text -in A-Trust-nQual-03.pem

$ openssl verify A-Trust-nQual-03.pem 
A-Trust-nQual-03.pem: OK

21 grudnia 2013

[C++14] Hello world

Kompilacja z ficzerami dla C++14. Niestety dla clang-3.4 wymagało to trochę zachodu, ale w końcu się udało. Przed kompilacją trzeba było doinstalować "libc++-dev - LLVM C++ Standard library (development files)".
sudo apt-cache search libc
sudo apt-get install libc++-dev
Następnym krokiem była edycja pliku cstdio. Jak przeczytałem pod tym linkiem, ::gets najwyraźniej zostało usunięte ze standardu, a ja przy próbie kompilacje otrzymywałem następujący error:
/usr/include/c++/v1/cstdio:156:9: error: no member named 'gets' in the global namespace
using ::gets;
      ~~^
1 error generated.
Sama poprawka jaką należy wprowadzić do /usr/include/c++/v1/cstdio, czyli otoczyć gets defajnsem:
#if !_ISOC11_SOURCE
using ::gets;
#endif
Kompilacja wygląda następująco:
$ clang++ -std=c++1y -stdlib=libc++ main.cpp
I kod, na którym testowałem
#include <iostream>

using namespace std;

auto fun() {
    return "Hello world";
}

int main() {
    cout << fun() << endl;
    return 0;
}

11 grudnia 2013

[C++11] Dziedziczenie/unhide konstruktora

W nowym standardzie klasa pochodna może odziedziczyć (jest to właściwie mechanizm unhide, jaki był do tej pory dostępny tylko dla metod) swój konstruktor z jednej lub więcej klas bazowych. Jeżeli taki sam konstruktor (z takimi samymi parametrami) pojawi się w kilku klasach bazowych należy zdefiniować własną wersję w klasie pochodnej. Ciekaw linki:
Mechanizm pozwala na niejawne zadeklarowanie wszystkich konstruktorów, które nie są: domyślnymi, copy/move ani konstruktorami o takiej samej sygnaturze jak już istniejące konstruktory z klasy bazowej.

W poniższym przykładzie klasa Derived, dziedziczy z dwóch klas bazowych, dla których zachodzi konflikt dla Base1(int) i Base2(int), powodujący błąd kompilacji. Aby się go pozbyć w klasie pochodnej należało stworzyć własną wersję tego konstruktora. Ponieważ w Derived pojawił się już konstruktor, kompilator nie wygeneruje za nas konstruktora domyślnego (linia 32 - nie działa) - można stworzyć własną wersję.
#include <iostream>
#include <vector>
using namespace std;

struct Base1 {
    Base1() { cout << "Base1" << endl; }
    Base1(std::vector<int>) { cout << "Base1(vector)" << endl; }
    Base1(int) { cout << "Base1(int)" << endl; }
};

struct Base2 {
    Base2() { cout << "Base2" << endl; }
    Base2(int) { cout << "Base2(int)" << endl; }
};

struct Derived : public Base1, public Base2 {
    using Base1::Base1;
    using Base2::Base2;

    // Ta wersja konstruktora znajduje się w Base1 i Base2
    // należy zdefiniować jej własną wersję!
    Derived(int i) : Base1(i), Base2(i) {
        cout << "Derived(int)" << endl;
    }
};

struct SimpleDerived : public Base1 {
   using Base1::Base1;
};

int main() {
//  Derived d1;
    Derived d2(789);
    Derived d3({1, 2});

    SimpleDerived s1;
    SimpleDerived s2(42);
    SimpleDerived s3({1, 2});

    return 0;
}
Wynik:
Base1(int)
Base2(int)
Derived(int)

Base1(vector)

Base2
Base1

Base1(int)

Base1(vector)

7 grudnia 2013

Ubuntu 13.10 - konfiguracja

Kolejna przesiadka tym razem na Ubuntu 13.10.

Układ klawiatury

Niestety w tej wersji wyparowała opcja zmiany układu klawiatury, co w moim przypadku powoduje uciążliwy problem w korzystaniu z klawiszy Shift+Home i Shift+End, które mam na klawiaturze numerycznej. Można skorzystać z rozwiązania jakim jest gnome-tweak-tool.
Znalazłem jeszcze jedno rozwiązanie, które nadaje się do wykorzystanie z fluxbox-em.
Przez wpisanie do .bashrc
# Set numeric keypad behavour so that shift <numeric key> works the same
# as shift <cursor key> when numlock is off.
setxkbmap -option numpad:microsoft

Wyłączenie konta gościa

Trzeba dopisać na koniec pliku /etc/lightdm/lightdm.conf.d/50-unity-greeter.conf
allow-guest=false

Zwalnianie miejsca na dysku

Doszło do tego, że zaczęło mi brakować miejsca, na partycji. Pomocne okazało się kilka opcji dla apt-get
# Czyści lokalne repozytorium, ze ściągniętymi paczkami. Usuwa paczki, 
# których już nie można ściągnąć i są w zasadzie bezużyteczne.
sudo apt-get autoclean

# Usuwa pliki które są cache-owane, kiedy program jest instalowany 
# albo uaktualniany.
sudo apt-get clean

# Usuwa paczki, które zostały zainstalowane w celu nasycenia 
# zależności dla innych  paczek i nie są już potrzebne.
sudo apt-get autoremove

1 grudnia 2013

[C++11] Wyjątki i noexcept

Jeżeli wyjątek wystąpi w konstruktorze, nawet jeżeli obiekt jest tylko częściowo stworzony standard gwarantuje, że stworzone już dotąd obiekty zostaną poprawnie zniszczone. Tak samo w przypadku gdy wyjątek wystąpi w momencie inicjalizacji tablicy albo kontenera.

Jeżeli destruktor działa na operacji, która może zniszczyć obiekt, powinien on z-wrapować taką operację w blok try i obsłużyć wyjątek lokalnie. Destruktory nie powinny rzucać wyjątków! Jeżeli podczas zwijania stosu destruktor rzuci wyjątkiem którego sam nie złapał program zostanie zterminowany.
#include <iostream>
using namespace std;

struct MyClass {
    ~MyClass() /* noexcept */ {
        throw std::exception();
    }
};

int main() {
    MyClass a;
    return 0;
}
Wynik:
terminate called after throwing an instance of 'std::exception'
  what():  std::exception
The program has unexpectedly finished.
Kilka zasad dotyczących tworzenia, rzucania i łapania wyjątków:
  • Obiekty wyjątków, które są rzucane, muszą mieć dostępny destruktor, a także konstruktor kopiujący lub konstruktor move.
  • Najbardziej wyspecjalizowany catch musi pojawić się jako pierwszy.
  • Aby wyrzucić wyjątek wyżej, trzeba podać throw bez wyrażenia (throw;).
  • Aby złapać wyjątek każdego typu trzeba skorzystać z catch(...), który powinien zawsze pojawiać się jako ostatni.
#include <iostream>
#include <typeinfo>
#include <stdexcept>
using namespace std;

void old() {
    throw std::runtime_error("old()");
}

void young() {
    try {
        old();
    } catch(const std::bad_cast& e) {
        cout << e.what() << endl;
    } catch(...) {
        cout << "unknown, rethrow" << endl;
        throw;
    }
}

int main() {
    try {
        young();
    } catch(const std::runtime_error& e) {
        cout << "in main: " << e.what() << endl;
    }

    return 0;
}
Wynik:
unknown, rethrow
in main: old()

Lista inicjalizacyjna konstruktora

Konstruktor nie może złapać wyjątków rzuconych z listy inicjalizacyjnej. Aby się przed tym ustrzec, blok try musi znajdować się przed dwukropkiem. Zachowanie jest podobne w działaniu do zwykłych try-catch, z tą różnicą że złapany wyjątek zostanie ponownie wyrzucony z bloku.
#include <iostream>
#include <stdexcept>
using namespace std;

struct Member {
    Member() { }
    Member(Member& m) {
        throw std::runtime_error("Constructor");
    }
};

struct BadCalss {
    Member member;
    BadCalss(Member& m) try : member(m) {
        // body
    } catch(...) {
        cout << "some bug" << endl;
    }
};

int main() {
    Member m;
    BadCalss bc(m);
    return 0;
}
Wynik:
some bug
terminate called after throwing an instance of 'std::runtime_error'
  what():  Constructor
The program has unexpectedly finished.

noexcept

W nowym standardzie pojawił się specjalny specyfikator noexcept. Jeżeli wiemy, że funkcja nie będzie rzucać wyjątku, może z tej informacji skorzystać i programista i kompilator. Wspominał o tym również Scott Meyers w swoim wykładzie na Going Native 2013. Kompilator w takim przypadku wygeneruje znacznie mniej kodu, który będzie bardziej optymalny w działaniu.
#include <iostream>
#include <stdexcept>
using namespace std;

void fun() noexcept {
    throw std::runtime_error("fun()");
}

// gun() ma taki sam specyfikator rzucanych typów jak fun()
void gun() noexcept(noexcept(fun())) {
    cout << "gun()" << endl;
}

int main() {
    fun();
    return 0;
}
Wynik:
terminate called after throwing an instance of 'std::runtime_error'
  what():  fun()
The program has unexpectedly finished.
W rezultacie noexpect powinno być stosowane w dwóch przypadkach. Kiedy jesteśmy przekonani, że funkcja nie rzuci wyjątku albo/i gdy nie chcemy obsługiwać błędu. Jeżeli z funkcji (oznaczonej jako noexcept) zostanie jednak rzucony wyjątek, natychmiast zawołane zostanie std::terminate().

Inny przykład, w którym wyjątek przelatuje przez funkcję z noexcept, co powoduje zterminowanie programu.
#include <iostream>
#include <stdexcept>

using namespace std;


void fun_a() {
    throw std::runtime_error("bug");
}

void fun_b() noexcept {
    fun_a();
}

void fun_c() {
    try {
        fun_b();
    } catch(...) {
        cout << "Exception caught" << endl;
    }
}

int main() {
    fun_c();
}
Wynik:
terminate called after throwing an instance of 'std::runtime_error'
  what():  bug
The program has unexpectedly finished.
Niektóre kontenery jak np. std::vector, sprawdzają (podczas realokacji wektora), czy "move konstruktor" jest oznaczony jako noexcept. Jeżeli tak nie jest zostanie zwołany zwykły konstruktor kopiujący, co jest operacją dużo wolniejszą. Odpowiedni eksperyment stworzyłem w innym artykule.
Poza "move konstruktorem" noexcept standardowo powinno znaleźć się również w deklaracji destruktora.

Stare - throw()

W poprzedniej wersji standardu istniało słowo kluczowe throw(), które obecnie jest uznawane za przestarzałe. Można było za jego pomocą wyspecyfikować jakiego rodzaju wyjątki mogą być wyrzucone z funkcji, albo (odpowiednik noexpect) że funkcja nie rzuci żadnego wyjątku.
int fun(std::string& b) throw();