Release: 0.35 - Lispward
0.35.0 - Lispward
Released 2026-05-03 · GitHub release
PHP 8.4 + dot-namespace canonical form + namespace introspection APIs + many nil/seq fixes + AI tooling helpers.
🎉 Added
Compiler
- Resolve dot-separated PHP class names and root-class aliases (#1553)
- Optional warning for deprecated backslash namespace separators (#1567)
- Dot-separated names in stdlib namespaces and
:useclauses (#1567, #1576) \uNNNNUnicode escapes in string literals (#1679)
Core
- List matchers in
case(#1615) - Optional hierarchy argument on hierarchy functions (#1543)
into-arrayfor.cljcinterop (#1550)- Consistent numeric comparison in
==(#1561) [size init-val-or-seq]in primitive array helpers (#1562)- Namespace introspection:
loaded-namespaces,find-ns,create-ns,remove-ns,intern,ns-interns,ns-publics,ns-aliases,ns-refers,load-file(#1694) var-getresolves a symbol to its registry value (#1774)(rand n)returns a number in[0, n)(#1696)canonical-nsreturns the canonical (dot) form of a namespace string (#1795, #1798)display-nsreturns the display (dot) form of a namespace string (#1795)
REPL
requireaccepts vector syntax:(require '[phel\string :as s])(#1693)
AI
with-configmacro for scoped, auto-restoring configuration overridesrun-toolshelper that drives a tool-calling loop end-to-end (Anthropic)
⚖️ Changed
- BREAKING: Require PHP 8.4
- BREAKING: Async functions move to
phel\core;delaystays inphel\async(#1548) - BREAKING: Canonical namespace form is dot: registry keys,
*ns*andSymbol::getFullNamefor Phel symbols. PHPnamespace ...;and class FQNs stay backslash. Backslash input is still accepted (warns underPHEL_WARN_DEPRECATIONS=1) (#1798)
Core
Lang
(str sym)and printer output for qualified symbols include the namespace- User-facing namespace APIs return strings in dot-separated display form:
loaded-namespaces,find-ns,create-ns,intern,ns-aliases,ns-refers,get-symbol-info,apropos,find-fn, REPL prompt,phel ns(#1795)
API
PhelFunction.githubUrlanchors to the latest release tag instead ofmain, so doc links remain valid across releases
🐛 Fixed
Core
atomaccepts:metaand:validatoroptions (#1785)min-key/max-keyreturn the latest argument on a tie (#1787)conj/conj!ignorenilmap entries;conjprepends to lazy seqs (#1650, #1683)reversible?andrseqhandle sorted sets (#1681)/preserves##Inf,##-Inf,##NaNon division by zero (#1658)nilhandling innth,rand-nth,take-last,rest,contains?,nthrest,butlast,get-in,dissoc(#1592, #1638, #1640, #1644, #1652, #1655, #1656, #1699, #1712, #1713, #1738)nthrestover a nil collection returns nil only whennis 0; otherwise an empty list (#1778)get-intraverses into strings by integer indexparents,ancestors,descendantsfind derive entries when the tag is a struct/record constructor functionparents/ancestorsof a record/type extended with a protocol include the protocol value (#1791, #1792)descendantsof a protocol returns nil for records/types extended viadefrecord/deftype(#1793)takerealizes exactlynelements from a lazy source- Namespace-string APIs (
find-ns,create-ns,remove-ns,ns-interns,ns-publics,ns-aliases,ns-refers,intern,dir,get-symbol-info) and CLI commands (phel run,phel ns) accept dot and backslash separators interchangeably (#1795) seq?recognizes lists andseq/rseqover vectors, sorted-maps, sorted-sets (#1700)special-symbol?recognizes&,catch,finally(#1701)bindingrebinds dynamic vars tonil(#1702)min/max/min-key/max-keypropagate##NaN;min/maxreturn a single non-numeric arg unchanged (#1703, #1730, #1740)dissocrejects non-map/set/struct targets withInvalidArgumentException(#1704)sort,sort-by,sorted-map-by,sorted-set-byaccept predicate comparators like</>;sort-byaccepts comparator before collection;sorthandles maps and nested vectors (#1610, #1611, #1613, #1657, #1705, #1737)- Sets compare equal regardless of underlying ordering (#1708)
emptyreturns()for lazy seqs and preserves source metadata (#1710, #1711)some-fnreturnsfalsewhen no predicate matches (#1714)compareorders namespaced keywords and symbols by namespace first (#1715)vector?reportsfalseforseqandrseqresults (#1716)list?reportsfalseforseqandrseqresults over vectors, sorted-maps, sorted-sets (#1759)keywordpreserves empty-string namespace; prints as:/hi(#1775)lastreturns the final element of ranges and lists (#1776)get-inreturns the collection for nil/empty path; default applies only on missing keys (#1777)- Keyword and symbol literals preserve
',",\through compilation (#1718) interleave,cycle,interposeover maps yield[key value]pairs;interleavestops at shortest input (#1726, #1734, #1757)odd?reports negative odd numbers as odd (#1736)symbolaccepts keywords and symbols (#1750)parse-booleanmatches only exact"true"/"false"(case-sensitive, no trim) (#1753)peekreturns head of lists/lazy seqs, last of vectors and PHP arrays (#1761)- Set support in
first,ffirst,second,next,nfirst,fnext,nnext,some(#1639, #1642, #1649) - Edge cases in
seq,cons,pop,nth,take-last,take-nth(#1598, #1599, #1600, #1641, #1643, #1645) - Map and seq behavior in
apply,merge,dissoc,find,mapcat(#1602, #1603, #1606, #1607, #1646, #1651, #1653) assoc!handlesapplytrailing keys withnilvalues (#1609)- Dynamic bindings are fiber-local and propagate through
futureandasync(#1536) - Hierarchy lookups handle invalid arguments, inline protocols, PHP parents and interfaces for class-string tags (#1560, #1591, #1597)
- Sequential equality is symmetric across lists, vectors, lazy seqs (#1546)
()is self-quoting (#1549)- Bare
applyresolves as a first-class function (#1564) evalreturns already-evaluated PHP objects unchanged (#1563)- Symbols are callable like keywords;
(ifn? 'a)istrue(#1697) - Promises implement IFn:
(p val)delivers,(p)derefs (#1698)
String
blank?excludes non-breaking separatorsU+00A0,U+2007,U+202Ffrom whitespace
Build
- Skip unparseable
.phelfiles during directory scans
API
phel analyzepreloadsphel\coreso core macros resolve (#1539)
AI
- API key error names the right env var per provider (
OPENAI_API_KEY,VOYAGE_API_KEY,ANTHROPIC_API_KEY) - Per-call opts honour explicit falsy values (
:max-tokens 0no longer ignored) - JSON-extraction errors truncate the model response so logs don't echo full prompts
- Default chat model is
claude-sonnet-4-5(alias) instead of a dated id
Test
run-testsresets assertion counts per run (#1604)- Default reporter prints string literals readably in failures (#1601)
phel test --stack-traceopts into the full PHP stack trace; default omits it (#1695)phel testseedsphel.testin canonical dot form soclojure.test :as taliases remap correctly in.cljcsources (#1807)phel testseeds every bundledphel.*module so fully qualified references likephel.async/delay,phel.html/escape-html,phel.json/encodecompile in test files without an explicit(:require ...)(#1805)
REPL
- Bare namespace symbols in
dir(#1588) - Preserve current namespace across autocompletion and nREPL
completions/lookup(#1692) - Every bundled
phel.*module (phel.async,phel.html,phel.json, ...) resolves via fully qualified name without explicit(:require ...)from REPL andphel eval(#1805)
Compiler
- Resolve PHP class aliases consistently regardless of case (#1567)
- Reject unknown PHP symbols in
useimports (#1688) - Imported PHP classes usable as class-string values (#1560)
- Lowercase root PHP classes resolve in constructor positions (#1567)
php/newreports invalid target types clearly (#1538)- Reader conditionals allow newline before closing paren (#1547)
(Name. args)invokes the Phel constructor fordefstruct/defrecord/deftype(#1607)
Lint
- Alias-qualified required calls no longer flagged as unresolved (#1540)
- Vendored stdlib files skipped when linting with no arguments (#1541)
Docs
docs/internals/: architecture, special forms, macros, runtime, FAQ; expanded compiler pipeline
👥 Contributors
@Chemaclass @CosmeValera @jasalt @JesusValeraDev @SauronBot
Full Changelog: v0.34.1...v0.35.0
Downloads
v0.35.0
- phel.phar (2.57 MB)