Skip to main content

Release: 0.35 - Lispward

Latest update

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 :use clauses (#1567, #1576)
  • \uNNNN Unicode escapes in string literals (#1679)

Core

  • List matchers in case (#1615)
  • Optional hierarchy argument on hierarchy functions (#1543)
  • into-array for .cljc interop (#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-get resolves a symbol to its registry value (#1774)
  • (rand n) returns a number in [0, n) (#1696)
  • canonical-ns returns the canonical (dot) form of a namespace string (#1795, #1798)
  • display-ns returns the display (dot) form of a namespace string (#1795)

REPL

  • require accepts vector syntax: (require '[phel\string :as s]) (#1693)

AI

  • with-config macro for scoped, auto-restoring configuration overrides
  • run-tools helper that drives a tool-calling loop end-to-end (Anthropic)

⚖️ Changed

  • BREAKING: Require PHP 8.4
  • BREAKING: Async functions move to phel\core; delay stays in phel\async (#1548)
  • BREAKING: Canonical namespace form is dot: registry keys, *ns* and Symbol::getFullName for Phel symbols. PHP namespace ...; and class FQNs stay backslash. Backslash input is still accepted (warns under PHEL_WARN_DEPRECATIONS=1) (#1798)

Core

  • Expose future from phel\core (#1537)
  • intern without a value preserves the existing root (#1774)

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.githubUrl anchors to the latest release tag instead of main, so doc links remain valid across releases

🐛 Fixed

Core

  • atom accepts :meta and :validator options (#1785)
  • min-key/max-key return the latest argument on a tie (#1787)
  • conj/conj! ignore nil map entries; conj prepends to lazy seqs (#1650, #1683)
  • reversible? and rseq handle sorted sets (#1681)
  • / preserves ##Inf, ##-Inf, ##NaN on division by zero (#1658)
  • nil handling in nth, rand-nth, take-last, rest, contains?, nthrest, butlast, get-in, dissoc (#1592, #1638, #1640, #1644, #1652, #1655, #1656, #1699, #1712, #1713, #1738)
  • nthrest over a nil collection returns nil only when n is 0; otherwise an empty list (#1778)
  • get-in traverses into strings by integer index
  • parents, ancestors, descendants find derive entries when the tag is a struct/record constructor function
  • parents/ancestors of a record/type extended with a protocol include the protocol value (#1791, #1792)
  • descendants of a protocol returns nil for records/types extended via defrecord/deftype (#1793)
  • take realizes exactly n elements 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 and seq/rseq over vectors, sorted-maps, sorted-sets (#1700)
  • special-symbol? recognizes &, catch, finally (#1701)
  • binding rebinds dynamic vars to nil (#1702)
  • min/max/min-key/max-key propagate ##NaN; min/max return a single non-numeric arg unchanged (#1703, #1730, #1740)
  • dissoc rejects non-map/set/struct targets with InvalidArgumentException (#1704)
  • sort, sort-by, sorted-map-by, sorted-set-by accept predicate comparators like </>; sort-by accepts comparator before collection; sort handles maps and nested vectors (#1610, #1611, #1613, #1657, #1705, #1737)
  • Sets compare equal regardless of underlying ordering (#1708)
  • empty returns () for lazy seqs and preserves source metadata (#1710, #1711)
  • some-fn returns false when no predicate matches (#1714)
  • compare orders namespaced keywords and symbols by namespace first (#1715)
  • vector? reports false for seq and rseq results (#1716)
  • list? reports false for seq and rseq results over vectors, sorted-maps, sorted-sets (#1759)
  • keyword preserves empty-string namespace; prints as :/hi (#1775)
  • last returns the final element of ranges and lists (#1776)
  • get-in returns the collection for nil/empty path; default applies only on missing keys (#1777)
  • Keyword and symbol literals preserve ', ", \ through compilation (#1718)
  • interleave, cycle, interpose over maps yield [key value] pairs; interleave stops at shortest input (#1726, #1734, #1757)
  • odd? reports negative odd numbers as odd (#1736)
  • symbol accepts keywords and symbols (#1750)
  • parse-boolean matches only exact "true"/"false" (case-sensitive, no trim) (#1753)
  • peek returns 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! handles apply trailing keys with nil values (#1609)
  • Dynamic bindings are fiber-local and propagate through future and async (#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 apply resolves as a first-class function (#1564)
  • eval returns already-evaluated PHP objects unchanged (#1563)
  • Symbols are callable like keywords; (ifn? 'a) is true (#1697)
  • Promises implement IFn: (p val) delivers, (p) derefs (#1698)

String

  • blank? excludes non-breaking separators U+00A0, U+2007, U+202F from whitespace

Build

  • Skip unparseable .phel files during directory scans

API

  • phel analyze preloads phel\core so 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 0 no 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-tests resets assertion counts per run (#1604)
  • Default reporter prints string literals readably in failures (#1601)
  • phel test --stack-trace opts into the full PHP stack trace; default omits it (#1695)
  • phel test seeds phel.test in canonical dot form so clojure.test :as t aliases remap correctly in .cljc sources (#1807)
  • phel test seeds every bundled phel.* module so fully qualified references like phel.async/delay, phel.html/escape-html, phel.json/encode compile 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 and phel eval (#1805)

Compiler

  • Resolve PHP class aliases consistently regardless of case (#1567)
  • Reject unknown PHP symbols in use imports (#1688)
  • Imported PHP classes usable as class-string values (#1560)
  • Lowercase root PHP classes resolve in constructor positions (#1567)
  • php/new reports invalid target types clearly (#1538)
  • Reader conditionals allow newline before closing paren (#1547)
  • (Name. args) invokes the Phel constructor for defstruct/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


View release on GitHub