Interesantno mesto gde se vrše elementarne minimizacije u izračunavanju logičkih funkcija je kompajler. Programski jezik C uslove (unutar if i while) razrešava tako što pokušava da uštedi na operacijama na sledeći način:
- ako se izraz sastoji od dva dela povezanih sa OR (operator ||) rezultujući kompajlirani program će prvo izračunati levi deo, pa ako je tu rezultat true desni deo se neće ni izračunavati a uslov se tretira kao tačan, jer je TRUE OR X = TRUE.
- ako se izraz sastoji od dva dela povezanih sa AND (operator &&) rezultujući kompajlirani program će prvo izračunati levi deo, pa ako je rezultat false desni deo se neće ni izračunavati a uslov se tretira kao netačan, jer je FALSE AND X = FALSE.
Jezici koji su naslednici C-a uglavnom primenjuju istu ideju, i to samo po sebi nije problem, jer je rezonovanje korektno. Ono što jeste problem je što C dopušta da se u uslovu izvršavaju naredbe.
Razmotrimo sledeći kod:
int x = 0;
int y = 0;
if( ++x > 0 || ++y > 0 ){
printf(“Jeste”);
}
printf(“%d %d”, x, y);
++x je prefiksni inkrement, i vrši uvećanje vrednosti promenjlive za 1. Unutar uslova će se prvo uraditi ++x, pa x dobija vrednost 1, 1 jeste veće od 0 i levi deo je tačan. Desni deo radi isto to sa y. Očekivali bismo da nakon uslova, u poslednjem redu, bude ispisano 1 1, tj. da je unutar uslova inkrementiran i x i y. To nije slučaj, biće inkrementiran samo x, tako da na kraju dobijamo ispisano 1 0.
„Normalni“ programski jezici, kao što je C# i Java, ne dopuštaju ovakvu sintaksu i ograničavaju programera da u uslovu piše isključivo operacije poređenja (što je i očekivano). Međutim, i dalje je moguće imati problem, ako se u uslovu pozivaju funkcije, koje pored toga što vraćaju rezultat, prave i neke „sporedne efekte“ – npr. upisuju broj izvršavanja u fajl. Pogledajmo ovo:
if( imaNaRacunu(user, iznos) && zeliDaKupi(user, proizvod) ){
kupi(user, proizvod);
}
I ovo deluje u redu, na prvi pogled. Ono što je problem je što funkcija zeliDaKupi(user,proizvod) radi tako što proverava da li korisnik ima proizvod u listi želja, a u poseban spisak upisuje trenutak kada je to proveravano, kako bi se primetili korisnici koji vrše akcije vezane za kupovinu, da bi na osnovu toga sistem mogao da im šalje promotivne mejlove i sl. U slučaju neuspešnog pokušaja kupovine, kada kupac nema dovoljno para, marketing tim će ostati bez obaveštenja o interesovanju za proizvod, a to nije baš najbolje.
Naravno, ovo su prilično pojednostavljene situacije i u praksi se to uglavnom dobro izbegava, ali treba biti svestan da loše pisan kod može da se raspadne na zaista zadivljujućim mestima i pod iznenađujućim uslovima.
Posledica ove priče biće jasnija u drugom delu predmeta, kada budemo ušli u koncepte funkcionalnog programiranja i naučili šta su to sporedni efekti i čiste funkcije.