wtorek, 10 marca 2015

Przezroczysty wskaźnik (PIMPL), czyli piękno rzeczy prostych

To jeden z moich ulubionych wzorców projektowych. Przydaje się zarówno do uproszczania nagłówka klasy jak i skraca czas kompilacji w dużych projektach. Przezroczysty wskaźnik (lub po prostu PIMPL) to wzorzec tworzenia abstrakcji pewnej struktury/klasy tak, aby (w najczęstszym przypadku) ukryć całą informację o budowie części prywatnej. Z racji, że jakakolwiek zmiana w części prywatnej dzieje się poza nagłówkiem, taka zmiana nie wymusza rekompilacji wszystkich plików zależnych od tego nagłówka. W dużym projekcie to na prawdę duża oszczędność.

Urok przezroczystego wskaźnka bierze się z zasady kompilacji w C/C++. Jeżeli klasa/funkcja posiada/bierze wskaźnik na typ złożny (T*) to dopóki nie próbujesz wyłuskać składowej klasy T lub utworzyć jej instancji, kompilatora nie interesuje budowa typu T. Dlaczego? Bo wskaźnik ma zawsze ten sam rozmiar, więc kwestia alokacji jest jasna. Aby kompilator nie narzekał, że używasz typu nieokreślonego w nagłowkach wystarczy zrobić deklarację wprzódstruct T. Przy deklaracji wprzód, ponieważ nie zamierzamy odnosić się do budowy tego typu, słowo struct i class można stosować zamiennie.

Koncepcja wskaźnika przezroczystego:

  • W nagłówku, części prywatnej, deklarujesz wprzód, że dana klasa ma lokalną strukturę, ale jej nie opisujesz
  • W nagłówku, części prywatnej, określasz że dana klasa ma składową typu wskaźnik na lokalną strukturę (wciąż nieopisaną)
  • W pliku .cpp dostarczasz budowę klasy TwojaKlasa::StrukturaWewnętrzna
  • W konstruktorze swojej klasy tworzysz instancję klasy lokalnej podpinając ją pod widoczny w nagłówku wskaźnik
W kodzie wygląda to tak: klasa.hpp
#ifndef KLASA_H
#define KLASA_H

#include <string>

class Klasa
{
  public:
    Klasa();
    ~Klasa();

    std::string twojeImie() const;

  private:
    struct Pimpl;
    Pimpl* priv;
};

#endif //KLASA_H

klasa.cpp
#include "klasa.hpp"

struct Klasa::Pimpl
{
  std::string imie;

  Pimpl(const std::string& imie)
  {
    this->imie = imie;
  }
};

Klasa::Klasa()
{
  priv = new Pimpl("Imie");
}

Klasa::~Klasa()
{
  delete priv;
}

std::string Klasa::twojeImie() const
{
  return priv->imie;
}

Jedyny dyskomfort związany z użyciem przezroczystego wskaźnika wiąże się z debuggowaniem kodu, bo mimo iż gdb ma dostęp do składowych chronionych klasy, a tym samym struktury lokalnej, to niekiedy z niewiadomej przyczyny GDB traci zdolność wykonania introspekcji budowy klasy lokalnej, na szczęście nie jest to częste. Jeżeli ktoś z Was wie jak temu zaradzić, będę wdzięczny za notkę w komentarzach.

wtorek, 27 stycznia 2015

C++: Operator przecinka, czyli jak ładnie zrobić pętlę

Dzisiaj w kodzie popełnionym przez kogoś z firmy, odnalazłem perełkę pokazującą inny sposób tworzenia pętli for w oparciu o iteratory. Tym drobiazgiem czyniącym róznicę jest sprytne wykorzystanie operatora przecinka i konstruktora iteratora. Wygląda to tak:

