1.14.0
June 3, 2026
BoxLang 1.14.0 is an innovative release that pushes the language forward with first-class dynamic sets, ranges, inner classes, template classes, class references as callable constructors, deep query transformation, JSONPath capabilities and much more. This release closes 65 issues spanning new features, developer experience enhancements, formatter maturity, CFML compatibility parity, and extensive runtime hardening.
This release introduces the Dynamic Set type — a new first-class collection with literal syntax, operator overloads for set algebra, functional pipelines, and three backing variants (hash, linked, sorted). We also introduce the Dynamic Range type, which revolutionizes interval operations with lazy iteration, multiple element types (integers, decimals, characters, dates, and custom IRangeable types), exclusive boundaries, custom stepping, Java Stream integration, and unbounded/half-bounded support. On the language evolution side, inner classes and template classes bring new structural capabilities, while class references now double as callable constructors via functional callbacks. The DataNavigator gains full JSONPath-style query support with get(), has(), and the new query() method. The MiniServer health endpoint now includes Undertow and WebSocket metrics. The formatter becomes even more production-ready with ignore-comment support (@formatter:off / bxformat-ignore-start), multiple-source input, --excludes flag, and fine-grained template.enabled / property_spacing rules. Phew! So much to cover, let's dive in!
🚀 Major Highlights
🔢 Dynamic Set — First-Class Collection Type
BoxLang 1.14.0 introduces BoxSet as a brand-new first-class type, wrapping java.util.Set with full BoxLang integration including member-function dispatch, change listeners, metadata, and JSON serialization. Sets provide a powerful collection model for working with unique values, making them ideal for deduplication, membership testing, tagging systems, permissions, caching, filtering, mathematics, and data comparison workflows.
Unlike arrays, sets enforce uniqueness by design and offer highly efficient lookup operations. BoxLang elevates sets to a first-class citizen with literal syntax, functional collection operations, and rich operator overloads for set algebra—including unions, intersections, differences, and symmetric differences—making complex data manipulation both expressive and concise.
Whether you're comparing datasets, managing unique identifiers, processing large collections, implementing access-control rules, or building recommendation and analytics engines, BoxSet provides a performant and elegant foundation for working with distinct values at scale.
Sets support three backing variants:
DEFAULT—HashSet, fastest, no orderingLINKED—LinkedHashSet, preserves insertion orderSORTED—TreeSet, natural ordering viaCompare.invoke
// BIF construction
s = setNew() // empty default (hash)
s = setNew( type="linked", values=[1,2,3] ) // ordered, deduped
s = setOf( 1, 2, 2, 3 ) // varargs, deduped
// Literal syntax (soft-keyword "set", parser-gated)
s = set{ 1, 2, 3 } // default (hash)
s = set{} // empty
// From an Array
s = [1, 2, 3].toSet()
s = [1, 2, 3].toSet( "linked" )Set algebra via operators:
Rich member-function API — sets support .add(), .contains(), .has(), .remove(), .delete(), .size(), .len(), .isEmpty(), .addAll(), .removeAll(), .retainAll(), .clear(), .containsAll(), .equals(), .isSubsetOf(), .isSupersetOf(), .isDisjointFrom(), .union(), .intersection(), .difference(), .symmetricDifference(), and functional pipelines: .each(), .map(), .filter(), .reject(), .reduce(), .every(), .some(), .none(), .find().
Set Built-In Functions Reference
Construction & Creation
setNew( [type], [values] )
—
Create a new Set, optionally seeded from a collection
setOf( ...values )
—
Build a default (hash) Set from positional arguments
toSet( collection, [type] )
Array.toSet(), Query.toSet(), String.listToSet()
Convert a collection into a Set, deduplicating
structKeySet( struct )
Struct.keySet()
Build a Set containing the keys of a Struct
structValueSet( struct )
Struct.valueSet()
Build a Set containing the values of a Struct
Mutation
boxSetAdd( set, value )
.add(), .append()
Add an element — duplicates ignored, returns the Set
boxSetAddAll( set, collection )
.addAll()
Add every element of a collection to a Set
boxSetRemove( set, value )
.remove(), .delete()
Remove an element — returns the Set for chaining
boxSetRemoveAll( set, collection )
.removeAll()
Remove every element of a collection from a Set
boxSetRetainAll( set, collection )
.retainAll()
Retain only elements also present in the collection
boxSetClear( set )
.clear()
Remove all elements, leaving the Set empty
Query & Membership
boxSetContains( set, value )
.contains(), .has()
Test whether a Set contains a given value
boxSetContainsAll( set, collection )
.containsAll()
Test whether a Set contains every element of a collection
boxSetIsEmpty( set )
.isEmpty()
Test whether a Set has no elements
boxSetEquals( setA, setB )
.equals()
Test whether two Sets contain the same elements
boxSetIsSubsetOf( setA, setB )
.isSubsetOf()
Test whether every element of A is also in B
boxSetIsSupersetOf( setA, setB )
.isSupersetOf()
Test whether every element of B is also in A
boxSetIsDisjointFrom( setA, setB )
.isDisjointFrom()
Test whether two Sets share no elements
boxSetFind( set, predicate )
.find()
Return the first element matching the predicate
boxSetEvery( set, predicate )
.every()
True if every element matches the predicate
boxSetSome( set, predicate )
.some(), .any()
True if at least one element matches the predicate
boxSetNone( set, predicate )
.none()
True if no element matches the predicate
Set Algebra
boxSetUnion( setA, setB )
.union()
+
Compute the union (A ∪ B)
boxSetIntersection( setA, setB )
.intersection()
*
Compute the intersection (A ∩ B)
boxSetDifference( setA, setB )
.difference()
-
Compute the difference (A − B)
boxSetSymmetricDifference( setA, setB )
.symmetricDifference()
^
Compute the symmetric difference (A △ B)
Functional Pipelines
boxSetEach( set, callback )
.each()
Invoke a callback for each element
boxSetMap( set, callback )
.map()
Transform each element, deduplicate results into a new Set
boxSetFilter( set, predicate )
.filter()
Return a new Set of elements matching the predicate
boxSetReject( set, predicate )
.reject()
Return a new Set of elements NOT matching the predicate
boxSetReduce( set, callback, initialValue )
.reduce()
Left-fold with an accumulator function and initial value
Export & Conversion
boxSetToArray( set )
.toArray()
Convert a Set to an Array, preserving iteration order
boxSetToList( set, [delimiter] )
.toList()
Join elements into a delimited string
For a deeper guide on BoxLang sets visit our docs: BoxSet Documentation.
📏 Ranges — Lazy, Typed, Iterable Intervals
BoxLang 1.14.0 introduces Ranges as a first-class type—a massive evolution from the original .. operator that simply materialized arrays. Instead of eagerly generating every value up front, ranges are now lazy, iterable objects that produce values on demand, making them far more memory-efficient, composable, and expressive for everything from loops and data processing pipelines to scheduling, analytics, and domain modeling. oai_citation:0‡Ortus Solutions Community
What makes BoxLang's implementation particularly unique is that ranges are no longer limited to integers. They natively support integers, decimals, characters, dates, and even custom user-defined types through the new IRangeable interface. Developers can create ascending or descending ranges, define custom step increments, use inclusive or exclusive boundaries, build unbounded or half-bounded ranges, perform membership and boundary checks, and seamlessly integrate with Java Streams for high-performance functional processing. oai_citation:1‡Ortus Solutions Community
Unlike many languages where ranges are little more than syntactic sugar for numeric loops, BoxLang elevates ranges into a rich abstraction for representing intervals and sequences of values. Need every day in a month? Every quarter in a fiscal year? Every character from a to z? Every version number, semantic identifier, or business object in a custom progression? Ranges make these operations natural, fluent, and type-safe.
Perhaps the most groundbreaking capability is the introduction of the IRangeable interface, which allows developers to teach BoxLang how to create ranges for their own domain objects. This means you can define ranges over custom types such as software versions, inventory SKUs, workflow states, fiscal periods, geographic coordinates, or any object that has a logical progression. This transforms ranges from a language feature into an extensible framework for modeling real-world sequences and intervals directly in your applications.
By combining lazy evaluation, multiple built-in data types, customizable boundaries and stepping, Java Stream interoperability, and user-extensible range semantics, BoxLang delivers one of the most powerful and flexible range implementations available in any dynamic language today. oai_citation:2‡Ortus Solutions Community
Basic range syntax:
Ranges are not arrays — they're lightweight objects that generate values on demand:
Multiple element types:
Lazy iteration and streaming:
Ranges don't allocate memory for their values — huge ranges are cheap:
Custom stepping:
Contains semantics:
Simple ranges use bounds checks, but stepped ranges verify step-reachability:
Clamping and position checks:
Typed unbounded ranges:
Use .type() to constrain an unbounded range to a specific BoxLang type:
For exact Java class matching with no coercion, pass a Class reference:
Custom rangeable types via IRangeable:
Any BoxLang or Java class can implement ortus.boxlang.runtime.types.IRangeable to participate in ranges:
For a comprehensive guide to BoxLang ranges, including advanced usage patterns and IRangeable implementation details, visit our docs: BoxLang Ranges Documentation.
🧩 Inner Classes and Template Classes
BoxLang now supports classes defined inline within scripts (.bxs), templates (.bxm), or even inside other classes, which enables encapsulation, organization, and scope-local class definitions. These are sometimes called script classes or local classes.
Local classes in .bxs scripts define a named class anywhere in a script file and instantiate it with new. Classes are hoisted, so you can use new before the textual definition:
Local classes in .bxm templates — define a class directly inside a <bx:script> island within a markup template:
Classes that extend other classes — local classes can extend other local classes, abstract classes, and even top-level .bx classes, with full polymorphism:
Local classes with imports — classes inherit their enclosing script's imports, allowing them to use Java types directly:
Inner classes — classes can also be nested inside other classes:
Inner classes are accessed externally via the $ separator syntax — fully qualified, imported, or with aliases:
You can read more about this feature and see additional examples in our docs: Inner Classes Documentation and Template Classes Documentation.
🏗️ Class References as Callable Constructors
BoxLang 1.14.0 introduces a major evolution in object construction by treating class references as first-class callable objects. Whether the class originates from BoxLang or Java, imported class references can now participate directly in the language's functional programming model. This removes much of the ceremony traditionally associated with object creation and opens the door to more expressive, composable, and concise code.
Traditionally, object creation required the new keyword, which remains fully supported. However, class references can now invoke their constructors directly using .init() without requiring new, making object construction feel more natural and consistent with the rest of the language. This is particularly useful when working with dynamically resolved classes, dependency injection scenarios, factory patterns, or APIs that return class references at runtime.
Even more powerful is the introduction of functional constructors, where the class reference itself becomes callable. Invoking a class reference as a function automatically executes the appropriate constructor and returns a new instance. This provides a clean, Python-inspired syntax that reduces noise while preserving full constructor semantics and compatibility with both Java and BoxLang classes.
Beyond syntactic convenience, this feature unlocks entirely new functional programming patterns. Since class references are now callable objects, they can be passed directly to higher-order functions such as map(), reduce(), filter(), and custom functional pipelines. Transforming collections of raw data into fully instantiated objects becomes remarkably concise, allowing developers to express object creation as a first-class operation rather than wrapping constructors in anonymous functions or lambdas.
This capability also strengthens BoxLang's interoperability story. Java classes and BoxLang classes now share a consistent construction model, reducing cognitive overhead when moving between the two ecosystems. Whether you're instantiating a StringBuilder, a custom domain object, or a framework component, the same fluent syntax applies.
Under the hood, class references are wrapped in a specialized ClassInvokerFunction, allowing them to participate in the runtime exactly like any other callable object. Constructor invocation is delegated to the same proven instantiation pipeline used by the new operator, ensuring consistent behavior, compatibility, and performance while dramatically expanding the expressive power of the language.
Class references as functional constructors — the imported class reference itself can be invoked as a function, which executes the constructor and returns an instance. This provides Python-style constructor ergonomics for both Java and BoxLang classes:
Because class references are callable, they can be passed directly to higher-order functions — a clean functional style for mapping data to objects:
Under the hood, class references are wrapped in a ClassInvokerFunction, whose _invoke() delegates to the same constructor plumbing as the new keyword.
🔍 DataNavigator JSONPath Support
What is a DataNavigator? A DataNavigator is BoxLang's fluent helper for safely moving through nested data structures such as Structs, Arrays, parsed JSON, runtime configuration, and metadata. It gives you a consistent API for scoping into data with from(), checking whether values exist with has(), reading values with get(), and applying defaults or strict access rules without scattering null checks throughout your code.
The DataNavigator fluent API gains full JSONPath-style expression support in get(), has(), from(), and the new query() method for multiple-return scenarios. This makes it much easier to inspect, extract, and reshape deeply nested configuration, JSON, API payloads, module metadata, and mixed Array/Struct data without writing repetitive defensive traversal code.
Developers can now use compact path expressions with dot notation, array indexes, slices, wildcards, recursive descent, and filter expressions directly inside the existing navigator workflow. get() remains the best fit when you expect a single value, has() can validate deep paths before use, from() can scope a navigator to a nested segment, and query() returns every match as a BoxLang Array when a path fans out across collections.
This release also adds getOrDefault() for explicit fallback values and getByKey() / hasByKey() for exact-key lookups when real key names contain dots or brackets. Together, these additions make data navigation safer, more expressive, and easier to read, especially in code that consumes external JSON where fields may be optional, irregular, or deeply nested.
Benefits:
Less boilerplate for nested Array/Struct traversal
Safer handling of optional values with clear fallback behavior
Multi-result extraction without manual loops
Better support for real-world JSON payloads and configuration documents
Exact-key access for data models that use dotted or bracketed key names
Path expression support:
New methods:
All path expressions are whitespace-tolerant — leading, trailing, and separator-adjacent whitespace is ignored.
For the complete guide, examples, and method reference, visit the DataNavigator documentation.
🧵 Query Transformers & Global Query Options
queryExecute() and bx:query are locked into three hardcoded return types: query, array, and struct. Users who want tabular arrays, rich column descriptors, JSON, domain objects, or any other format must post-process results in a separate step. Adding new native return types for every use case is unsustainable.
A powerful new Query Transformer framework (BL-2476) solves this by allowing you to register transformers that process query result sets natively and return exactly what you need — eliminating boilerplate post-processing, since you have access to the full query object and metadata at transformation time.
Three transformer input types:
Closure/Lambda —
(query, metadata) => anyor(query, metadata) → anyClass instance — any class with a
transform(query, metadata)methodString — name of a registered transformer from
this.queryTransformersinApplication.bx
When transformer is provided, it takes precedence over returnType. The transformer receives two arguments:
query— the raw Query object (.recordCount,.toArrayOfStructs(),.getData(),.getColumnNames(), etc.)metadata— a struct containingsql,parameters,executionTime,columnMetadata, and more
Transformer Examples
1. Inline Closure — Custom Struct with Metadata
2. Inline Closure — Domain Objects
3. Inline Closure — "Rich" Format with Column Descriptors
4. Inline Closure — "Tabular" Format (Near Zero-Copy)
5. Class Instance Transformer
6. Registered Transformers (Application.bx)
7. Transformer Takes Precedence Over returnType
8. bx:query Component
Global Query Options (BL-2477)
BL-2477)A new queries configuration section in boxlang.json allows global query option defaults, while this.queryOptions = {} in Application.bx provides application-level default query behaviors.
boxlang.json:
Application.bx:
All options can be overridden per query via queryExecute() options or bx:query attributes. Per-query options take highest priority, followed by this.queryOptions, with boxlang.json as the fallback.
✨ New Features
schedulerNew() BIF (BL-2408)
schedulerNew() BIF (BL-2408)Create and register schedulers directly with a single BIF call — no class file required. Unlike schedulerStart() which requires a class path, schedulerNew() creates a lightweight, ad-hoc scheduler ready for task registration.
Use schedulerNew() for lightweight runtime schedulers. Use schedulerStart() when you need lifecycle callbacks (onStartup, onShutdown, onAnyTaskError) via a dedicated scheduler class.
webMode Server Identifier (BL-1790)
webMode Server Identifier (BL-1790)The server scope now exposes a webMode boolean indicating whether the runtime is operating in web (servlet/MiniServer) mode.
New String BIFs: stringStartsWith, stringEndsWith (BL-2439)
stringStartsWith, stringEndsWith (BL-2439)Four new Built-In Functions with member-method support for checking string prefix/suffix:
Left/Right Arrow Key REPL Navigation (BL-2409)
The REPL now supports left and right arrow keys for cursor movement within the current input line — a long-requested quality-of-life improvement for interactive development.
Formatter: Multiple File Sources & Excludes (BL-2417, BL-2418)
The boxlang format command now accepts multiple --source files and a new --excludes flag for skipping files or directories:
Formatter: Ignore Comments (BL-2440)
Three styles of formatter-ignore comments are now supported, matching the most popular conventions:
Formatter: template.enabled Flag (BL-2442)
template.enabled Flag (BL-2442)A new formatter config flag template.enabled (defaults to false) gates template (.bxm / .cfm) formatting until it exits experimental mode:
Formatter: property_spacing Rule (BL-2443)
property_spacing Rule (BL-2443)The new class.property_spacing rule (default: 1) controls blank lines between property declarations in class bodies — matching Ortus coding standards with a single blank line between properties.
Pretty Print Config Clone (BL-2422)
The Config object now supports .clone(), enabling safe configuration mutation for multi-pass formatting and tooling scenarios without side effects.
ResolvedFilePath Dump Template (BL-2428)
ResolvedFilePath instances now render with a dedicated HTML dump template showing mapping name, mapping path, relative path, and absolute path — invaluable for debugging module resolution and class loading issues.
Skills & AGENTS.md Standards (BL-2415)
BoxLang now ships with AI agent skills in .agents/skills/ and updated AGENTS.md standards, providing structured domain knowledge for AI coding assistants working with BoxLang codebases.
ON_DATASOURCE_INITIALIZED Interception Point (BL-2454)
ON_DATASOURCE_INITIALIZED Interception Point (BL-2454)A new interception point fires after a datasource config is loaded but before the connection pool is established — giving modules full access to the raw HikariCP configuration for advanced customization:
MiniServer Health Metrics (BL-2455, BL-2456)
The MiniServer /health endpoint now includes Undertow worker pool statistics, WebSocket session counts, and additional JVM metrics. The MiniServer also supports static retrieval of the Undertow server instance and XNIO worker for programmatic metrics access.
🔧 Improvements
Language & Runtime
BL-1012—BooleanFormatandTrueFalseFormatconsolidated:TrueFalseFormatis now a deprecated alias forBooleanFormat, scheduled for removal in 2.0.
BL-2379/BL-2450— Function argument names now blocked from overlapping with import names; validation extended to closure/lambda argument names that shadow imports.BL-2432— Java interop varargs improved: BoxLang arrays passed to Java varargs methods no longer require manual unpacking intoObject[].
BL-2436— Auto-generate Java method stubs when a BoxLang class extends a Java class, filling in required abstract/interface method implementations.BL-2437— Support import aliases inextendsandimplementsclauses for Java classes:
BL-2459— Range type improvements with better element category detection (NUMBER, STRING, CHARACTER, IRANGEABLE, OTHER), enabling faster coercion and broader type support for range operations.BL-2471— Application objects now expose.getWatchers(),.getSchedulers(), and.getAppDuration()for runtime introspection of active watchers, registered schedulers, and application uptime.
CFML Compatibility & Transpiler
BL-2395— CF compat:form.getPartsArray()added for compatibility with Adobe CF's form part enumeration.BL-2397/BL-2399— CF transpiler CLI now supports config loading (by convention or explicit path) and new CLI flags for fine-tuned transpilation control.BL-2410—FileUploadnow supportsmimeTypeas an alias for theacceptattribute:
BL-2460— TranspileparameterExists()toisDefined()and quote the parameter name for correct resolution.BL-2467— Transpilehash( string='test' )tohash( input='test' )— thestringargument is renamed toinputto match BoxLang'shash()BIF signature.
Formatter
BL-2397— Pretty print config can now be loaded by convention for the CF transpiler CLI tool.BL-2442— Newtemplate.enabledflag (defaults tofalse) gates experimental template formatting.BL-2443— Newclass.property_spacingrule (defaults to1) for consistent property declaration spacing.BL-2462— Semicolons now correctly emitted on required rules whenpreserveisfalse.
Caching & Data
BL-2472—ICacheStats.toStruct()now includes cache hit/miss ratios that were previously missing from the stats output.BL-2473— Theremove()method on cache providers no longer double-JSON-serializes when the result is already a JSON string.BL-2482— UUID values are now JSON-serialized as strings instead of objects, preventing downstream deserialization issues.
MiniServer & Web
BL-2469— Whitespace management now enabled ontext/plaincontent types, matching the behavior already present fortext/html.
Query & JDBC
BL-2468—fromPendingQueryand query announcements now include the execution context that was previously missing from the event data.BL-2485— Duplicate logic betweenarrayUnique()andlistRemoveDuplicates()consolidated into a shared implementation for consistency and maintainability.
String & Case Utilities
BL-2478— PascalCase and KebabCase BIFs updated with additional edge case handling. All case-conversion functions (snakeCase,pascalCase,kebabCase) now robustly handle camelCase, PascalCase, snake_case, kebab-case, space-separated, and mixed inputs:
🐛 Bug Fixes (By Area)
Language & Parser
BL-2424— Required function argument with no type no longer parsed as being of type"required"under certain conditions.BL-2425— Largeif/elseblocks no longer throwLargeMethodErrors— the compiler now splits oversized conditional blocks.BL-2426— Current template now correctly reported in an include from inside a function inside a class.BL-2429— Tag-based functions withoutput=truenow correctly interpolate variables during parsing.BL-2430— CF transpiler no longer addsoutput=trueto functions that don't match CF's default behavior.BL-2445— Interfaces with methods that lackdefaultno longer have thedefaultmodifier incorrectly added, which broke interface contracts.BL-2452— Parser now correctly handles method chaining to expression invocation patterns.BL-2470— Unscoped internal call to a generated accessor setter no longer mis-resolves to a BIF (regression in 1.14.0-snapshot+4460).BL-2475—try/catchnow works correctly within static blocks.
CFML Compatibility
BL-2331—DateFormatno longer throws "Can't cast Number to a DateTime" on valid numeric date representations.BL-2392— Cached query metadata no longer mutated by subsequent cache retrievals — a defensive copy is returned.BL-2405— CF's query column passed to array now applies to bracket notation correctly.BL-2406— Template switch cases no longer incorrectly usebreakstatements — alignment with CF semantics.BL-2419—ParseDateTimenow supportsyymmddformat parsing.BL-2435— CF compat:arrayMax(),arrayMin(), andarraySum()now accept dates in addition to numbers.BL-2414— Adobe CF compatibility: empty form fields removed from form scope list of same-named fields.
Formatter
BL-2441— Formatter no longer adds double assignment expressions when using theincludekeyword.BL-2444— Empty blocks with comments no longer collapse into invalid code.BL-2447— Formatter now adds a line break when an expression is followed by HTML.BL-2448— Include issue fixed where formatter was adding an extra attribute that broke other engines.BL-2462— Semicolons now correctly emitted on required rules whenpreserveisfalse.
Query & JDBC
BL-2411— JDBC trailing semicolon removal now handles multiple semicolons (not just one).BL-2412— QoQ single column in parentheses now takes the column name instead of defaulting tocolumn_0.BL-2413— Improved thread safety of large QoQ operations under contention.BL-2420— Data validation now enforced when setting values into query objects.BL-2421— QoQ math operations no longer fail on string data — values are coerced automatically.BL-2464— Query timeout bug fixed — was using the wrong configuration key internally.
Web & HTTP
BL-2416— WebService creation/usage now promotes HTTP/SSL exception messages to the main error message for better debuggability.BL-2423— ODataPOSTrequests fixed: aContent-Length: 0header is now sent to resolve "411 Length Required" errors.BL-2427—enableOutputOnlysetting now correctly uses output components from the parent context.BL-2480—writeToBrowserno longer overrides existingContent-Dispositionheader.BL-2483— FixedURISyntaxExceptionwhen executing files from paths containing spaces.
Caching, Serialization & Runtime
BL-2042—LoggingServiceconcurrent modification exception fixed with thread-safe logger management.BL-2400— Regression fix:serializeJSON()no longer stack overflows (1.13 regression).BL-2402—fileSetLastModified()now accepts a numeric timestamp in addition to date objects.BL-2403—DecryptBIF now correctly decrypts complex/structured objects — previously corrupted nested data.BL-2407— Scheduler task methods using(Double period, String timeUnit)now handle plural time units correctly.BL-2434—dataNavigatenow honors the default value parameter; a newgetOrDefault()method provides explicit fallback behavior.BL-2438— Preserve primitive type case (e.g.,intvsInt) in@overrideJavafallback stubs.BL-2458— Jackson JR JSON parsing no longer silently ignores trailing content — raises a parse error instead.BL-2461— Return values from interface methods are now properly coerced to the declared return type.BL-2479—BoxCacheStats.hitRate()no longer always returns0due to integer division — now uses floating-point arithmetic.BL-2483— FixedURISyntaxExceptionwhen executing files from paths containing spaces.
Scheduler & Async
BL-2407—ScheduledTaskmethods using(period, timeUnit)with plural time units (e.g., "hours", "minutes") now work correctly — previously only singular forms were recognized.
String BIFs
BL-1007—SnakeCaseBIF now correctly converts from camelCase to snake_case instead of simply replacing spaces. All case-conversion BIFs (snakeCase,pascalCase,kebabCase) handle camelCase, PascalCase, snake_case, kebab-case, and space-separated inputs.
📊 Release Snapshot
Release Date: June 3, 2026
Total Issues: 65
Distribution: 24 New Features, 20 Improvements, 21 Bugs
Primary Focus: Language evolution (sets, inner classes, template classes) and developer experience (formatter, data navigation, REPL)
BoxLang 1.14.0 is the recommended update for all teams. The new Dynamic Set type, inner/template class support, JSONPath data navigation, and query transformers are production-ready and bring significant expressiveness and productivity improvements over previous releases.
Last updated
Was this helpful?
