Perl 5 pokračuje, možná trochu ve stínu perlu 6, jehož interpret v první stabilní verzi by snad již letos opravdu měl vyjít, poklidně ve vývoji. Cílem dnešního článku je postupně projít některé změny, které se za poslední rok od verzí řady 5.20 udály a trochu čtenáře zasvětit do toho, co se s perlem vlastně v poslední době děje.
Na začátku je třeba podotknout, že vývoj perlu 5 běží nezávisle na perlu 6, ačkoliv jsou velmi často změny v perlu 5 perlem 6 inspirovány. Jde ale o dva různé jazyky a dva různé týmy lidí, kteří se na jejich vývoji podílejí.
Hlavním člověkem a release managerem posledních major verzí je již od řady 5.16 Ricardo Signes.
Instalace
Na distribuční balíčky nové verze perlu si asi budeme muset chvíli počkat, ale kdo by chtěl, může si novou verzi nainstalovat ze zdrojových kódů.
Doporučit lze instalaci pomocí nástroje perlbrew
, který je přímo určen pro správu několika verzí perlu zároveň a nevyžaduje žádné zásahy do stávajícího systému, takže nový perl může testovat opravdu každý. Navíc pomocí něj lze instalovat také vývojové verze, release candidate distribuce atd.
Instalace perlbrew
je velmi přímočará. Postupujme pomocí návodu na perlbrew.pl. Příkaz
> wget -O - http://install.perlbrew.pl | bash
provede instalaci samotného perlbrew
. Pro instalaci konkrétní verze perlu do perlbrew
pak zavoláme
> perlbrew install perl-5.22.0
Dále můžeme zvolit implicitní verzi perlu pro stávající sezení
> perlbrew switch perl-5.22.0
a nebo místo toho volat všechny příkazy s prefixem
> perlbrew exec --with perl-5.22.0 [příkaz]
Tedy například:
> perlbrew exec --with perl-5.22.0 perl program.pl arg1 arg2
My budeme dále v tomto článku používat alias perl5.22.0
:
> alias perl5.22.0="perlbrew exec --with perl-5.22.0 perl"
Verzování perlu
V posledních letech se ustálila linuxovým jádrem inspirovaná pravidla pro vydávání nových verzí perlu 5:
- Stabilní verze perlu 5 jsou sudá čísla, lichá čísla označují vývojové verze
- Major verze perlu 5 vychází každý rok koncem května. Tedy 5.22 vychází v červnu 2015, 5.20 vyšlo v květnu 2014, 5.18 v květnu 2013 atd.
- Dále ještě vznikají u stabilní větve minor verze, do kterých se obvykle pouze backportují důležité opravy a nemají žádná pravidla o tom, kdy musí vycházet. Nedávno se například stalo, že vyšly verze 5.18.3 a 5.18.4 den po sobě, ačkoliv zde to bylo způsobeno chybou během vytváření instalačního balíčku. Na jaře, když vyjde major verze, má vždy minor verze číslo 0 a to se, inkrementuje, je-li potřeba vydat opravnou verzi.
- Minor verze ve vývojové větvi jsou vydávány každý měsíc. Prvních cca 7 měsíců (do poloviny ledna) se přidávají nové featury a poté dochází ke zmrazení a po zbytek roku se pouze vychytávají chyby.
- Malé vývojová minor verze jsou obvykle nestabilní, protože všichni mergují své nové featury, které psali po dobu od posledního zmrazení (leden až květen). To potom od července do ledna zlepšuje, tedy až na okamžik před dalším zmrazením, kdy opět všichni chtějí na poslední chvíli ještě zahrnout svůj kód do nadcházející major verze. Když je vývoj zmrazen, tak je hlavním úkolem opravovat padající testy, kterých má Perl obrovské množství pro různé platformy. Díky Jenkinsu, což je projekt pro continuous integration, se v tom pak dělá pořádek.
Změny oproti řadě 5.20
Pojďme se tedy podívat na konkrétní změny. Zde jsou vybrány pouze některé, pokud možno ty zajímavější. Kompletní přehled je v dokumentu perldelta, který je součástí distribuce. Dokument perldelta má zčásti formální syntaxi a existují nástroje, díky kterým dostaneme rozdíl mezi libovolnými verzemi perlu. Je tedy v podstatě sám o sobě jednoduchým správcem verzí.
Operátor vstupu <<>>
Operátor <>
se používal jako zkratka pro <ARGV>
, kde ARGV
byl implicitně definovaný ovladač souborů předaných na příkazovém řádku, pokud byly definované; nebo případně vstup z STDIN
. Díky této konstrukci lze v perlu velmi snadno předané soubory číst.
Tento způsob čtení pomocí operátoru <>
má ovšem jeden nedostatek - nelze ho použít pro všechny soubory. Ve skutečnosti se totiž argumenty příkazového řádku ještě interpretují, což v některých okrajových případech může způsobit pro někoho možná nečekané chování. Příklady interpretovaných znaků je |
, >
, >>
apod.
Pojďme se podívat podrobněji o co jde. Nejprve vytvořme soubor s trochu obskurním jménem echo SOUCAST_JMENA_SOUBORU |
a uložme do něj nějaký obsah.
> echo 'OBSAH SOUBORU' > 'echo SOUCAST_JMENA_SOUBORU |'
Nyní je již jasné, kam míříme. Zkusme nyní číst pomocí operátorů <>
a <<>>
a pozorujme rozdíl:
> perl5.22.0 -e 'while (<>) {print;}' 'echo SOUCAST_JMENA_SOUBORU |'
SOUCAST_JMENA_SOUBORU
> perl5.22.0 -e 'while (<<>>) {print;}' 'echo SOUCAST_JMENA_SOUBORU |'
OBSAH SOUBORU
>
V prvním případě došlo k interpretaci argumentu, zatímco v druhém se nic takového nestalo.
Zájemci si mohou zkusit totéž se souborem začínajícím na >
a smazat tak obsah potenciálně existujícího souboru.
Otázkou je, jak řešit tento problém v dřívejších verzích perlu. K pochopení by mohla napomoci souvislost s funkcí open
. Z podobného důvodu totiž kdysi došlo ke vzniku tříparametrové varianty této funkce, kdy se odděluje mód a název souboru. Jak byste například u dvouparametrové varianty četli soubor začínající na >
? U open
je problém ještě zřejmější, protože se tam speciální znaky (narozdíl od jejich výskytu u jmen souborů) běžné používají. Proto ostatně změna u open
nastala již u verze 5.6. Ale zpět k řešení problému u <>
- pomoci by nám zde měla právě tříparametrová funkce open
. Ta v podstatě přesně vystihuje rozdíl mezi <>
a <<>>
. Následující kód s tříparametrovou funkcí open
hezky popisuje změnu <<>>
oproti <>
:
FILE:
for my $file (@ARGV) {
open my $fh, '<', $file || next FILE;
while(my $line = <$fh>){
print $line;
}
}
Jak je to s experimentálními featurami
Je-li nějaká funkcionalita experimentální, pak to jednoduše znamená to, že bychom měli být obezřetní, neboť se její chování může změnit. Experimentální featury podle interních pravidel vydávání musí zůstat nezměněny alespoň 2 roky (nepočítají se samozřejmě změny v dokumentaci, refactoring kódu, znění chybových hlášek atd.). Po této lhůtě lze diskutovat o zrušení příznaku "experimentální".
I když víme, že se chování nezmění (tj. hlavně proto. že používáme starou verzi perlu a v nové již featura experimentální není), musíme to reflektovat v kódu. Jednotlivé featury mají svá jména a před použitím bychom měli zavolat pragmu feature:
Takto ovšem použití dané featury nadále generuje varování. Chceme-li ho umlčet, přidáme ještě tento řádek:
no warnings 'experimental::featura';
Je ovšem na důkladné zvážení, zda se používání jakékoliv experimentální featury vyplatí a nestojí za to počkat si dva roky až bude syntaxe stabilní. Pokud jde daný problém vyřešit jinak a není s tímto řešením jiný problém, pak bychom se pro něj měli rozhodnout, protože takové řešení je čistější.
Příkladem experimentální featury jsou od řady 5.20 signatury v definicích podprogramů místo používání proměnné @_
.
Vytváření aliasů přiřazením do reference
Aliasem myslíme proměnnou, která ukazuje na stejné místo v paměti jako nějaká jiná proměnná.
Aliasing je experimentální featura, takže platí vše z předchozího odstavce. Přibližme si o co v případě aliasingu půjde. Jelikož experimentální featury je třeba zapnout, zadejme
use feature qw(refaliasing);
# no warnings 'experimental::refaliasing';
Je možná následující syntaxe pro vytvoření aliasu proměnné, například:
\%new_hash = \%old_hash;
is(\%new_hash, \%old_hash, "oba hashe ukazují na stejné místo v paměti");
\&new_code = \&old_code;
is(\&new_code, \&old_code, "oba podprogramy jsou též aliasy");
Díky této vlastnosti je možné při procházení složitější datové struktury získat přímo pole místo pouhého odkazu na něj. Konkrétně tedy místo
for my $hashref (@list_of_hashes) {
process(%$hashref);
}
můžeme napsat o něco expresivnější
for \my %hash (@list_of_hashes) {
process(%hash);
}
Detailnější možnosti jsou v dokumentu perldelta.
Unicode
Nový perl přichází s podporou aktuální verze Unicode 7.0.
Regulární výrazy
Asi nejzajímavější nová věc je, že máme k dispozici rozšířenou syntaxi pro boundaries. \b
standardně znamená kotvu pro hranici slova. Je trochu ošemetné mít v jazyce něco závislého na slově, protože sama definice slova je velmi nejasná a napříč jazyky se může diametrálně lišit. Totéž platí o větách, jejichž koncept navíc v mluveném jazyce zcela ztrácí smysl. Přesto jsou boundaries pro jednoduché tokenizátory poměrně dobře funkční. Lingvistům nyní udělají velkou radost následující nové kotvy:
-
\b{sb}
- hranice věty
-
\b{wb}
- hranice slova - funguje skoro jako staré \b
, ale reflektuje něco více z přirozeného jazyka. Například ví, že apostrof se může vyskytnout i uvnitř slova (výhodnost záleží na konkrétním použití)
-
\b{gcb}
- matchuje hranice znaku tak, jak ho vidí člověk (ve skutečnosti může zápis několika symbolů tvořit jen jeden grafém - některé znaky například pouze přidávají nějaký symbol k jinému znaku; například ze dvou znaků P\x{307}
vznikne P s tečkou) - více na perldoc perlbackslash
Rozdíly si můžeme krátce demonstrovat. Představme si, že máme následující tokenizery:
my $tokenizers = {
b => qr{(?:\b)}xms,
sb => qr{(?:\b{sb})}xms,
wb => qr{(?:\b{wb})}xms,
gcb => qr{(?:\b{gcb})}xms,
};
Budeme chtít zobrazit, kde jsou boundaries v nějakém textu:
my $text = "Aaaa a aaaa aaaaa aa. B. Cc'c ccc'ccc c\"c. D\x{307}d\x{307}.";
for my $boundary_type (keys %$tokenizers) {
my $text_copy = $text;
$text_copy =~ s{$tokenizers->{$boundary_type}}{|}xmsg;
print "$boundary_type: $text_copy\n";
}
Z výsledku je pěkně vidět, jak jednotlivé boundaries fungují:
b: |Aaaa| |a| |aaaa| |aaaaa| |aa|. |B|. |Cc|'|c| |ccc|'|ccc| |c|"|c|. |Ḋḋ|.
wb: |Aaaa| |a| |aaaa| |aaaaa| |aa|.| |B|.| |Cc'c| |ccc'ccc| |c|"|c|.| |Ḋḋ|.|
sb: |Aaaa a aaaa aaaaa aa. |B. |Cc'c ccc'ccc c"c. |Ḋḋ.|
gcb: |A|a|a|a| |a| |a|a|a|a| |a|a|a|a|a| |a|a|.| |B|.| |C|c|'|c| |c|c|c|'|c|c|c| |c|"|c|.| |Ḋ|ḋ|.|
Už jen stručně další změny v regulárních výrazech:
- Modifikátor regulárního výrazu
/n
pro potlačení extrakce pomocí závorek
- Striktní režim
use re 'strict'
upozorní na potenciální chyby
- Whitespace znaky pro modifikátor
/x
je úplnější, nyní zahrnuje další typy mezer
\c
funguje pouze pro tisknutelné znaky
- Modifikátor
/x
lze uvést pouze jednou
Mazání deprecated featur
Jedním z hlavních důvodů, proč by se nové featury měly přidávat do jazyka jen velmi opatrně po dlouhé diskuzi je nutnost zpětné kompatibility, na kterou se v perlu velmi striktně dbá. Jakmile se totiž do široce používaného jazyka zavede funkcionalita, která není žádoucí (např. z důvodu matoucí interpretace, narušení jiných a třeba i budoucích a zatím neplánovaných featur), je to obrovský problém, protože cesta zpátky je téměř nemožná. Čištění jazyka nicméně v omezené míře probíhá, i když nějaké zásadní změny se z výše uvedeného důvodu dít nemohou. (Od toho bude perl 6.)
Podle Richarda Signese bude v jazyce každá funkcionalita označená jako deprecated minimálně další dva roky (výjimečně i pouze rok, ale to se ještě nestalo) a bude generovat varování. Potom může (a taky nemusí) dojít jejímu odstranění. Několik deprecated syntaktických konstrukcí (některé byly deprecated i 20 let) bylo nyní odstraněno:
Obecně lze říci, že cokoliv deprecated nemá vůbec žádný smysl používat, protože to může být v budoucnu odstraněno. Navíc je stejně velmi pravděpodobné, že takováto featura bude v silném rozporu s Perl Best Practices, jejichž striktní používání je v moderním perlu naprosto nezbytné.
Odstraněná funkcionalita
Podívejme se jen pro zajímavost a ilustraci, co v perlu vlastně bylo, na několik featur, které jsou nově odstraněny. Všimněme si mimochodem, jak dramaticky všechny následující kostrukce snižovaly čitelnost kódu.
?regex?
jakožto regulární výraz pro jednorázové porovnání nebude fungovat. Pokud přidáme operátor m
, tj. m?regex?
tak bude validní nadále - to však nemění nic na tom, že používat takto nekonvenční zápis by se vůbec nemělo. Doporučená základní syntaxe pro jednorázové porovnávání resp. nahrazování regulárních výrazů je m{regex}xms
resp. s{regex}{string}xms
, případně ještě m/regex/xms
resp. s/regex/string/xms
.
- Používání
%hash->{$key}
místo $hash{$key}
již není možné, objeví se chybová hláška Can't use a hash as a reference"
- Totéž platí analogicky pro používání
@list->[$index]
místo $list[$index]
.
- (Naštěstí) asi málokdo věděl, že syntakticky korektní bylo použití některých operátorů s proměnnými bez sigil znaku. Korektními výrazy tak byl například velmi obskurní zápis:
my @list = (1, 2);
push list, 3, 4;
nebo
my %hash = (a => 1);
@keys = keys hash;
- Není možné nadále používat již dlouho deprecated konstrukce
defined(@list)
a defined(%hash)
. Nyní se objeví chybová hláška s návrhem Maybe you should just omit the defined()?
. V případě testování na prázdnost pole stačí defined
vynechat a u hashů ještě přidat keys
.
Změny specifické pro platformy
Verze pro Windows podporuje konstrukce s rourou u tříparametrové funkce open
, což doposud možné nebylo:
open my $fh, '-|', @list;
open my $fh, '|-', @list;
Změny v modulech
Odstraněn z core modulů byl kdysi nepostradatelný modul CGI. V době MVC a jiných frameworků a šablonovacích systémů již není třeba. Dále byl odstraněn modul Module::Build z důvodu nepohodlných závislostí (automake
).
Všechny bývalé core moduly jsou samozřejmě nadále na CPANu.
Další změny stručně
- Máme nové bitové operátory pro řetězce:
&.
, |.
, ^.
, ~.
. To proto, že perl místo typování rozlišuje často typy operandů pomocí operátorů. Staré bitové operátory vyžadují čísla. Takové chování bude konzistentnější s ostatními operátory.
- Funkce
close
nastaví chybový kód do proměnné $!
.
- Nelze nadále importovat konkrétní metody z třídy
UNIVERSAL
pomocí use
.
- Uvnitř
my()
lze zadávat repetitive operátor, použití by mohlo vypadat například takto: my((undef) x 5, $year) = localtime(time());
.
- Podpora Hexadecimal floating-point constants, tj. zápis tvaru
0x1.23p-4
(převody lze vyzkoušet pomocí printf("%a", $number)
)
- Různé změny v prototypech
- Řada bugfixů a optimalizací (nejvýznamnější je asi zrychlení lookupu pro jednoduché indexy u polí a hashů a zrychlení volání metody, je-li název znám)
Další zdroje informací
- Perl 5.22.0 na CPANu
- Kompletní seznam změn je v dokumentaci perldelta
- přednáška Richarda Signese o perlu 5.22.0 na konferenci FOSDEM (bohužel na letošním FOSDEMu byla řada technických problémů a postihlo to i tuto přednášku: po 5 minutách vypadl zvuk a jsou pouze slajdy; jiný záznam pravděpodobně neexistuje)
- Rozhovor s Ricardem Signesem z února 2015 o nových featurách, kompatibilitě, experimentálních featurách, signaturách, perlu 6, verzování, jak přispívat atd. na rebuild.fm
- Ještě jedna přednáška s Ricardem Signesem o perlu 5.22 se chystá na YAPC::NA; měla by se uskutečnit 10.6.2015 a bude streamovaná online
- Pro zájemce o hlubší informace o novinkách v perlu je zde archiv konference perl5.porters
Článek je vydán bez honoráře.