#include <vector>
#include <iostream>
int main()
{
  int array[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  std::vector<int> vector(array, array+8);

  for ( std::vector<int>::const_iterator it(vector.begin()), end(vector.end());
  end != it;
  ++it )
    std::cout << *it << std::endl;

  return 0;
}

Takie proste, a jakie ładne.

czwartek, 25 grudnia 2014

Dekorator w Python: Testowanie: Podmiana ciała funkcji

Z racji na wygodną składnię i elastyczność Python'a używanie dekoratorów jest potężnym środkiem, szczególnie w pisaniu aplikacji sieciowych, czy testowaniu oprogramowania. Chciałbym pokazać prosty przykład tego, jak wygodnie i elegancko podstawiać ciała funkcji na potrzeby testów.

Ogólna idea dekoratora w Python

Mamy funkcję bezargumentową o nazwie przywitaj_sie, która wypisuje na ekran i zwraca wartość prawdy. Chcąc objąć ją dekoratorem o nazwie dekorator (nazwa zmyślona), należy przy definicji użyć następującej notacji:
@dekorator
def przywitaj_sie():
    print 'Witaj'
    return True
Dekorator zazwyczaj jest funkcją, która ma zwrócić wywołalny obiekt, który podmieni przywitaj_sie. Definiując go nad funkcją powodujesz, że dekorator się wykonuje w chwili udekorowania funkcji przywitaj_sie a następnie zwraca wywoływalny obiekt podmieniający działanie funkcji przywitaj_sie. Dwa wnioski: dekorator (zazwyczaj funkcja) winien przyjmować jeden parametr, który jest wywoływalny; dwa: winien zwracać obiekt wywoływalny o takiej samej ilości parametrów jak funkcja, którą dekoruje (tu: zero).

W wielu przypadkach wręcz wskazane jest użycie domknięć. Definiując dekorator dla funkcji z przykładu powyżej można zrobić tak:

def dekorator(callme):
    def zamiennik():
        return False
    return zamiennik

Po udekorowaniu funkcji każde wywołanie funkcji przywitaj_sie zwraca wyłącznie False.

Dekorator może zwrócić swój argument, czyli teoretycznie nic nie zmieniać. To podejście stosowane jest szczególnie w wypadku mechanizmów rejestrowania wywołań zwrotnych (callbacks), gdyż dekorator jest uruchamiany podczas dekorowania każdej funkcji, a nie przy jej wywołaniu. Programowanie sieciowe notorycznie korzysta z tego mechanizmu np. do ustalania rejestrowania akcji na określony wzorzec URL albo rejestrowania wywołań zwrotnych (callback) na określony kod stanu HTTP.

Wracając do podstawień funkcji... Argumentem dekoratora może być cokolwiek, co jest wywoływalne, np. lambda. Dekorator musi zwracać cokolwiek wywoływalnego, może być również lambda. Jeszcze inna rzecz, że dekorator musi być wywoływalny (callable), co w wypadku Pythona oznacza bycie regularną funkcją, lambdą lub ... klasą ze zdefiniowaną metodą __call__().

Moja koncepcja podmiany wywołań funkcji (przydatne podczas testowania) to:

class Mocker(object):
    def __init__(self, substitute):
        assert(callable(substitute))
        self.substitute = substitute
    def __call__(self, mocked):
        assert(callable(mocked))
        return self.substitute
I przykłady zastosowania:
import random

@Mocker(lambda : random.random() > 0.5)
def zwroc_false():
    return False

for i in range(10):
    print zwroc_false()

@Mocker(lambda x,y : x*y)
def suma(a,b):
    return a+b

print suma(2,3)
print suma(3,4)

@Mocker(lambda s : s+'snake')
def podwoj_lancuch(lancuch):
    return s*2

print podwoj_lancuch('Ala')
print podwoj_lancuch('Alicja')

niedziela, 30 listopada 2014

Problem z operatorem trójelementowym

Parę dni temu C++ robił mi za kawę: podniósł ciśnienie bez łyka kofeiny. Poniższy kod:

#include <iostream>
#include <string>

std::ostream& operator<<(std::ostream& stream, const char* chr)
{
        stream << 0;
        return stream;
}

std::ostream& operator<<(std::ostream& stream, const std::string& str)
{
        stream << 1;
        return stream;
}

int main()
{
        std::cout << ( true ? "CCharStar" : std::string("StdString") ) << std::endl;
        std::cout << ( true ? std::string("StdString") : "CCharStar" ) << std::endl;

        return 0;
}
przeciąża operator strumienia dla łańcucha znaków oraz std::string. Zgodnie z pobieżną logiką pierwszym przypadku użycia operatora trójelementowego, z racji że warunek jest spełniony, winno wypisać "0", a w drugim "1".

To jest C++, więc nie może być łatwo. Niuans pokazany w tym kodzie był pośród setek innych linii, które posądzałem o nieprawidłowe działanie kodu. Po głębszej analizie tego, co powoduje błąd/niezrozumienie sprawa okazuje się całkiem prosta, ale serio mówiąc zajęło to trochę czasu.

W obu przypadkach zostanie wypisane "1", mimo że w pierwszym przypadku oczekiwałoby się 0. Przyczyną jest to, że operator trójpunktowy zawsze oczekuje, aby typ zwracany przez obie sekcje był identyczny, tym samym operator ?: nie jest wymienny z if-else. Tutaj są dwa różne typy, więc kompilator samowolnie szuka metody rzutowania jednego w drugi. Ponieważ std::string da się zbudować z const char*, to dochodzi do tego absurdu. Sytuacji by nie było, gdyby std::string miał konstruktor typu explicit, co oznacza niemożność niejawnego utworzenia zmiennej tego typu (np. poprzez operator trójelementowy).

Nie neguję słuszności tego mechanizmu a jedynie chcę się podzielić spostrzeżeniem, które - w bardziej 'życiowym' kodzie potrafi sprawić niemałą zagwozdkę, szczególnie w przypadku gdy programista nie jest zupełnie świadom, że oba typy użyte w tym operatorze powiązane są hierarchią dziedziczenia lub jeden da się zbudować z drugiego. Ani GCC, ani Clang (w domyślnej konfiguracji) nie wychwytują tego jako błędu. Następnym razem opiszę cyrk z tym operatorem gdy właczymy do tego dziedziczenie.

czwartek, 26 czerwca 2014

[Linux] KDE Rekonq i luka w bezpieczeństwie

Od jakiegoś czasu miałem problem z aktualizacjami systemu, w szczególności duże update'y szły jak krew z nosa. Łącze rzędu 40-50kbps przypominały mi czasy modemów ściągania map do Quake po 2 godziny jedna. Pomimo przepisania sources.list na mirror innego kraju problem nie ustępował. Dzisiaj podczas ściągania pakietu o rozmiarze < 1MB dostałem kolejne odrzucenie. Coś mnie zaintrygowało...

Od pewnego czasu próbnie używam KDE Rekonq - takiej lekkiej przeglądarki opartej o WebKit. Skonfigurowałem ją jakiś czas temu tak, aby działała przez zagraniczne proxy. Rozwiązanie? Ustawiając proxy w Rekonq ustawienie propagowane jest do konfiguracji całego KDE. Niniejszym, używając równolegle Firefox'a czy ręcznego apt-get wszystko będzie w porządku, ale np. aktualizując system za pomocą graficznego KDE Muon wszystkie aktualizacje także idą przez proxy. To samo dotyczy między innymi usług kryptograficznych (pobieranie kluczy GPG dla oprogramowania) czy pobierania paczek "security". Piękna dziura.

Aha.. teraz pobieram aktualizacje ok. 1.8Mbps.

niedziela, 23 marca 2014

Raport o zarobkach w zawodzie programisty w Polsce - Sedlak&Sedlak

Otrzymałem raport na temat wynagrodzeń na stanowisku inżynier oprogramowania w Polsce. Raport został przygotowany przez firmę Sedlak&Sedlak.

Dwie konkluzje:
  • Mityczne zarobki programistów rzędu 15 000 zł netto to bajka
  • Programiści z wyższym zarabiają mniej od tych z podyplomowym
Raport do pobrania stąd: http://pl.scribd.com/doc/213989917/Analiza-593-Inzynier-oprogramowania-pdf

Processing.js - Processing dla JavaScript

Dawno temu, w jednym z pierwszych postów hucznie zapowiedziałem język Processing. Nie zmieniam zdania, że to jeden z najbardziej innowacyjnych pomysłów ostatnich lat, bo jako jedyny umożliwia przyzwoite programowanie osobom, które nie są programistami - co więcej, pomimo że był celowany w nieprogramistów, Processing ma coraz silniejsze grono użytkowników ze strony profesjonalistów. Dlaczego? Bo nikt nie lubi się męczyć, a skoro można coś zrobić w Processing, to po co utrudniać.

Od niedawna istnieje projekt Processing.js, który umożliwia translację kodu Processing do natywnego JavaScript. Podkreślam, że nie ma miejsca żadna kompilacja. Całość pracuje natywnie w JavaScript. Oprócz oczywistej korzyści z odrzucenia konieczności eksportu do apletu Java pojawia się ogromny potencjał integracji Processing z milionem wspaniałych narzędzi: począwszy do D3JS, czy choćby jakiś MVC - w rezultacie tworzenia stron WWW z interfejsem artystycznym. Bajka!

Podtrzymuję, że JavaScript jest najważniejszą technologią tej dekady.

poniedziałek, 17 marca 2014

Google Dev Art

Dopiero dziś się o tym dowiedziałem!
Trwa Google DevArt, czyli konkurs prac wizualnych napędzanych kodem. Projekty mogą pracować pod Androidem, czy Linuxem. Dopuszczono między innymi Javę, HTML5, Cpp czy Python. Można korzystać z ogromu zewnętrznych bibliotek, także OpenCV. Co ciekawe, projekty mogą korzystać z Arduino czy Raspberry PI. Brzmi cudnie ^-^

piątek, 7 lutego 2014

Wprowadzenie do STL

Kiedyś, dawno temu, miałem okazję prowadzić w ramach koła naukowego wprowadzenie do C++ STL. Materiały szczególnie przydadzą się maturzystom wybierającym C++, studentom rozpoczynającym pracę z C++ oraz osobom, które wolą C.

Część pierwsza: http://secred.pl/2012/06/16/stl-materialy-z-prezentacji/
Część druga: http://secred.pl/2012/06/16/stl-podejscie-drugie-materialy-z-prezentacji/

wtorek, 4 lutego 2014

C/C++: Operator nawiasu kwadratowego

Niech:

int tab[] = { 1, 2, 3, 4, 5 };
const int n = 2;


wtedy można zrobić tak:

int wynik = tab[n];

ale ale ...... można też tak:

int wynik = n[tab];

Dziwne?

W zasadzie tak wyszło przez przypadek. Gdy powstawał C (a może nawet B), operator nawiasu kwadratowego był lukrem składniowym. Nim wprowadzono go do języka n-ty element tablicy tab otrzymywano w taki sposób:

T operator[]( loperand, roperand )
{
  return *(loperand+roperand);
}
(co całkiem nieźle tłumaczy czemu tablice numerujemy od zera)

Później wprowadzono operator[], który wewnątrz robi dokładnie to samo, co kod powyżej. Ponieważ relacja jest przemienna, bo *(tab+n) <=> *(n+tab), to możliwe jest zamiana indeksu i tablicy.

Lubię ten język : )