Vlákno názorů k článku Perličky: úvod do referencí od LENIN POWER - Prosimvas kdo jeste Perl neumite, tak se ho...

  • Článek je starý, nové názory již nelze přidávat.
  • 22. 2. 2008 2:48

    LENIN POWER (neregistrovaný)
    Prosimvas kdo jeste Perl neumite, tak se ho radsi neucte. Kdybych se misto perlu naucil rovnou Python, udelal bych lip.
  • 22. 2. 2008 6:45

    mach (neregistrovaný)
    Pane,
    ve článku nikdo nikoho nenutil se něco učit. Tento jazyk byl vymyslen člověkem z praxe pro lidi, řešící praktické věci. V žádném případě není výlupek ctností a akademické krásy - na druhou stranu, zatím co v jiných jazycích dokončujete ještě deklarace, tak perlista už balí. Používám několik jazyků, ale díky organizované strávě modulů (CPAN) a díky časovému stresu jsem si za hlavní (a poslední) jazyk zvolil perl. A udělal jsem dobře.
  • 22. 2. 2008 10:05

    Jindroush (neregistrovaný)
    Nechápu, jak něco tak až psychopatického jako Python, může mít tolik příznivců. Grafická úprava součástí programu - peklo smrt čerti.
  • 22. 2. 2008 10:52

    anonymní
    ... "neco tak az psychopatickeho" ... malem sem se udusil cajem, takove slovni spojeni ve spojistosti s pgm. jazykem jsem jeste neslysel :))
  • 22. 2. 2008 14:37

    anonymní
    Právě v čitelnosti je IMHO síla Pythonu... Perl je sice o drobet kompaktnější, ale právě nutnost explicitních dereferencí je něco, co by se v moderním jazyku už dávno vyskytovat nemělo. Číst Perl je díky těm operátorovým zvratkám vo držku- viz příklad, a to by se v perlu navíc správně mělo místo "@$a" psát "scalar(@{$a})" atp..

    def merge(a, b):
    ret = []
    ia = ib = 0
    while 1:
    if ia == len(a):
    if ib == len(b): break
    ret.append(b[ib]); ib += 1
    elif ib == len(b) or a[ia] < b[ib]:
    ret.append(a[ia]); ia += 1
    else:
    ret.append(b[ib]); ib += 1
    return ret

    sub merge {
    my ($a, $b) = @_;
    my $ret = [];
    my $ia = 0;
    my $ib = 0;
    while (1) {
    if ($ia == @$a) {
    last if $ib == @$b;
    push @$ret, $$a[$ia++];
    elsif ($ib == @$b or $$a[$ia] < $$b[$ib]) {
    push @$ret, $$a[$ia++];
    } else {
    push @$ret, $$b[$ib++];
    }
    }
    return $ret;
    }
  • 22. 2. 2008 15:15

    Yenya (neregistrovaný)
    jee, tohle je pekne! Diky za krasnou ilustraci proc Python ne. Vyse uvedeny kod v Pythonu nebude fungovat (kvuli formatovani).
    Jo, nemuzete pastnout kod do HTML komentaroveho systemu, nemuzete psat one-linery, atd.

    Pred elsif Vam chybi zavorka.

    Misto $$a[$ia++] je myslim citelnejsi psat $a->[$ia++].

    Hmm, jak vlastne v Pythonu reknu ze mam lokalni promennou? Pri prvnim prirazeni? To je fakt spatne, protoze pak neodhalite preklep ve jmene promenne uz v compile-time.

    Michani objektoveho zapisu s funkcemi (ret.append() versus len(a)) je taky dost divne.

    -Yenya
  • 22. 2. 2008 19:13

    VM (neregistrovaný)

    Souhlasim s kritikou. Navic ta dvojita reference (push @$ret, ...) je zbytecna - staci push @ret... a pak return [ @ret ];

    To je argumentace stylem : umim Perl jen trochu - jednoduchy problem v nem vyresim neprehledne - takze Perl je spatny. Ja osobne bych to resil takhle - myslim ze to je jeste lepsi nez ten ukazkovy Python.

    sub merge
    {
        my @a=@{$_[0]};
        my @b=@{$_[1]};
        my @ret=();
        my $minlen = (@a<@b ? @a : @b);
        push @ret, map { shift @a, shift @b } (0 .. $minlen-1);
        push @ret, @a;
        push @ret, @b;
        return [ @ret ];
    }
    
  • 22. 2. 2008 22:03

    Michal Svoboda
    Bojim se, ze Vas algoritmus nedela presne co bylo zamysleno. Respektive, netusim, co ma delat ten puvodni, ale pokud to ma byt jeden pruchod mergesortem, tak nekde potrebujete uvnitr porovnavat prvky poli @a a @b.

    Nicmene mi mergesort neprijde jako prilis stastny priklad, jelikoz jedna z velkych vyhod mergesortu je, ze umi radit seznamy daleko vetsi nez je dostupna pamet. Tudiz bych v tomto algoritmu neoperoval vubec s poli, ale spise bych sekvencne nacital vstupy (maximalne bych pouzil tieovane pole, ktere umi jen operace push a shift). (Pokud chci radit neco co se vejde do pameti, muzu pouzit rovnou vestavenou funkci sort.)

    Jinak souhlasim s tim, ze uvedeny priklad vyse byl na primitivni urovni a navic prasacky napsan. Hodne lidi pouziva Perl jako nejake "C na steroidech". (A nejen Perl ale i PHP a dalsi jazyky s C-like syntaxi.) I temto je urcen tento serial.
  • 23. 2. 2008 14:16

    JS (neregistrovaný)
    Velmi spravne! Uz kdyz jsem cetl diskusi, uvazoval jsem o implementaci v Pythonu pres iteratory, protoze mi ty stavajici priklady Pythonu prisly zbytecne slozite (prilis mnoho indexu). Takze moje verze, pro neverici:
    def merge(a,b):
      for aa in a:
        for bb in b:
          if bb>=aa: break
          yield bb
        yield aa
        for aa in a:
          if aa>bb: break
          yield aa
        yield bb
      for bb in b:
        yield bb
    
    a=iter([3,5,7,9,11,13,15])
    b=iter([1,2,4,6,12,14,16,17])
    c=merge(a,b)
    print list(c)
    
    Nejen ze funguje na jakekoli iteratory, tedy i treba radky ve 2 souborech, ale bude patrne i rychlejsi.
  • 23. 2. 2008 18:20

    Rejpal (neregistrovaný)

    Tyhle čachry s iterátorama mi teda nepřijdou moc srozumitelný. Nepřijde mi kupříkladu příliš intuitivní, jakým způsobem se tady střídá řízení mezi těmi výběry. Musel jsem nad tím chvíli přemýšlet, abych to přečetl. Inu, Python. :-)

    A co takhle pěkně čistě deklarativně, pánové? ;-)

    (define (merge . lists)
      (match lists
             ((xs ()) xs)
             ((() xs) xs)
             (((x . xs) (y . ys)) (if (< x y)
                                      (cons x (merge xs (cons y ys)))
                                      (cons y (merge (cons x xs) ys))))))
  • 23. 2. 2008 11:30

    bez přezdívky
    Ačkoliv nevidím důvod k flamewar a uznávám, že perlisti si nezačali, odpovím na věcné výtky.

    1. Že jsou komentářové systémy špatně napsané, není chyba Pythonu. Není však nic jednoduššího, než na začátek každého řádku napsat třeba tečku a pak ji odstranit v editoru pomocí označení sloupcového bloku.

    Na Rootu to lze udělat pomocí html tagu:
    def hello():
        print "hello"
    
    Takže v tomto případě je chybou autora, že nepoužil náhled a situaci nějak nevyřešil.

    2. V Pythonu jsou všechny modifikované proměnné lokální, pokud nepoužijeme klíčové slovo global. Ochránit kód před překlepy není vždy možné a to bez ohledu na použitý programovací jazyk. Rozumný pythonista ale používá nástroje pylint nebo pychecker, které potenciálních problémů najdou opravdu hodně.

    3. One-linery psát lze, ikdyž je to samozřejmě samozřejmě obtížnější než v některých jiných jazycích. Zde je moje one-line (z ohledů ke čtenářům rozdělená do více řádků, ale funguje i po spojení do jednoho řádku) verze programu beer bottles:

    print (lambda beers : (globals().setdefault('beers', beers) and beers(99)))(lambda count:(((count == 0) and
            ("No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.")) or
            ((count == 1) and
            ("1 bottle of beer on the wall, 1 bottle of beer.\nTake one down and pass it around, no more bottles of beer on the wall.\n\n" + beers(count - 1))) or
            (("%d bottles of beer on the wall, %d bottles of beer.\nTake one down and pass it around, %d bottle of beer on the wall.\n\n" % (count, count, count - 1)) + beers(count - 1))
            ))
    
  • 23. 2. 2008 11:50

    bez přezdívky
    Hm, teď vidím, že ten výstup není úplně korektní, ale dá se snadno upravit. Pro demonstraci možnosti psát one-linery to každopádně myslím stačí.

    Nevidím ale stejně moc důvodů one-linery používat. Pokud chci použít Python k rychlému jednorázovému řešení nějaké situace, tak buďto použiju interaktivní prostředí Pythonu (nejlépe ipython) - Perl pokud vím tuto možnost ani nemá - a tam není důvod omezovat se jednou řádkou nebo pro opakované použití napíšu skript a tam můžu mít řádek rovněž kolik chci.
  • 22. 2. 2008 16:16

    Michal Svoboda
    nutnost explicitních dereferencí je něco, co by se v moderním jazyku už dávno vyskytovat nemělo.

    S tim nesouhlasim. Pokud to syntakticky neodlisite, musite zaridit, aby se kazda reference chovala jako samotny objekt. To znamena, ze pri kopii reference budete kopirovat i objekt. V opacnem pripade programator nebude vedet, co se stane, kdyz napise a<-b. Respektive to bude muset nejak "odtusit" z kontextu, coz rozhodne neprispiva k vytvoreni korektniho kodu.

    Číst Perl je díky těm operátorovým zvratkám vo držku

    Reference v Perlu jsou jako Perl samotny. Kdo tomu nerozumi, mysli si ze to je o drzku a dela si z toho vtipy. Kdo tomu rozumi, tak uz nechce jinak :-)

    Navic jako v kazdem jazyce, i v Perlu lze psat uhledny kod i bordel. Na druhou stranu, sebelepe formatovany kod nepomuze, pokud nekdo nezna syntaxi jazyka.

    a to by se v perlu navíc správně mělo místo "@$a" psát "scalar(@{$a})" atp..

    Nemelo, @$a je naprosto spravny zapis. Navic scalar(@{$a}) dela neco jineho.

  • 22. 2. 2008 19:07

    Miloš (neregistrovaný)

    Nečitelnost není vlastností jazyka ale programátora. Co třeba takhle?

    
    sub merge {
    	my $r_a=shift;
    	my $r_b=shift;
    	my @ret=();
    	my ($ia,$ib)=(0,0);
    	my ($ctia,$ctib)=(1,1);   # 0..necti 1..cti 2..konec
    	my ($maxa,$maxb);         # maximalni indexy
    	my $prveka;
    	my $prvekb;
    
    	$maxa=$#{@{$r_a}};
    	$maxb=$#{@{$r_b}};
    
    	while (1) {
    		$ctia=2 if ($ia>$maxa);
    		$ctib=2 if ($ib>$maxb);
    		last if ($ctia==2 and $ctib==2);
    
    		if ($ctia==1) {
    			$prveka=$r_a->[$ia++];
    			$ctia=0;
    		}
    		if ($ctib==1) {
    			$prvekb=$r_b->[$ib++];
    			$ctib=0;
    		}
    
    		if ($prveka<$prvekb) {
    			push(@ret,$prveka);
    			$ctia=1;
    		}
    		elsif ($prveka==$prvekb) {
    			push(@ret,$prveka);
    			push(@ret,$prvekb);
    			$ctia=$ctib=1;
    		}
    		else {
    			push(@ret,$prvekb);
    			$ctib=1;
    		}
    	}
    	return (\@ret);
    
  • 22. 2. 2008 19:20

    VM (neregistrovaný)
    Pekne, ale trosku moc kodu na jednoduchou vec. V Perlu na tohle mame operatory pro praci se seznamy - viz muj prispevek vyse: http://www.root.cz/clanky/perlicky-uvod-do-referenci/nazory/187417/
  • 22. 2. 2008 20:13

    tukan (neregistrovaný)

    Síla? Vážně? A kromě toho, že se to vám nováčkům pěkně čte to má jaké unikátní výhody? Zatím jsem si totiž všiml jediné věci: když se kód rozformátuje, tak jste v hajzlu a opravit to znamená projít a zkontrolovat celou funkcionalitu, protože pouhé odsazení má syntaktický význam - náležitost do sub-bloků kódu. Kromě toho to taky znamená, že si s tím moc nepohrajete, co? Jak to není pod sebou, je to blbě... Zajímavá myšlenka, opravdu!

    Co mě ale nejvíc fascinuje - když nějaký beginner (soudím podle tvé implementace) porovnává dva jazyky a přitom zná jen jeden z nich. Fakt přínos.

    Teď ti ukážu čtyři možnosti implementace: tvoji, a la Perl, lepší a správnou. První tři jsou ekvivalentní, čtvrtá funguje jak bych si představoval (obecněji). Je to subjektivní hodnocení, takže necháme ostatní, aby to posoudili. Samozřejmě existuje nekonečně mnoho způsobů jak v Perlu správně napsat to, oč jsi se pokusil ty, a to je důvod, proč mám Perl rád.

    Mimochodem, nikdy nemám problém s "čitelností", kde se tahle kravina vzala? A reference? Kde bysme byli s C bez pointerů (i.e. referencí) nebo hůř, kdyby C (de)referenci provádělo automaticky?

    Přiložený zdroják je samostatný, stačí paste a spustit. Je to i s benchmarkem všech metod.

    #!/usr/bin/env perl
    # vi:ft=perl
    
    use Benchmark qw( :all );
    
    my @TA1 = qw/ 1 2 3 /;				# Test case A
    my @TA2 = qw/ 1 5 3 4 5 6/;
    
    my @TB1 = qw/ 2 2 3 4 5 6/;			# Test case B
    my @TB2 = qw/ 1 3 3 4 7 /;
    
    my (@M1, @M2);					# Vysledky
      
    #########################[ Reseni 1 ]########################
    #
    # Tvoje sragora, mimochodem v prvnim "push" jsi mel chybu,
    # cpal jsi do vysledku prvky pole A misto pole B. A chybela
    # ti zavorka pred elsif.
    #
    # Uz jen ty reference a dereference vsude, pane boze!!
    #
    sub merge {
    	my ($a, $b) = @_;
    	my $ret = [];
    	my $ia = 0;
    	my $ib = 0;
    	while (1) {
    		if ($ia == @$a) {
    			last if $ib == @$b;
    			push @$ret, $$b[$ib++];
    		} elsif ($ib == @$b or $$a[$ia] < $$b[$ib]) {
    			push @$ret, $$a[$ia++];
    		} else {
    			push @$ret, $$b[$ib++];
    		}
    	}
    	return $ret;
    }
    
    @M1 = @{merge(\@TA1, \@TA2)};
    @M2 = @{merge(\@TB1, \@TB2)};
    print "Reseni 1a: @M1\tReseni 1b: @M2\n";
    
    
    #########################[ Reseni 2 ]########################
    #
    # Takhle bych to napsal od boku.
    # Lepsi? Co myslis?
    #
    sub merge2( \@\@ ) {
    	my @a = @{$_[0]};
    	my @b = @{$_[1]};
    	my @c = map { my @c; push @c, shift @b while $b[0]<=$_ && @b; @c, $_ } @a;
    	return @c, @b;
    }
    
    @M1 = merge2 @TA1, @TA2;
    @M2 = merge2 @TB1, @TB2;
    print "Reseni 2a: @M1\tReseni 2b: @M2\n";
    
    
    #########################[ Reseni 3 ]########################
    #
    # To same, jen bez kopirovani poli a s primou indexaci.
    #
    sub merge3( \@\@ ) {
    	my ($a, $b) = @_;
    	my (@c, $i);
    	map { push @c, $b->[$i++] while $b->[$i] <= $_; push @c, $_ } @{$a};
    	return @c, @{$b}[$i..$#{$b}];
    }
    
    @M1 = merge3 @TA1, @TA2;
    @M2 = merge3 @TB1, @TB2;
    print "Reseni 3a: @M1\tReseni 3b: @M2\n";
    
    
    #########################[ Reseni 4 ]########################
    #
    # Tvuj priklad ale testovaci pole spojuje blbe, viz vystup,
    # protoze predpoklada, ze jsou obe setridena. Co z toho leze
    # kdyz nejsou jsi videl. Ale beru, zes to tak treba chtel.
    #
    # Tohle reseni je ze vsech nejlepsi, protoze pole zmerguje
    # i v pripade, ze nejsou predem setridena a hlavne je trikat
    # rychlejsi nez ostatni (a nepotrebuje extra funkci:)
    #
    
    @M1 = sort @TA1, @TA2;
    @M2 = sort @TB1, @TB2;
    print "Reseni 4a: @M1\tReseni 4b: @M2\n\n";
    
    
    ##########################[ Timing ]#########################
    my $c = 100000;
    print "Cas reseni 1:\n\t"; timethis($c,
    	sub { @M1 = @{merge(\@TA1, \@TA2)}; @M2 = @{merge(\@TB1, \@TB2)} });
    print "Cas reseni 2:\n\t"; timethis($c,
    	sub { @M1 = merge2 @TA1, @TA2; @M2 = merge2 @TB1, @TB2 });
    print "Cas reseni 3:\n\t"; timethis($c,
    	sub { @M1 = merge3 @TA1, @TA2; @M2 = merge3 @TB1, @TB2 });
    print "Cas reseni 4:\n\t"; timethis($c,
    	sub { @M1 = sort @TA1, @TA2; @M2 = sort @TB1, @TB2 });
    
    Výstup:
    Reseni 1a: 1 1 2 3 5 3 4 5 6	Reseni 1b: 1 2 2 3 3 3 4 4 5 6 7
    Reseni 2a: 1 1 2 3 5 3 4 5 6	Reseni 2b: 1 2 2 3 3 3 4 4 5 6 7
    Reseni 3a: 1 1 2 3 5 3 4 5 6	Reseni 3b: 1 2 2 3 3 3 4 4 5 6 7
    Reseni 4a: 1 1 2 3 3 4 5 5 6	Reseni 4b: 1 2 2 3 3 3 4 4 5 6 7
    
    Cas reseni 1:
    	timethis 100000:  3 wallclock secs ( 2.93 usr +  0.00 sys =  2.93 CPU) @ 34129.69/s (n=100000)
    Cas reseni 2:
    	timethis 100000:  3 wallclock secs ( 3.05 usr +  0.00 sys =  3.05 CPU) @ 32786.07/s (n=100000)
    Cas reseni 3:
    	timethis 100000:  3 wallclock secs ( 2.75 usr +  0.00 sys =  2.75 CPU) @ 36363.64/s (n=100000)
    Cas reseni 4:
    	timethis 100000:  1 wallclock secs ( 0.97 usr +  0.00 sys =  0.97 CPU) @ 103092.78/s (n=100000)
    
  • 25. 2. 2008 10:57

    Yenya (neregistrovaný)
    Disclaimer: pouzivam Perl >10 let.

    Kod je zda se dobry, ale nektere konstrukty bych nepouzil.
    V prvni verzi kodu bych asi spis nadeklaroval pole @ret a na konci udelal
    "return \@ret;" - uvnitr kodu by bylo mene dereferencovani a byl by tak jeste
    o kousek citelnejsi a mozna i rychlejsi.

    Vsem kdo v Perlu pisou delsi veci doporuji knihu Perl Best Practices: http://www.oreilly.com/catalog/perlbp/ - ne ze bych se vsim tam uvedenym souhlasil pro sve projekty, ale aspon se autor obtezuje vysvetlit, proc si mysli ze by soucasti programatorskeho stylu neco konkretniho melo nebo nemelo byt. Je to pekne psane a prinuti to cloveka se zamyslet.

    Z konstrukci ktere PerlBP nedoporucuje bych tady konkretne nepouzil prototypy v merge2 a merge3 - prototypy maji nekolik podstatnych nevyhod: napriklad chovaji se jinak v kodu ktery je uvedeny drive nez ta funkce a jinak v kodu pod ni; dale pokud uz reference na ta dve pole mate nekde z drivejska v promenne, tak nemuzete zavolat merge3(@moje_dva_arrayrefy).

    Ale jinak samozrejme, TIMTOWTDI.

    -Yenya
  • 25. 2. 2008 13:59

    Yenya (neregistrovaný)
    Jeste si to tady po sobe ctu, a neudelal bych jeste jednu vec: nenazyval bych kod meho oponenta "sragora" :-(. Je treba argumentovat k veci, ne ad hominem.

    -Yenya
  • 22. 2. 2008 16:53

    JS (neregistrovaný)
    Uprimne receno, docela by me zajimalo, zda jenom tak placate nebo jste zkusil v Pythonu neco (vetsiho, na mensich kusech se to tak nepozna) naprogramovat.

    Kdyz je clanek o referencich, historku ze zivota: Znal jsem cloveka, co byl zaryty Perlista, a na Python take velmi nadaval. Shodou okolnosti nechapal, proc Python reference nepotrebuje - v Perlu mu prisly nezbytne. Pozdeji zkusil programovat v Pythonu; dnes na nej neda dopustit, a na Perl si ani nevzpomene.
  • 23. 2. 2008 23:01

    Václav Haisman (neregistrovaný)

    Napsal jsem jednu netrivialni aplikaci v Pythonu. Reknu Vam, co se mi na Pythonu oproti Perlu nelibilo:

    1. Zadne deklarace. Nekdo to povazuje za vyhodu, me to desne chybelo. Hledat chyby v kodu, kde se clovek prepise v nazvu promenne nebo kde zapomene vytvorit promennou pred telem vnoreneho bloku je fakt opruz.

    2. Prakticky nepouzitelne defaultni hodnoty parametru funkci. Myslim, ze jednoduchy priklad je dostacujici vysvetleni:

    
    def t (s = []):
      s.append (1)
      return s
    
    print t()
    print t()
    
    

    3. Nedostacujici uzavery/lambda funkce. Python ma sice konstrukt lambda:, ale v jeho tele muze byt pouze vyraz.

    4. Chybejici reference. Chybejici reference znemoznuje napsat neco tak zakladniho, jako je funkce swap.

    Tohle jsou vsechno zasadni veci. Pak existuje spousta dalsich mensich problemu jako napr. osklive __identifikatory__, nutnost psat vsude self., chybejici autovivifikace atd.
  • 24. 2. 2008 0:37

    bez přezdívky
    1. To je fakt otázka názoru.

    2. Prakticky nepoužitelný příklad. V praxi tohle vůbec není problém, věř mi (nebo mě zkus přesvědčit).

    3. Silnější lambda funkce by spousta lidí uvítala. O nějakých praktických problémech s uzávěry ale nevím (opět se nechám přesvědčit).

    4. V Pythonu se swap píše a, b = b, a - problém je vyřešen ;). Pythonu má holt některé typy proměnlivé a jiné neměnné. Podle toho se volí hodnoty parametrů. V praxi opět nevidím problém.

    Ty __identifikátory__ jsou "ošklivé" záměrně - aby se "magické metody" nepletly s klasickými metodami. Autovivifikace je typický perlismus. Pokud někdo řekne, že potřebuje autovivifikaci, pak ho neuspokojí žádný jiný jazyk. Pro mě to například zase je víceméně nesmyslná vlastnost.
  • 24. 2. 2008 1:19

    Rejpal (neregistrovaný)
    1. Tak třeba schemeři jsou názoru zcela opačného. Ony to vlastně nejsou deklarace, ale bindings. Binding jasně vymezuje scope a to je užitečnější, než by se na první pohled zdálo. :-) Na problémy se scope docela dojíždí Ruby 1.8, inu, tak to je, když se některé věci nedomyslí. Dvojka to spraví, V Pythonu zase může na člověka při vhodné konstelaci hvězd vyskočit UnboundLocalError, z velmi podobných důvodů.

    3. Pythonovské uzávěry neposkytují mutable bindings, jen immutable. Ač je přiřazení zlo, občas je nutné (pokud jazyk nemá monády nebo něco podobně ztřěštěného :-)). Pravda je, že zrovna v Pythony tyhle věci na přestřes tak často nepřijdou, ostatně lambda je spíš na výrazy než side-effecting akce, ale týká se to třeba vnořených funkcí.

    4. Hmm, to je jen speciální případ. ;-) Ale netuším, jak zrovna tohle souvisí s immutable daty.

    Pokud jde o podtržítka, je zajímavé, že třeba SmallTalk se bez nich obejde, a to je charakterově velmi podobný jazyk. Taktéž Ruby. Možná je to ale jen kulturní záležitost... Pravda je, že SmallTalk má velkou výhodu díky kategoriím metod, které umožňují dělat v metodách pořádek trošku jinak. :-)
  • 24. 2. 2008 11:32

    bez přezdívky
    Odpovím teď jenom na ten 4. bod. Ta implicitní hodnota parametru, kterou pranýřuje Václav Haisman, se konstruuje v okamžiku vytváření funkce a ne pokaždé znovu při jejím volání. To má takový efekt, že seznam z daného příkladu se používá při každém volání znovu - pokud samozřejmě člověk ten parametr nevyplní explicitně. Takže ta implicitní hodnota má chování statické lokální proměnné v C. V případě, že chceme v Pythonu implicitně pracovat s prázdným seznamem, namísto [] použijeme None a není s tím žádný problém. Mně toto chování přijde konzistentní, protože [] je jenom syntaktický cukr pro list() a jako pythonista když vidím list, čekám, že sekonstrukce hned provede. Opožděné provádění kódu jako třeba v MetaOCamlu je určitě příjemná vlastnost, ale Python jím zkrátka nedisponuje. S immutable daty to tedy souvisí tak, že jako implicitní hodnota parametru se muttable v zásadě nepoužívají a dávají se tam jenom "konstanty". Ve jiných jazycích se to dělá podobně a ještě jsem neslyšel názor, že jsou proto implicitní hodnoty parametrů "nepoužitelné".

    Pokud jde o podtržítka, kdo sleduje vývoj Pythonu, ten ví, že magické metody přibývají snad s každou novou verzí. Určitě by bylo pro vývojáře nemilé, pokud by měli nadefinovanou nějakou metodu, jejíž název se v další verzi zalíbí vývojářům Pythonu a následkem té kolize bude objekt v některých situacích vykazovat podivné chování nebo házet výjimky kvůli odlišnému počtu parametrů. Ano, Python jiný prostředek nenabízí. Jiné jazyky však nenabízejí ani tento.

  • 24. 2. 2008 11:35

    bez přezdívky
    Uf, to je překlepů, omlouvám se. Asi si dám ranní kávu. Jenom pro jistotu opravím: ...když vidím list()...
  • 24. 2. 2008 1:49

    Václav Haisman (neregistrovaný)
    1. To neni otazka nazoru, to je otazka dlouholetych zkusenosti. Pokud mohu soudit, tak velka vetsina programovacich jazyku deklarace promenny v nejake forme podporuje. To neni samo sebou.

    2. Tenhle priklad je pochopitelne zjednoduseny a ciste pro demonstraci, ale nerekl bych, ze prakticky nepouzitelny. Naopak, nepouzitelna je semantika defaultnich parametru Pythonu. Rozhodne tedy pro cloveka, ktery je zvykly na pekne pouzitelne defaultni parametry z jazyku jako C++ ci Ada.

    4. Swap neni jedina vec, kterou absence referenci znemoznuje. Znemoznuje jakoukoliv zmenu promenne primitivniho typu jako vedlejsi efekt. To je pro praci v imperativnim jazyce dosti omezujici.
  • 24. 2. 2008 11:07

    bez přezdívky
    Promiň, ale tyhle Tvoje výtky jsou natolik povšechné, že si z nich nemůžu vzít naprosto nic. Já se živím programováním (nejen) v Pythonu už relativně dost roků a myslím, že docela mám povědomí o tom, co se v Pythonu dělat dá a co ne a nakolik to programátora skutečně omezuje.
  • 24. 2. 2008 11:21

    Václav Haisman (neregistrovaný)
    Povsechne? Ja bych rekl, ze jsou pekne konkretni. Take netvrdim, ze se ty nedostatky nedaji obejit a prezit, ale rozhodne praci v nem neusnadnuji.
  • 24. 2. 2008 20:53

    bez přezdívky
    Nejsou pěkně konkrétní. Konkrétní podle mě znamená praktický a sorry, ale ani funkce swap a ani funkce na vložení prvku do implicitně prázdného seznamu moc praktické nejsou. Swap jsem předvedl myslím dostatečně názorně a pokud chci něco obdobného ale složitějšího, můžu například naplnit ty dvě proměnné pomocí návratové hodnoty.
    def minmax(a, b):
        return min(a, b), max(a, b)
    
    a, b = minmax(a, b)
    
    Pokud budu mít složitější program, stejně budu pravděpodobně pracovat se složenými typy a ne s primitivními. Co se týče příkladu na tu implicitní hodnotu, tam není důvod implicitní hodnotu vynechat a případný prázdný seznam posílat explicitně. Jasně, Perl dovoluje každý problém řešit ne dvěma nebo pěti způsoby jako Python, ale dvaceti až padesáti. Toto Python neumožňuje schválně, což však někteří z nás spíše vítají. Pokud má někdo námitku, že nějaký problém v Pythonu špatně řešitelný, pobavme se o tom. Pokud ale námitka zní, že v Perlu nebo některém jiném jazyce to dělá takhle a Python to neumožňuje (ne, skutečně nepotřebuju sahat na parametry funkce pomocí shift ani $_), není to pro mě argument.
  • 24. 2. 2008 20:29

    MikRom (neregistrovaný)
    Ja som na tom skor opacne, napisal som len asi jednu netrivialnu aplikaciu v Perle a viac som napisal v Pythone. Tymto ale nechcem povedat, ze Perl je horsi ako Python, alebo naopak. Oba povazujem za velmi dobre. Keby tu nebol Perl ani Python by tu mozno nebol, lebo Python prebral vela od Perlu. Perl je starsi. Python sa mozno v mnohom snazil byt modernejsi. Niekomu sa to paci a niekomu nie. To je individualna zalezitost.

    1. Ziadne deklaracie ma nijako nerozculuju. Ani v Perle predsa netreba premenne deklarovat. Alebo ako to myslis?

    2. Pre pouzitie defaultnych hodnot si zvolil akurat priklad so zoznamom v ktorom to nefunguje. Python vzdy vytvara na zoznamy referencie a z toho plynie aj spravanie funkcie t(). Ak ju zavolas s argumentom prazdnym alebo neprazdnym zoznamom, bude fungovat, tak ako ocakavas, napr:
    print t([])
    print t([])
    print t(t([]))
    print t(['a','b'])
    print t(['x'])
    
    Toto ako zaobchadza Python s listami ma tiez netesi, lebo pri priradeni list2=list1 sa vytvori len nova referencia na ten isty list. Ak chce clovek vytvorit novy list ako kopiu stareho treba urobit list2=list1[:]
    Inac ale defaultne hodnoty vo funkciach prakticky funguju, napr:
    def halo(meno="Vaclav"):
      return "Halo %s" % meno
    
    print halo()
    print halo ('MikRom')
    
    3. Lambda funkcie neposkytuju taku funkcionalitu ako pomenovane funkcie - ano s tym suhlasim, ale Guido sam nema zrejme lambdy rad a chcel ich v Pythone 3000 povodne aj zrusit. Zrejme si mysli, ze sa moc nepouzivaju. 4. Ze referencie nechybaju, toho dokazom je tvoj priklad s funkciou t(). Na zoznamy sa vzdy pouzivaju referencie. Swap tiez funguje
    l1=['a','b']
    l2=['x','y']
    print "l1=%s, l2=%s" % (l1, l2)
    l1, l2 = l2, l1
    print "l1=%s, l2=%s" % (l1, l2)
    
    Ina vec je, ze netreba explicitne dereferencovat ako v Perle. Ale to pracu so zlozitejsimi strukturami podla mna skor zjednodusuje.

    5. __identifikatory__: Ano v Pythone si treba zapamatat co znamena
    if __name__ == "__main__":
      ...
    
    ale je to podobne ako vediet v Perle, co to je $_,@_,...

    6. self: Python prostrednictvom self pri premennej, resp. funkcii rozlisuje, ci sa jedna o atribut, resp. metodu aktualneho objektu, alebo o nejaky globalny identifikator (ak tam self nie je). Self je vlastne referencia na slovnik, ktory reprezentuje dany objekt. Identifikator self pochadza z Perlu. Python prebral z Perlu sposob, ze objekty su reprezentovane cez asociativne polia (t.j. slovniky). A v Perle sa tiez doporucuje odkaz na aktualny objekt oznacovat ako $self.
  • 24. 2. 2008 22:54

    Václav Haisman (neregistrovaný)
    1. V Perlu sice deklarace pouzivat nemusis, ale kazdy, kdo v nem dela, pouziva "use strict;".

    2. To jsem zvolil, protoze se mi ten priklad pak vejde na 6 radek. To same plati i pro objekty.
  • 24. 2. 2008 23:03

    MikRom (neregistrovaný)
    > V Perlu sice deklarace pouzivat nemusis, ale kazdy, kdo v nem dela, pouziva "use strict;"
    Ano "use strict" sa doporucuje, ja to tiez pouzivam, ale nie som si isty, ci to pouziva kazdy :-)
  • 26. 2. 2008 12:29

    MikRom (neregistrovaný)
    Ked som prvykrat skusal Python, tiez mi povinne odsadzovanie pripadalo nasilne. Ale nerobilo mi to problemy, pretoze som tak pisal aj predtym.
    Vynutene odsadzovanie ma aj svoje vyhody - precitaj si napriklad toto: Python: Myths about Indentation
  • 22. 2. 2008 18:47

    Petr (neregistrovaný)
    Perl dokazu generovat z jineho programu snadno. Generovani Pythonu z jineho programu je problem, protoze musim navic ke vsemu ostatnimu drzet globalni stav indentovani; anebo musim generovat dvoupruchodove, kde v druhem pruchodu zformatuji.

    Dekuji za radu, ale rozhodl jsem se ji nenasledovat.
  • 23. 2. 2008 14:30

    JS (neregistrovaný)
    Pominu-li, ze generovat Python z jineho programu je nesmysl (diky dynamickym vlastnostem jazyka), presto myslim, ze nemusite. Staci, kdyz ve funkci ktera vola funkci generujici radek(y) kodu, do toho radku pripisete prislusnou uroven. Tim se vam ta globalni uroven udrzi rekurzivne. Priklad:
    def generuj_soucet(a,b):
      yield 'print '+str(a)+'+'+str(b)
    
    def generuj_funkci_soucet(x,y):
      yield 'def soucet('+str(x)+','+str(y)+')'
      for s in generuj_soucet(a,b):
        yield '  '+s
    
    for s in generuj_soucet(1,2):
      print s
    
    for s in generuj_funkci_soucet('cislo1','cislo2'):
      print s
    
    
    Pak muzete generator generuj_soucet pouzit na obou urovnich, a budete mit zarovnani spravne, jak ukazuje funkce generuj_funkci_soucet.
  • 23. 2. 2008 17:10

    Rejpal (neregistrovaný)
    Naopak, generování kódu má smysl i v dynamickém jazyku, ba co víc, tam pro něj jsou i mnohem lepší podmínky, neb generátory pro statické jazyky jsou většinou děs na používání. Přínos generování kódu v dynamickém jazyků může být ohromný - třeba sražení zdrojového kódu na zlomek velikosti, a to i ve velkých aplikacích (nebo možná právě v nich) a z toho plynoucí lepší udržovatelnost (samozřejmě hovořím o čistých způsobech generování kódu, nikoli o nějakém prasáckém lepení řetězců dohromady).
  • 23. 2. 2008 17:44

    JS (neregistrovaný)
    Tomu moc nerozumim. Neni proste v dynamickem jazyce lepsi, nez ten kod vygenerovat, ho rovnou provest? A pokud ho chcete generovat kvuli rychlosti, neni lepsi generovat rovnou C? A generovat kod, ktery bude dale nekdo upravovat rucne, mi nepripada zrovna dobry napad (z hlediska spravy). To jsou asi vsechny moznosti, proc byste neco takoveho chtel delat. Asi by se hodil nejaky konkretni priklad.

    Nevim co nazyvate "cistym zpusobem generovani kodu" - kod (ve smyslu zdrojak) jsou prece retezce. Nevim, jak byste to chtel delat cisteji bez retezcu, asi by zase pomohl nejaky priklad. Vyse uvedeny program si navic nedava vyssi ambice, nez byt kratkou ilustraci toho, o cem autor tvrdil, ze to neni mozne.
  • 23. 2. 2008 18:26

    Rejpal (neregistrovaný)
    Tomu moc nerozumim. Neni proste v dynamickem jazyce lepsi, nez ten kod vygenerovat, ho rovnou provest?
    Jako přes eval? A co když ten jazyk používá inkrementální in-memory kompilátor, jako třeba všelijaké mutace Lispu? to ho budete pokaždé znovu kompilovat? ;-)
    A generovat kod, ktery bude dale nekdo upravovat rucne, mi nepripada zrovna dobry napad (z hlediska spravy).
    Proč? To nepoužíváte kompilátory? Nikdo snad neříká, že by se ručně upravoval vygenerovaný kód, takoví šílenci snad už vyhynuli. Pokud generátor vytváří správný výstup, není třeba vrtat se v jeho výstupu - přece když potřebuju upravit program, taky se nevrtám ve strojáku hexeditorem, ale upravím zdrojový kód a zrekompiluju ho. Nevim co nazyvate "cistym zpusobem generovani kodu" - kod (ve smyslu zdrojak) jsou prece retezce. Ehm, řetězce? Už jste slyšel o syntaktickych stromech? A o jejich transformátorech? Nebo třeba o partial application? Pokud vím, partial application používá třeba Psyco.
  • 23. 2. 2008 19:18

    JS (neregistrovaný)
    Pokud kod generujete za behu, tak se urcitym krokum (jako je kompilace) nevyhnete. Pokud se jim totiz dokazete vyhnout, nemusite to resit za behu. To co rikate jenom potvrzuje to, co rikam i ja.

    O AST vim, ale pokud by ten dotycny generoval primo AST (a ja bych to mimochodem delal take tak, ale v Pythonu pro to skutecne nevidim zadny duvod), pak by samozrejme problemy s whitespace asi nemel. ;-)
  • 23. 2. 2008 19:25

    Rejpal (neregistrovaný)
    Pokud kod generujete za behu, tak se urcitym krokum (jako je kompilace) nevyhnete. Pokud se jim totiz dokazete vyhnout, nemusite to resit za behu.
    Tak tomuhle nerozumím. Nebyl by nějaký příklad?
  • 23. 2. 2008 18:42

    Rejpal (neregistrovaný)
    Zatroleně, špatný tlačítko. :-/ Tak znovu a líp...
    Tomu moc nerozumim. Neni proste v dynamickem jazyce lepsi, nez ten kod vygenerovat, ho rovnou provest?
    Jako přes eval? A co když ten jazyk používá inkrementální in-memory kompilátor, jako třeba všelijaké mutace Lispu? to ho budete pokaždé znovu kompilovat? ;-)
    A generovat kod, ktery bude dale nekdo upravovat rucne, mi nepripada zrovna dobry napad (z hlediska spravy).

    Nikdo snad neříká, že by se ručně upravoval vygenerovaný kód, takoví šílenci snad už vyhynuli. Pokud generátor vytváří správný výstup, není třeba se vůbec vrtat v jeho výstupu - přece když potřebuju upravit program, taky se nevrtám ve strojáku hexeditorem, ale upravím zdrojový kód a zrekompiluju ho.

    Nevim co nazyvate "cistym zpusobem generovani kodu" - kod (ve smyslu zdrojak) jsou prece retezce.

    Ehm, řetězce? Už jste slyšel o syntaktickych stromech? A o jejich transformátorech? Nebo třeba o partial application? Pokud vím, partial application používá třeba Psyco. Techniky jako partial application dále stírají rozdíly mezi kompilátory a interprety a přitom můžou často vyžadovat generování kódu za chodu, s tím, že za to něco přinesou - v případě Psyca třeba ten výkon. :-)

    Probém je, kam to generování napasujete. Pokud jazyk AST nějakým způsobem neexponuje (což většina jazyků nedělá), holt se člověk musí uchýlit ke generování textu. Tím sice nenapíšete něco jako Psyco, ale něco jako třeba ESQL už ano, a i k takovým věcem se generování kódu často používá. Nebo třeba AOP, pokud to jazyk neumí lepšími prostředky, jako je třeba metaobjektový protokol. Ale určitě má smysl tyhle věci dělat.

  • 25. 2. 2008 18:59

    Petr (neregistrovaný)
    "Tomu moc nerozumim. Neni proste v dynamickem jazyce lepsi, nez ten kod vygenerovat, ho rovnou provest?"

    Pokud mate na mysli "z Pythonu generuji dalsi Python", pak to muze byt lepsi - ale stejne nemusi.

    Priklady:
    a. Generovani kodu muze byt cast "build" procesu. Nikoliv dynamicky za behu aplikace, ale dynamicky z makefilu.
    b. Proc bych nemohl Python generovat z jineho jazyka? Napriklad z C aplikace? Napriklad protoze ke generovani kodu musim analyzovat velke mnozstvi dat a mam na to v C hotove a odladene knihovny?
    c. A z druhe strany, proc bych nemohl Python generovat ze skriptu nebo treba z sqlplus? Zejmena *tady* mam problem s nejakym globalnim trackovanim hloubky vnoreni.
  • 25. 2. 2008 23:39

    bez přezdívky
    To bych fakt chtěl vidět ten generovaný kód, kde bude tak obrovská hloubka vnoření, že se to nedá snadno vyřešit. Že by to byl jeden velký skript v globálním prostoru s desítkami vzájemně vnořených cyklů a podmínek?
  • 26. 2. 2008 19:35

    Petr (neregistrovaný)
    To vubec nesouvisi s maximalni nebo minimalni hloubkou. To souvisi s nutnosti udrzovat globalni stav. A to muze byt v rozporu s tim, ze nektere casti generatoru nejsou oteviratelne pro zmeny (duvody legalni, licencni, politicke), ze jsou ruzne casti generatoru psany v ruznych systemech (cast prijde z sqlplus, cast z ksh, cast z koupene aplikace, atd.) apod.

    Pokud vase druha veta naznacuje, ze by snad generovany kod mel byt "spravne strukturovany" a ze by to nemel byt "jeden velky skript", pak nechapu proc. Vystup z lexu nebo yaccu snad hezky a strukturovany je? Proc by mel vubec byt?
  • 26. 2. 2008 22:31

    bez přezdívky
    Mohl bych se zeptat, proč by měl být hnusný. Ale OK, budu to generovat systémem každý pes jiná ves - z takového systému bych měl samozřejmě "radost", ale dejme tomu. Není ovšem důvod pamatovat si globální stav. Napadají mě třeba tato dvě řešení:

    1. Nadeklarujeme FUNCSTACK = []. Volající zavolá podřízený generátor, ten vygeneruje funkci stackFunc(). Volající udělá FUNCSTACK.append(stackFunc()). Toto udělá nadřízený generátor kolikrát potřebuje, vybere si funkce ve své funkci třeba pomocí FUNCSTACK.pop() a volá je podle potřeby. Takto si nikdo žádný globální stav pamatovat nemusí; jediný globální stav je v globální proměné FUNCSTACK.

    2. Volající si pamatuje jenom svůj lokální stav a indentuje o jednu úroveň přijatý kód od volaného, kdykoliv je potřeba.
  • 26. 2. 2008 22:42

    bez přezdívky
    Oprava: správně mělo být FUNCSTACK.append(stackFunc) - funkce se samozřejmě volá až v nadřízené funkci po vyzvednutí ze zásobníku.
  • 27. 2. 2008 0:29

    bez přezdívky
    Řešení č. 3:
    class Generator(object):
        def __init__(self):
            self.codeRows = []
    
        def indent(self):
            self.add('$I')
    
        def detent(self):
            self.add('$D')
    
        def add(self, row):
            self.codeRows.append(row)
    
        def process(self):
            indentLevel = 0
            indentedRows = []
            for row in self.codeRows:
                if row == '$I':
                    indentLevel += 1
                elif row == '$D':
                    indentLevel -= 1
                else:
                    indentedRows.append(indentLevel * 4 * ' ' + row)
            exec '\n'.join(indentedRows)
    
    g = Generator()
    
    g.add('print "Zaciname"')
    g.add('for a in xrange(3):')
    g.indent()
    g.add('for b in xrange(4):')
    g.indent()
    g.add('print a * b')
    g.detent()
    g.detent()
    g.add('print "Vse v poradku"')
    g.process()
    
    Řešení č. 4: Nasazení preprocesoru případně i v kombinaci s řešením č. 3.
  • 27. 2. 2008 0:40

    bez přezdívky
    Řešení 6:
    def process_code(code):
        indentLevel = 0
        indentedRows = []
        for row in (r.strip() for r in code.split('\n')):
            if (not row):
                continue
            if row == 'BEGIN':
                indentLevel += 1
            elif row == 'END':
                indentLevel -= 1
            else:
                indentedRows.append(indentLevel * 4 * ' ' + row)
        return '\n'.join(indentedRows)
    
    exec process_code('''
    print "Zaciname"
    
    for a in xrange(3):
    BEGIN
        for b in xrange(4):
        BEGIN
            print a * b
        END
    END
    
    print "Vse v poradku"
    ''')
    
  • 27. 2. 2008 0:48

    bez přezdívky
    Samozřejmě funguje i toto:
    def process_code(code):
        indentLevel = 0
        indentedRows = []
        for row in (r.strip() for r in code.split('\n')):
            if (not row):
                continue
            if row == 'BEGIN':
                indentLevel += 1
            elif row == 'END':
                indentLevel -= 1
            else:
                indentedRows.append(indentLevel * ' ' + row)
        return '\n'.join(indentedRows)
    
    exec process_code('''
    print "Kaslu na level"
    
    for a in xrange(3):
    BEGIN
    for b in xrange(4):
    BEGIN
            print a * b
    END
    END
    
    print "Vse v poradku"
    ''')
    
    Tak co, Petře, furt problémy?
  • 27. 2. 2008 6:51

    Michal Svoboda

    Panove, musim vam neco duleziteho rict. Ne ze bych vam chtel v necem branit, to by me ani ve snu. Jen me to tak napadlo, ... mozna je to malickost, bezvyznamny detail. Ale dobra, kdyz ven s tim tak ven s tim.

    Jste s touhle diskusi celkem brutalne off-topic.

    :D

  • 26. 2. 2008 7:31

    JS (neregistrovaný)
    Dobre, uznavam, ze nejake priklady se najit daji. Ale stejne mi to vsechno pripada v oblasti "klesajicich zisku". Kdyz uz investovat do generatoru kodu, ktery de facto delate jenom proto, abyste to cele mel o drobet rychlejsi (protoze pokud vam na rychlosti nezalezi, tak to v dynamickem jazyce muzete primo provest z nejakych jinych informaci - nemusi to byt nutne skript v Pythonu), to uz je mozna vyhodnejsi generovat primo C, ktere pak pobezi i radove rychleji.
  • 26. 2. 2008 19:41

    Petr (neregistrovaný)
    Generovat primo C... Ale ano, pokud predpokladame, ze C kompilator je zdarma (nebo ze kompilacni a produkcni stroj je tentyz), ze firemni politika povoluje instalaci C kompilatoru na produkcni stroje, ... A ze autor generatoru se krome starani o algoritmy chce starat i o low-level detaily alokace pameti v generovanem kodu ... A ze neni potreba resit problemy multiplatformniho razu (little/big Endian; 32/64/128-bit integer; ...) ... atd.

    Smyslem meho argumentu bylo, ze existuji niche, ve kterych Python bidne hyne zatimco Perl si jich uziva. Implicitne pak tvrdim, ze na zaklade toho je Perl obecnejsi a ma vyssi hodnotu (a ted kvantifikuji, napriklad pro me). Nevyslovena premisa konecne je, ze neexistuje niche, ve kterem prezije Python a ne Perl.
  • 26. 2. 2008 20:36

    JS (neregistrovaný)
    Nevim, me to pripada trochu jako vymluva. Perl prece take obsahuje kompilator, tak pokud vygenerujete kod pro Perl, tak budete mit kompilator na produkcnim stroji - takova politika nedava smysl. To same multiplatformnost - tohle resit, a pritom je urcite zbytek toho programu zkompilovany na tu prislusnou platformu? A low-level detaily se nemaji kompilovat za behu, ty maji byt ulozeny ve vhodne knihovne, kterou ten kod vola.

    Navic, opravdu nic nebrani tomu, generovat z te aplikace jenom nejaky mezivysledek, ktery se pote Pythonem zpracuje nebo zkompiluje (i kdyby slo jen o pridani nejakych znacek zacatek a konec bloku, ale ja bych spis vytahl z te aplikace co vlastne chce a kod vygeneroval Pythonem). Tam uz si to zarovnani pamatovat lze. Nakonec tim usetrite cas, protoze pokud je jazyk, z ktereho chcete ten Python generovat, natolik dementni, ze si nemuzete pamatovat odsazeni, pak si co nejrychlejsim prechodem do Pythonu praci jen usnadnite. :)

    Predchozi odstavec plati i pro Perl, samozrejme.

    Perl a Python jsou prinejmensim ekvivalentni jazyky (to spis Python ma sirsi zaber, protoze treba takovy Blender nebo Maya skriptovani v Perlu neumoznuje). Takze asi tezko najdete situaci, kde by se dal pouzit jenom Perl.
  • 26. 2. 2008 22:37

    bez přezdívky
    Třeba niche webových vyhledávačů (Google, Seznam, Centrum), niche skriptování ve významných počítačových hrách, niche interaktivních interpreterů, niche JVM a CLR?