Souhlasim. Neslo mi o jazyky s dynamickou syntaxi, o jejichz realne prakticnosti mam pochyby, ale uvidime, co prinese budoucnost. Slo mi o fenomen slozitosti, ktery se tu prehlizi a je imho vyznamne podstatnejsi ohledne kvality a spolehlivosti vysledne aplikace. Chci-li vysokou spolehlivost, nevyresim to typovym systemem, ale a) vhodnou metodou vyvoje software, zalozenou na dukladnych testech, viz treba extremni programovani, b) kvalitnim testovacim prostredim a c) zvolenám prostredku, ktere mi rozumne snizi druhotnou slozitost, jenz je vyznamnym zdrojem chyb (proto typicky neprogramujeme ve strojovem kodu nebo asm a proto se vyvoj nezastavil ani u jejich nastupcu C, C++, Java /C# nebo dnes popularni JS a Python, kde Python je nejpokrocilejsi, ale take nejmene vykonny). Ony ty testy take zvysuji druhotnou slozitost, ale maji vyhodu, ze nejsou soucasti produkcni aplikace a nezasahuji do ni, ale to uz se ale opakuji. Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
Jen pro doplnění. Kdysi jsem četl jeden zajímavý článek (bohužel už ho teď nedohledám), kde autor považoval za velice důležitý parametr jazyka konzistentní hustotu informací (to je moje parafráze, jak to nazval on už si nepamatuji). Šlo o to, aby nebylo na 3 řádcích "prázdno" a pak na jednom řádku složitá konstrukce. Tímhle nešvarem dle mého názoru trpí třeba Perl nebo Python, naopak jazyky jako Lua nebo Go jsou skoro až řídké (alespoň dle mých zkušeností). Nejzajímavější na tom je to, že ve výsledku nevidím, že by program v Go nebo Lue byl delší než odpovídající program v v Perlu nebo Pythonu, skoro naopak.
Tahle ta konzistentní hustota je podle autora článku klíčová pro snadnou čitelnost/udržitelnost kódu.
Javapublic class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
C#include <stdio.h>
int main(){
printf("Hello, World!");
return 0;
}
Gopackage main
import "fmt"
func main() {
fmt.Println("hello world")
}
Python 3, Luaprint("Hello, World!")
Perlprint "Hello, World!\n";
Python 2print "Hello, World!"
Python není jazyk vycpaný vatou, na to tu jsou jiní experti, třeba Java.
A i co se týče zápisu algoritmu není Python nijak zbytečně ukecaný a jde přímočaře k věci, oproštěn od všeho zbytečného. Následující jsem převzal z nějakého benchmarku jazyku.
Python 2import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
Lualocal h, max, n = {}, 0, 0
for l in io.lines() do
if (h[l]) then
h[l] = h[l] + 1
else
n, h[l] = n + 1, 1
end
max = max > h[l] and max or h[l]
end
print(n, max)
Gopackage main
import (
"fmt"
"bufio"
"os"
)
func main() {
r := bufio.NewReader(os.Stdin)
h := make(map[string]int, 1e6)
max := 1
for {
b, e := r.ReadSlice('\n')
if e != nil {
break
}
l := string(b)
v := h[l] + 1
h[l] = v
if v > max {
max = v
}
}
fmt.Printf("%d\t%d\n", len(h), max)
}
Javaimport java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
Ano, jsou to primitivní demonstrační příklady. Zajímavé to začne být ve chvíli, kdy chceme doplnit třeba unit testy o kterých je tu řeč. Python nabízí několikero možností, pro malé věci se nabízí třeba velmi pohodlný doctest. Následuje drobná úprava předešlého kódu:
import sys
def counter(lines):
r"""
>>> from cStringIO import StringIO as fwrap
>>> counter(fwrap('a\nb\nb\n'))
(2, 2)
>>> counter(fwrap('a\nb\nb'))
(3, 1)
>>> counter(fwrap(''))
(0, 0)
>>> counter(fwrap('a a'))
(1, 1)
"""
h, m = {}, 0
for l in lines:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
return len(h), m
if __name__ == '__main__':
print counter(sys.stdin)
A takto se to použije:
python -m doctest -v dict-test.py
Trying:
from cStringIO import StringIO as fwrap
Expecting nothing
ok
Trying:
counter(fwrap('a\nb\nb\n'))
Expecting:
(2, 2)
ok
Trying:
counter(fwrap('a\nb\nb'))
Expecting:
(3, 1)
ok
Trying:
counter(fwrap(''))
Expecting:
(0, 0)
ok
Trying:
counter(fwrap('a a'))
Expecting:
(1, 1)
ok
1 items had no tests:
dict-test
1 items passed all tests:
5 tests in dict-test.counter
5 tests in 2 items.
5 passed and 0 failed.
Test passed.Bez verbose to vypisuje jenom chyby. Doctest lze separovat do pomocného txt souboru, pokud by někomu vadilo mít testy přímo v kódu. Pro složitější projekty pak python nabízí komplexnější modul unittest. Testy jsou důležité, ale důležité je také aby byly snadno použitelné, jinak je nikdo u menších věcí používat nebude.