# pperl 0.6.24 *2026-10-15 to 2026-10-25, 457 commits.* ## JIT and parallelization - **Loops over arrays sized with $#a stay compiled**: a loop that stores into an array whose size was set with `$#a = $n`, directly or through a reference, now runs as compiled code. It used to fall back to the interpreter on every element until the JIT gave the loop up, and ran about three times slower than the same loop over an array filled with values first. - **& | ^ under use v5.28 and later are compiled**: with the `bitwise` feature, which `use v5.28` and later versions turn on, the numeric `&`, `|` and `^` are separate operations, and a loop holding one of them ran in the interpreter. Such loops are now compiled, signed under `use integer` and unsigned otherwise, as perl computes them. - **Index arithmetic no longer decides how a statement computes**: in `$y[$n] = $C[$i] + $C[$i + 64]` over an array of floating-point numbers, the integer `$i + 64` made the compiled loop treat the whole statement as integer arithmetic, and every element fell back to the interpreter until the loop was given up. Arithmetic that only computes an array index is now plain integer arithmetic, its overflow checked, whatever the elements hold. Loops of this kind that ran about four times slower when every value they computed was 0.0, such as a reverb fed silence, now run as fast as on any other input. - **Float arithmetic survives a run of zeros**: a loop that computes with arrays of floating-point numbers, such as an audio filter fed silence, kept falling back to the interpreter while every value it saw was zero, and was then replaced by a slower form that also ran the signal after the silence. An array of floats that also holds a value perl keeps as an integer too is now recognised as an array of floats. - **A copied array element keeps its spelling**: in compiled code, copying an array element that holds a number written as a string, such as `my $x = $list->[$i]` of "-2.0", "0.10" or "1e1" after it had been compared numerically, gave the number instead: "-2", "0.1", "10". The copy is now the string, as in perl. Complete::Sah's completions of floating-point values were affected. - **A [`next`](../p5/core/perlfunc/next) out of a branch that was cold no longer crashes**: a loop nest compiled while an `if` branch holding its own loop and a `next` had never run, as in `if ($four) { while (...) { ... } next }`, could crash pperl once that branch ran, when the enclosing sub returned. It runs as under perl now. - **A loop that increments the position it reads no longer crashes**: a loop such as `for (my $k = 0; $k < length $s; $k++) { $n += ord substr($s, $k, 1) }` aborted pperl once it ran often enough to be compiled. Such loops now run compiled. - **Negative array indexes stay compiled**: `$a[-1]`, or an index such as `$n - 100` that goes below zero, counts from the end of the array in compiled code. In a loop over an array of plain numbers, each such access used to fall back to the interpreter, and a loop doing it often was given up. - **Loops over unsigned 64-bit integers stay compiled**: a loop whose numbers go past 9223372036854775807, perl's unsigned integers as in 64-bit hashes, masks and random numbers, or a C function returning `uint64`, fell back to the interpreter on every trip until the JIT gave the loop up, and one naming such a number as a constant, such as `0x9E3779B97F4A7C15`, was never compiled. Such loops now run compiled with perl's exact values, under `use integer` too; a result perl computes as a floating-point number still takes the interpreter's path. A loop that only reads a large integer, such as an argument of -9223372036854775808, no longer leaves the compiled code each time it starts either. ## Language and runtime - **END blocks run after an exit during compilation**: when a program exits or dies while it is still being compiled, in a `BEGIN` block or in the import a [`-MModule=...`](../cli_options) switch calls, the `END` blocks compiled so far now run and can set the exit status, as in perl. A failing test file that exited this way reported success, which broke the test suite of Test::Needs and every CPAN distribution that needs it. An `END` block that sets `$?` to 0 after `exit 5` now makes the exit status 0. - **Arguments that are not UTF-8**: an argument that is not valid UTF-8, such as a file name in Latin-1, made pperl stop with an internal error before running anything. Arguments, [`-e`](../cli_options) code, script names and `-I` directories now reach the program byte for byte, as in perl. And `pperl -e CODE a -x` hands its program `a` and `-x` instead of rejecting `-x` as an unknown option. - **A regex match creates no variable**: a pattern match no longer creates `${^RE_DEBUG_FLAGS}` in `main::`, and no longer looks that variable up on every match. Code that walks the main symbol table while matching names, such as Devel::Symdump, saw it appear under its iterator and warned "Use of each() on hash after insertion". - **The built-in library is a directory on disk**: the modules built into pperl are a real directory now, `$Config{privlibexp}` under `~/.cache/pperl`, which `@INC`, `%INC` and [`__FILE__`](../p5/core/perlfunc/__FILE__) name. It is written the first time a program looks at it - a file test, [`opendir`](../p5/core/perlfunc/opendir), [`chdir`](../p5/core/perlfunc/chdir), [`glob`](../p5/core/perlfunc/glob), `abs_path` or reading a module as a file - never at startup, and holds the modules as perl installs them, documentation included, with perl's `pod/` files and `Config.pod`. Tools that search `@INC` as a filesystem, such as Pod::Find, Module::Path and Module::List, find pperl's own modules now. - **@INC hooks see built-in modules**: a code reference at the front of `@INC`, as Test::Without::Module and `use lib sub {...}` put it there, is asked for a built-in module before pperl's own copy is used, as in perl. Such a hook can hide a built-in module or serve its own version of it. A directory in `@INC` still never replaces a built-in module. - **Modules fall back to Perl when their compiled part is missing**: a module whose compiled part pperl does not have now fails to load with perl's message for that case, "Can't locate loadable object for module ... in @INC", instead of "dynamic loading not available". Modules that try their compiled part and go on in Perl without it look for exactly that message, so DateTime and others now run in their Perl implementation where they died before. - **A built-in module's file runs however it is reached**: when a built-in module's file reaches perl without a plain [`require`](../p5/core/perlfunc/require) - served by an `@INC` hook such as lib::filter's or a FatPacker one, read with `do FILE`, or checked with `perl -c` - its compiled part now loads, as perl finds the module's shared object. Such a file used to die "Can't locate loadable object", which took Moo down with lib::filter. - **Installed scripts run with pperl**: `$Config{perlpath}` and `$Config{startperl}` name the pperl binary that is running. They named `/usr/bin/perl`, so the commands a distribution installs with `pperl --cpan` started the system's perl, or failed on a machine without one. - **pperl starts faster**: a short script runs in about a quarter less time, as the binary has less than half the addresses to fix up when it is loaded and a run no longer reads the CPU topology unless it goes parallel. The binary is also 5.5 MB smaller. A panic inside pperl itself, which is always a bug, no longer names a source file and line. - **Catching errors from built-in modules no longer leaks memory**: a built-in module that died with an error built at run time left a few hundred bytes behind every time, so a program catching such errors in a loop with [`eval`](../p5/core/perlfunc/eval) grew without bound. [Peta::FFI](../p5/Peta/FFI), [Storable](../p5/Storable), [Opcode](../p5/Opcode), [POSIX](../p5/POSIX) and the other built-in modules now free everything before they die, and `opset` with an unknown name no longer leaks the set it was building, as it does under perl. The error messages are unchanged. ## Modules - **[DBI](../p5/DBI) 1.655**: the built-in DBI is 1.655, up from 1.651. [`DBD::DBM`](../p5/DBD/DBM) accepts only a module name as `dbm_type` and `dbm_mldbm`, so a file path given there is no longer loaded and run, and [`DBD::File`](../p5/DBD/File) no longer reads a table linked into a directory whose name merely begins with that of `f_dir`. These are the fixes for CVE-2026-78030 and CVE-2026-15392. - **DBI: sql_type_cast and fetchrow_hashref as in [DBI](../p5/DBI) under perl**: `DBI::sql_type_cast` returns what DBI's compiled version returns, so `SQL_INTEGER` refuses "3.14", "1e3" and "inf", `DBIstcf_DISCARD_STRING` leaves only the number, and the two flags have DBI's values. A plain number with `SQL_INTEGER` and `DBIstcf_DISCARD_STRING` is handled too, where DBI 1.655 aborts perl. `fetchrow_hashref` with a key name that holds no column list, from `FetchHashKeyName` or its argument, sets the handle's error and returns undef instead of dying whatever `RaiseError` says, and a number as that name is taken as a name. - **PDL: update_data_from reads the value of a tied source**: `$pdl->update_data_from($bytes)` fetches a tied or otherwise magical `$bytes` and copies its current value, as [PDL](../p5/PDL) does under perl. It used to copy whatever that scalar last held. - **[PDL](../p5/PDL): the operator overloads are PDL's own subs**: `PDL::overload_plus` and the other handlers PDL installs for its operators exist under their names and are what `overload::Method` returns, as with PDL under perl. An error raised through an operator, such as a broadcast mismatch in `$a + $b`, now names PDL's own line and the handler in its backtrace, and so does a warning such as "isn't numeric" for a string operand. A redefined `PDL::plus`, or a subclass's own `inplace`, is now what the operators use. - **PDL::FFT loads quietly under -w**: `use PDL::FFT` under `-w` no longer warns "Subroutine PDL::realfft redefined", as it doesn't with [PDL](../p5/PDL) under perl. - **[Pod::Text](../p5/Pod/Text) and [Pod::Man](../p5/Pod/Man) 6.1.1**: the POD formatters are those of podlators 6.1.1, up from the 6.0.2 that perl 5.44.0 ships. Formatting a document whose `=over` nesting brings the margin to the output width no longer loops forever while the output fills memory (CVE-2026-82560). `Pod::Man` lists with tags now use `.TP` and the fixed-width font is `CR`, for groff 1.24. - **[Text::LineFold](../p5/Text/LineFold) no longer repeats its input**: `fold` on text holding form feeds, vertical tabs or other special breaks returned the whole text once for every piece between them, so the output grew with the square of the input (CVE-2026-8594). Each piece is folded once now; the Text::LineFold of CPAN still has the fault. - **[Hash::Util::FieldHash](../p5/Hash/Util/FieldHash) is built in**: perl's field hashes for inside-out classes, whose entries vanish with the object they are keyed by, together with `id`, `id_2obj`, `register` and idhashes. It was the one module of perl's own library that would not load, and `B::Hooks::EndOfScope`, `namespace::clean`, `namespace::autoclean` and Mojolicious, which need it, now install from CPAN and pass their tests. - **Five more CPAN modules with compiled parts are built in**: [`XString`](../p5/XString) 0.005, [`Test::LeakTrace`](../p5/Test/LeakTrace) 0.17, [`PerlIO::utf8_strict`](../p5/PerlIO/utf8_strict) 0.010, [`Scalar::Util::Numeric`](../p5/Scalar/Util/Numeric) 0.40 and [`Sub::Identify`](../p5/Sub/Identify) 0.14. Each passes its own test suite with the results it has under perl. Distributions that need one of them, such as DateTime, Specio, PPI and Template Toolkit, get past it when they are installed from CPAN. - **[Sub::Name](../p5/Sub/Name) is built in**: `Sub::Name` 0.28, which renames a sub for [`caller`](../p5/core/perlfunc/caller) and stack traces, passes its own tests as under perl. It runs the code of [`Sub::Util::set_subname`](../p5/Sub/Util/set_subname), which perl ships and which was taken from it, so renaming a sub under the debugger no longer leaks a reference to its `%DB::sub` entry with every call, as `Sub::Name` does under perl. - **[B::COW](../p5/B/COW) is built in**: `B::COW` 0.007 reports whether a string shares its buffer copy-on-write and the share count, with the same answers as under perl, and passes its own tests. - **[Digest::SHA1](../p5/Digest/SHA1) is built in**: `Digest::SHA1` 2.13, the SHA-1 module older code uses where newer code uses [`Digest::SHA`](../p5/Digest/SHA), passes its own tests with the results it has under perl. Its digests are computed by the built-in `Digest::SHA`, with the processor's SHA instructions where it has them. `sha1_transform` given more than 64 bytes uses the first 64, where perl aborts. - **[String::CRC32](../p5/String/CRC32) is built in**: `String::CRC32` 2.100 computes the CRC-32 of a string or of what a filehandle reads, with the results it has under perl, and passes its own tests. The CRC is computed by the zlib of the built-in [`Compress::Raw::Zlib`](../p5/Compress/Raw/Zlib). A filehandle whose read fails, such as a closed one, gives the CRC of no data, where perl crashes. - **[Crypt::OpenSSL::Random](../p5/Crypt/OpenSSL/Random) is built in**: `Crypt::OpenSSL::Random` 0.17 draws bytes from OpenSSL's random-number generator and seeds it, in the builds that include [Net::SSLeay](../p5/Net/SSLeay), and passes its own tests. It reaches libcrypto through Net::SSLeay, so both draw from one generator. Asking for 0 bytes returns the empty string, where perl returns stray memory; a negative count returns false, and 0 from Net::SSLeay's `RAND_bytes`, where perl exits. - **[URL::Encode](../p5/URL/Encode) is built in**: `URL::Encode` 0.03 and its fast half [`URL::Encode::XS`](../p5/URL/Encode/XS) encode and decode URL-encoded strings and split query strings into their parameters, with the results they have under perl, and pass their own tests. The fast half is used, as under perl when it is installed, and is about 17 times as fast as the pure-Perl one. - **[Text::LevenshteinXS](../p5/Text/LevenshteinXS) is built in**: `Text::LevenshteinXS` 0.03 computes the edit distance of two strings, with the results it has under perl, and passes its own tests. Long strings work: perl needs memory for a table of both lengths multiplied, and crashes when that memory is not there (two strings of 20000 bytes need 1.6 GB). - **[Math::Random::MT](../p5/Math/Random/MT) is built in**: `Math::Random::MT` 1.17, the Mersenne Twister random-number generator, gives the same sequences as under perl for the same seeds, and passes its own tests. - **[Data::UUID](../p5/Data/UUID) is built in**: `Data::UUID` 1.227 makes time-based and name-based UUIDs and converts them, passing its own tests with the results it has under perl. Its name-based UUIDs are computed by the built-in [`Digest::MD5`](../p5/Digest/MD5). Where perl reads or writes past a string - a binary UUID shorter than 16 bytes, a Base64 UUID that is too short, too long or has bytes above 0x7F, a hex UUID that ends inside a byte - the result is zero-filled, cut to 16 bytes, or an error instead. - **[Params::Util](../p5/Params/Util) is built in**: `Params::Util` 1.102, whose checks such as `_STRING`, `_HASH` and `_INSTANCE` many CPAN modules validate their arguments with, passes its own tests with the results it has under perl. It did not load at all before, so PPI, Package::DeprecationManager, Config::MVP and the modules that need them could not be installed from CPAN. - **[Class::Load::XS](../p5/Class/Load/XS) is built in**: the compiled `is_class_loaded` of `Class::Load::XS` 0.10, which Class::Load uses when it is there, passes its own tests with the results it has under perl. Class::Load itself, which loads it, is installed from CPAN as before. - **[Template::Stash::XS](../p5/Template/Stash/XS) is built in**: the compiled stash of Template Toolkit 3.106, which the Template Toolkit uses by default, passes the Template Toolkit's own tests with the results they have under perl. The Template Toolkit itself, which did not install without it, now installs from CPAN with `pperl --cpan`. A method that dies "Can't locate object method" no longer overwrites the caller's arguments, and `set` on a value that is not a reference dies with an error where perl crashes. - **[Package::Stash::XS](../p5/Package/Stash/XS) is built in**: `Package::Stash::XS` 0.32, the compiled implementation of `Package::Stash` that [Moose](../p5/Moose), namespace::clean and many others read and change symbol tables through, passes its own tests with the results it has under perl. `Package::Stash` itself comes from CPAN and now uses it, as it does under perl, instead of its pure-Perl implementation. - **[List::MoreUtils::XS](../p5/List/MoreUtils/XS) is built in**: the compiled backend of `List::MoreUtils` 0.430 passes its own tests and those of the front end with the results they have under perl, and `List::MoreUtils`, installed from CPAN, now uses it instead of its pure-Perl implementation. Where perl crashes or answers wrongly, pperl does not: a block that is a compiled sub, arrays with holes, objects overloading `@{}` over a hash, and `<=>` overloading that gives no number. `reduce_u`, `reduce_0` and `reduce_1` no longer overwrite the caller's `$_`, and `frequency` no longer leaks. - **[Term::ReadKey](../p5/Term/ReadKey) is built in**: `Term::ReadKey` 2.38 sets terminal modes, reads keys with a timeout or without blocking, and reports the terminal's size, speed and control characters as it does under perl; modules that need it, such as `CPAN::Uploader`, now install from CPAN. Where perl aborts, pperl does not: a timed read on a closed handle or on a descriptor of 1024 or above, and `SetTerminalSize` with a width or height ten characters long. `GetSpeed` of a handle that is not a terminal returns 0 for both speeds where perl returns leftover memory. - **[Filter::Util::Exec](../p5/Filter/Util/Exec), [Filter::tee](../p5/Filter/tee) and [Filter::decrypt](../p5/Filter/decrypt) are built in**: the source filters of Filter 1.65 that run a program through a command ([`Filter::exec`](../p5/Filter/exec), [`Filter::sh`](../p5/Filter/sh), [`Filter::m4`](../p5/Filter/m4)), copy it to a file or decrypt it work as they do under perl and pass the dist's own tests. Where perl crashes, pperl does not: these filters, and `filter_add` of [Filter::Util::Call](../p5/Filter/Util/Call), called while nothing is being compiled. A command that stops reading early, such as `head -n 1` on a long source, no longer kills the program without a word or leaves it empty: what the command wrote is compiled. [`Filter::cpp`](../p5/Filter/cpp) is not available, because pperl's configuration names no C preprocessor. - **[IO::Tty](../p5/IO/Tty) and [IO::Pty](../p5/IO/Pty) are built in**: IO-Tty 1.31 allocates pseudo-terminals, names them, sets their window sizes and defines the terminal constants as it does under perl, and passes the dist's own tests. Where perl crashes or reports a length it read from unrelated memory, pperl does not: `IO::Tty::unpack_winsize` of undef, a number or a reference dies saying the length is 0. - **[Moose](../p5/Moose) loads**: the compiled part of Moose 2.4001 is built in, so Moose's own modules load and pass Moose's own tests with the results they have under perl. `pperl --cpan` installs Moose and what is built on it, Catalyst and Dist::Zilla among them: a distribution's check for a working C compiler ([ExtUtils::HasCompiler](../p5/ExtUtils/HasCompiler)) answers yes when the compiled part it needs is built in. Where perl crashes on a malformed metaclass or method object, pperl dies with an error or leaves it alone. - **[JSON::XS](../p5/JSON/XS) is built in**: JSON-XS 4.04 encodes and decodes JSON, parses it incrementally and calls `TO_JSON`, `FREEZE` and `THAW` as it does under perl, and passes its own tests; [Types::Serialiser](../p5/Types/Serialiser), whose booleans JSON `true` and `false` decode to, is built in with it. Where perl crashes, pperl does not: a method called on something blessed into `JSON::XS` that `new` did not make dies with an error, and `JSON::XS::CLONE` called by hand no longer breaks `new`. - **[YAML::XS](../p5/YAML/XS) and [YAML::PP](../p5/YAML/PP) are built in**: YAML-LibYAML 0.910.0 loads and dumps YAML with the settings, objects and output it has under perl and passes its own tests, over YAML::PP 0.43.0, pperl's YAML engine. YAML is read as the YAML 1.2 specification reads it, so the few documents libyaml reads otherwise, rejects or wrongly accepts follow the specification, and `Dump` escapes U+2028 and U+2029 so that what it writes loads back unchanged. Where perl crashes or refuses, pperl does not: the object interface loading a flow mapping inside a flow sequence, and dumping strings of latin-1 bytes. A document that does not parse dies with YAML::PP's account of the problem: nearly always the same document and line, in other words. - **[FFI::Platypus](../p5/FFI/Platypus) is built in**: FFI-Platypus 2.12 calls C functions with every type it offers, from integers, strings and arrays to records by value, closures and custom types, as it does under perl, and no C compiler is needed to install it. Where perl fails, pperl does not: reading an array member of a record no longer leaks memory, an index past an opaque array member warns instead of reading beyond the record, and a hash reference passed for a pointer no longer crashes. A regex capture or a tied scalar passed as an argument passes its value, where perl passes 0, or no string at all, which crashes `strlen($1)`, and a callback that a library calls from a thread of its own stops the program with a message where perl crashes. - **[FFI::Build](../p5/FFI/Build) is built in**: a CPAN module that ships C code for [FFI::Platypus](../p5/FFI/Platypus) to call, built at install time with FFI::Build, now installs, passes its tests and runs under pperl when a C compiler is on `PATH`, as it does under perl. [Capture::Tiny](../p5/Capture/Tiny), which FFI::Build uses, is built in with it. - **[DynaLoader](../p5/DynaLoader) loads shared libraries**: `dl_load_file`, `dl_find_symbol`, `dl_unload_file`, `dl_findfile` and the rest work on any C library as they do under perl, and [FFI::CheckLib](../p5/FFI/CheckLib), which finds libraries with them, is built in. A module's compiled part is still never loaded from a file: [`XSLoader`](../p5/XSLoader) and `DynaLoader::bootstrap` load only pperl's built-in modules. Unloading a library that failed to load no longer crashes, as it does under perl when FFI::CheckLib meets a linker script such as `libm.so`. - **[XSLoader](../p5/XSLoader) checks the version a module asks for**: `XSLoader::load($module, $VERSION)` dies "... object version ... does not match bootstrap parameter ..." when the built-in compiled part is of another version, as it does under perl, and loads a built-in module's compiled part even when nothing has required the module yet. - **[Peta::FFI](../p5/Peta/FFI) reaches more of any C library**: signatures gain fixed-width integers from `i8` to `u64`, `bool`, variadic functions such as [`ioctl`](../p5/core/perlfunc/ioctl) and `snprintf`, strings the caller must free, and C objects as Perl objects whose destructor runs with their last reference. `function` and `attach` prepare a C function once and call it as a Perl sub, a function pointer can be called by its address, and `errno` reports what a call left behind. A callback that a library calls from a thread of its own now stops the program with a message instead of corrupting it, and [Peta::FFI::EventSource](../p5/Peta/FFI/EventSource) brings such a library's events to Perl through a file descriptor that [AnyEvent](../p5/AnyEvent), [EV](../p5/EV), Mojo::IOLoop or a [`select`](../p5/core/perlfunc/select) loop watches. `scan` finds the libraries in the directories it is given, or in `PETA_FFI_PATH` and the dynamic linker's own, and lists only the files this program can load. - **[Peta::FFI](../p5/Peta/FFI) passes C structs, arrays and long doubles**: `record` declares a C struct as a Perl class with an accessor per member, and a signature passes and returns it by value or by pointer, callbacks included. Signatures gain pointers to numbers and strings for out-parameters, arrays the function reads and changes in place, `long double` and the complex types, and an output buffer that holds what the function wrote. `symbol`, `fetch`, `store` and `variable` read and write a library's global variables and any typed value in memory. [FFI::Platypus](../p5/FFI/Platypus) now runs on the same engine, so whatever it can call, Peta::FFI can. - **[Peta::FFI](../p5/Peta/FFI) reaches C unions**: `union` declares one as `record` declares a struct, with every member at its start, to be passed by pointer and read and written in memory, as `SDL_PollEvent` fills an `SDL_Event`. Passing a union by value is refused, because on some platforms that would call the function wrongly instead of failing. A record member that is itself a record now reads as an object of its class and is set from one. - **[Peta::FFI](../p5/Peta/FFI) takes what C functions hand over**: a handle or a string a function stores through a pointer, as `sqlite3_open` does, becomes the caller's object or string, and arrays of handles, of records and of pointers ended by NULL can be passed. An array the function allocates itself, its length given by the result, by another argument or by a NULL at its end, comes back as a Perl array of objects, strings, records or numbers. Everything is freed with the library's own functions once nothing uses it, so a record taken from such an array still reads its strings for as long as it lives. - **[Peta::FFI](../p5/Peta/FFI) reads arrays C lends and sets strings in records**: an array a function hands out from memory it keeps, as libxkbcommon hands out a keymap's keysyms, is written `&T[r]`, `&T[#k]` or `&T[0]` and is copied without being freed, whether it comes through an argument or, as `&T[#k]` or `&T[0]`, as the result. A record's string member can now be set from Perl: the record keeps its own copy for as long as it lives, [`undef`](../p5/core/perlfunc/undef) passes NULL, and a string C put there is never freed by Perl. When C moves the strings between records, as sorting an array of them does, each string stays alive with the record that now points to it. - **[Peta::FFI](../p5/Peta/FFI) reads byte buffers C allocates**: a buffer a function allocates and hands over through a pointer, with its length in the result or in another argument, is written `*P[r]` or `*P[#k]`. It arrives as one byte string, NULs and all, and is then freed with the library's own function, which is how librados's `rados_mon_command` returns its reply. Bytes a function only lends, `&P[r]` or `&P[#k]`, are copied and never freed, and a callback handed bytes with their length, `&P[#k]`, gets them as a string. - **[Peta::FFI::Pool](../p5/Peta/FFI/Pool) runs C calls that may hang**: a function prepared with [Peta::FFI](../p5/Peta/FFI) runs on one of a pool's threads, with a deadline, so `statfs` on a dead NFS mount no longer needs a child process with a timeout. Each call is reported as an event, through a descriptor any event loop can watch as a [Peta::FFI::EventSource](../p5/Peta/FFI/EventSource): done, with its result and what it wrote back; timed out; or busy, when every thread is taken. A call that returns after its deadline changes nothing. - **[Peta::FFI::Queue](../p5/Peta/FFI/Queue) takes callbacks from a library's own threads**: a closure made with `queue => $queue` may be called on any thread, as librados calls its monitor log and watch callbacks. It copies its arguments into the queue, returns a value given once, and its sub runs later, when Perl's event loop takes the queue's events through a [Peta::FFI::EventSource](../p5/Peta/FFI/EventSource). A queue holds a bounded number of calls and counts those it had to drop. - **Loops that call C functions run compiled**: a loop calling a C function prepared with [Peta::FFI](../p5/Peta/FFI) or [FFI::Platypus](../p5/FFI/Platypus) used to stay out of the JIT entirely. When the function takes and returns plain integers, pointers or floating-point numbers, the compiled loop now calls it directly; other calls, and any call while C holds a Perl callback, still go through the library as before. - **C functions called often cost less**: a C function prepared with [Peta::FFI](../p5/Peta/FFI)'s `function` or `attach`, or attached with [FFI::Platypus](../p5/FFI/Platypus), that takes and returns plain numbers or pointers is compiled into machine code of its own once it has been called a few thousand times. A call of `labs` or `ldexp` outside a compiled loop then takes about 30% less time, with the same results and the same errors as before. A function that is seldom called is never compiled, so declaring a library's functions costs no more than it did. - **Peta::LMDB and Peta::PCRE2 are now Peta::FFI::LMDB and Peta::FFI::PCRE2**: pperl's own modules for C libraries live under [Peta::FFI](../p5/Peta/FFI), beside [Peta::FFI::UUID](../p5/Peta/FFI/UUID). Programs that load [Peta::FFI::LMDB](../p5/Peta/FFI/LMDB) or [Peta::FFI::PCRE2](../p5/Peta/FFI/PCRE2) work as before, with the class names, error class and `$Peta::FFI::LMDB::DBM_WRITE` renamed to match; the old names no longer load. - **[Cairo](../p5/Cairo) survives a libcairo without a function it calls**: when the installed libcairo lacks a function a Cairo method needs, as an older release does, calling the method stopped the whole program. It now dies with a message naming the function, which [`eval`](../p5/core/perlfunc/eval) catches, as the other library modules already did. - **[EV](../p5/EV) and [Coro](../p5/Coro) no longer need a system perl**: the built-in `EV` and `Coro` start with `use common::sense`, which pperl did not carry, so they loaded only where a system perl's copy was on `@INC`, and [`AnyEvent`](../p5/AnyEvent) otherwise fell back to its pure-Perl event loop without a word. `common::sense` 3.75 is built in now, with the warnings and features it sets under perl 5.44. - **[Event](../p5/Event) runs on libev, and EV and Event share signals**: [`Event`](../p5/Event) now waits for descriptors, signals and time through libev, the engine behind [`EV`](../p5/EV), and reports the same readiness and conditions as before; its timers and event queues are its own, as they were. A signal that both modules watch now reaches the watchers of both. Under perl the module that installed its handler last took it, and an EV loop reading signals through a signalfd hid them from Event entirely. - **[XML::Parser](../p5/XML/Parser), [HTML::TokeParser](../p5/HTML/TokeParser) and [PDL::IO::Pic](../p5/PDL/IO/Pic) load without a system perl**: they need [`File::ShareDir`](../p5/File/ShareDir), [`HTML::Tagset`](../p5/HTML/Tagset) and [`File::Which`](../p5/File/Which), which pperl did not carry, and loaded only where a system perl's copy was on `@INC`. Those three are built in now, with [`Class::Inspector`](../p5/Class/Inspector), which `File::ShareDir` needs; [`HTML::LinkExtor`](../p5/HTML/LinkExtor) is fixed with them. - **XML::Parser parses with libxml2**: [`XML::Parser`](../p5/XML/Parser) and [`XML::Parser::Expat`](../p5/XML/Parser/Expat) read documents with libxml2 2.15 or newer, and the expat library is no longer needed. Handlers see what they saw over expat: the same calls with the same arguments, character data split where expat splits it, the same positions and source text from `current_byte`, `recognized_string` and `original_string`, and expat's error messages. A document with `standalone="yes"` has the parameter entities of its internal subset read, as XML requires; expat left them unread and then refused the document. - **[Devel::Cover](../guide/debugging/coverage) measures coverage**: the compiled part of [Devel::Cover](../p5/Devel/Cover) 1.52 is built in, so with the distribution installed by `pperl --cpan Devel::Cover`, `pperl -MDevel::Cover` collects statement, branch, condition and subroutine coverage, and `cover` reports it, with the same counts as perl. Devel::Cover's own test suite passes. While it collects, loops are not compiled, since compiled code would bypass the counting. - **JSON::PP works in compiled code**: [`JSON::PP`](../p5/JSON/PP) encodes and decodes with the same compiled engine as [`JSON::XS`](../p5/JSON/XS), with JSON::PP's own options, results and error messages, about 6 times faster at encoding and 14 times at decoding. CPAN's metadata files and everything else that reads or writes JSON through it gain with it. Where JSON::PP went wrong it no longer does: `decode_prefix` counts characters as documented, what a `FREEZE` method returns is encoded as JSON, the incremental parser keeps Latin-1 text and the rest of its buffer as they are, and bare keys keep their non-ASCII characters. - **[Text::CSV](../p5/Text/CSV) is built in**: Text::CSV 2.06 comes with pperl, and its pure-Perl engine [`Text::CSV_PP`](../p5/Text/CSV_PP) parses, warns and checks its settings as Text::CSV_XS 1.65 does. A CR at the very end of the input after an empty last field is error 2032, as after any other field; a failed `print` returns "" and warns where it was called; a separator, quote or line end longer than 16 bytes is refused. Installing Text::CSV with `pperl --cpan` gets the same engine, and Text::CSV_XS installs over it with all of its own tests passing. ## Command line - **pperl -S finds the program on PATH**: `pperl -S prove` runs the `prove` installed on the search path, as `perl -S` does; pperl rejected the switch. - **A program's arguments are its own**: pperl's switches, such as `--parallel` or [`--no-jit`](../cli_options), are read only before the program, as perl reads its own. After it, they reach the program in `@ARGV`; pperl used to take them out, so `tool.pl --parallel 4 list` saw only `4 list`. - **pperl -v names the build and credits perl**: the first line names what kind of binary it is, its native tier and added features such as `dbi`, `pdl` or `shell`, the second is the copyright, and the text says pperl is "compatible to perl 5.44 by Larry Wall and others". `pperl -V` still lists everything. Tests that read [`-v`](../cli_options) as perl's, such as those of IPC::System::Simple and Expect, pass. - **pperl --cpan no longer asks you to set PPERL5LIB**: pperl finds what it installs into your own tree without it, so the advice that ended every install is gone. - **pperl --cpan --system installs where pperl looks**: a system-wide install now goes to `/usr/local/share/pperl/site_perl`, which every pperl searches, with its scripts and manuals beside it; it used to land in a directory pperl never looked in. It now stops before downloading anything when the account may not write there, and says to run it as root. - **pperl --cpan applies distribution preferences**: a CPAN.pm distroprefs file under `~/.pperl/cpan/prefs` that matches a distribution now takes effect, including its patches, which are looked up beside it. A `.yml` preference used to be read only where the separate YAML distribution happened to be installed, and now uses pperl's built-in [YAML::XS](../p5/YAML/XS). Any patch a preference named stopped the install, because no patch command was configured. - **pperl --cpan installs XS distributions it has a substitute for**: each run first fetches pperl's pure-Perl substitutes for distributions with a compiled part from `https://perl.petamem.com/downloads/cppan`, so a substitute published after your pperl applies to it too. Text::CSV_XS installs and runs on the Perl engine of Text::CSV, true, multidimensional and bareword::filehandles on perl's own features, Scalar::Readonly, Test::Taint, Regexp::Util, next::XS and Socket6 on its built-in modules, and Crypt::SSLeay (Net::SSL) on its OpenSSL binding, where it no longer builds under perl with OpenSSL 3; the few places where their own tests show a difference are marked as known in them. `PPERL_CPPAN_URL` names another address, and set empty it skips the fetch. - **JavaScript::QuickJS runs on QuickJS-NG**: `pperl --cpan` installs JavaScript::QuickJS as a binding over the QuickJS-NG library (`libqjs.so.0`, on Arch Linux the `quickjs-ng` package), used where it is installed; without it the module installs, its tests skip and say why, and it works once the library is there. The distributions that need it, such as Data::Sah and the Perinci family, install with it. Where QuickJS-NG differs from the QuickJS the CPAN distribution bundles, its own behaviour shows: its error messages, and a Date's `getTime` as a floating-point number. - **pperl --cpan downloads over https with curl or wget**: like perl's own first-run setup, it now finds `make`, `tar`, `gzip`, `gpg`, `wget` or `curl` and the other tools CPAN.pm uses on your `PATH`. A pperl built without TLS support therefore fetches from CPAN over https through `wget` or `curl` instead of falling back to plain http, and the XS substitutes come the same way. - **pperl --cpan builds the pure-Perl form of a distribution**: it asks every build for the distribution's Perl-only variant, as `PUREPERL_ONLY=1` and `--pureperl-only` do, so a distribution such as Params::Validate that has a Perl implementation beside its compiled one installs instead of failing for want of a C compiler. A module that does not load without its compiled part is named and kept, not removed: [Params::Util](../p5/Params/Util) switches to its Perl half when its tests ask for it, and those tests now run. - **[Config](../p5/Config) names the C compiler**: `$Config{cc}`, its flags, its preprocessor and `gccversion` describe the C compiler found on `PATH` (cc, gcc or clang), so [FFI::Build](../p5/FFI/Build) compiles the C libraries a distribution bundles and Devel::CheckLib's probes run. `usedl` and `dlsrc` say what perl's say on Linux, as [DynaLoader](../p5/DynaLoader) loads shared libraries. Modules with a compiled part still load only when they are built in, and [ExtUtils::CBuilder](../p5/ExtUtils/CBuilder)'s `have_compiler` still says no. - **@INC includes the architecture directories of PERL5LIB and -I**: as under perl, each entry's `x86_64-linux` subdirectory, and that of each of its version directories, comes ahead of the entry when it exists. An installer puts a distribution's Perl files there whenever the distribution carries anything architecture-dependent, so modules installed into a local::lib by `cpanm -l`, Alien modules among them, are now found. `pperl --cpan` installs into its tree's architecture directory as perl's installers do, and pperl's own tree is searched the same way. - **ipps runs programs as functions**: with the new `autorun` setting on, calling a sub that does not exist runs the program of that name and returns its output, a list of lines in list context, as in `whoami()` or `my @files = ls('*.pl')`. `:programs ls cat` makes such names subs that need no parentheses, whether `autorun` is on or not, and `:programs` alone lists them. A program that cannot be run is an error, and the exit status is in `$?` as for backticks. ## Documentation - **Links in the changelog**: the entries of every version link the modules, built-in functions, command-line options, guides and tutorials they name to their pages, in every language of the documentation.