boxlang-language-fundamentals — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited boxlang-language-fundamentals (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
BoxLang is a modern, dynamic JVM language (JRE 21+) influenced by Java, CFML, Python, Ruby, Go, and PHP. It compiles to Java bytecode and provides complete Java interoperability with a more expressive, concise syntax.
| Extension | Purpose |
|---|---|
.bx | Class files (components, services, models) |
.bxs | Script files (standalone scripts, CLIs) |
.bxm | Markup/template files (HTML output, views) |
BoxLang uses dynamic typing — types are inferred at runtime. Explicit type annotations are optional but supported.
// Variable declaration (var keyword in functions)
var name = "BoxLang"
var count = 42
var price = 9.99
var active = true
// Null
var nothing = nulllocal — variables declared with var inside a functionarguments — function parametersvariables — component/class private scopethis — component/class public scopeurl, form, session, application, request, cgi, server// Explicit scope reference
variables.counter = 0
this.publicValue = "visible"
local.tempResult = compute()// Arithmetic
a + b a - b a * b a / b a % b a ^ b a \ b // integer divide
// Comparison
a == b a != b a > b a < b a >= b a <= b
a === b a !== b // strict (type + value)
// Logical
a && b a || b !a
a and b a or b not a // word operators
// String concatenation
a & b
// Safe-navigation (null-safe member access)
user?.address?.city // returns null instead of throwing
// Inclusive range (v1.12+)
1..5 // produces [1, 2, 3, 4, 5] — both ends included
// Ternary
result = condition ? trueValue : falseValue
// Elvis (null coalescing)
result = value ?: "default"// if / else if / else
if ( age >= 18 ) {
writeOutput( "adult" )
} else if ( age >= 13 ) {
writeOutput( "teen" )
} else {
writeOutput( "child" )
}
// switch
switch ( status ) {
case "active":
doActive()
break
case "pending":
case "review":
doPending()
break
default:
doDefault()
}
// for (index)
for ( var i = 1; i <= 10; i++ ) {
writeOutput( i )
}
// for-in (collection)
for ( var item in myArray ) {
writeOutput( item )
}
// for-in with destructuring (v1.12+)
for ( var [key, value] in myStruct ) {
writeOutput( "#key# = #value#" )
}
// while
while ( queue.len() > 0 ) {
process( queue.dequeue() )
}
// do-while
do {
attempt = tryConnect()
} while ( !attempt.success && retries++ < 3 )try {
result = riskyOperation()
} catch ( "CustomException" e ) {
handleCustom( e )
} catch ( any e ) {
// e.message, e.detail, e.stackTrace, e.type
logError( e.message )
} finally {
cleanup()
}
// Throwing exceptions
throw( message="Something went wrong", type="MyApp.ValidationError", detail="Field X is required" )
// Or as an object
throw new MyException( "Bad input" )// Double-quoted: interpolation enabled
var greeting = "Hello, #name#!"
var multi = "Line one
Line two"
// Single-quoted: literal (no interpolation)
var literal = 'Hello, #name#' // outputs literally: Hello, #name#
// Common string functions
len( str )
trim( str )
uCase( str ) / lCase( str )
left( str, n ) / right( str, n ) / mid( str, start, n )
replace( str, search, replacement )
reFind( pattern, str )
listToArray( str, delimiter )
str.contains( "foo" ) // member function syntaxCRITICAL: BoxLang arrays are 1-indexed (not 0-indexed like Java). The first element is always at index 1.
var fruits = [ "apple", "banana", "cherry" ]
// Access by index — starts at 1
fruits[ 1 ] // "apple" ✅
fruits[ 0 ] // null / out-of-bounds ❌ WRONG
// Preferred: use named accessors instead of numeric index
fruits.first() // "apple" — first element
fruits.last() // "cherry" — last element
// Common array operations
fruits.len() // 3
fruits.append( "date" ) // adds to end
fruits.prepend( "avocado" ) // adds to front
fruits.isEmpty() // false
fruits.contains( "banana" ) // true
fruits.find( "cherry" ) // 3 (1-based index, 0 if not found)
fruits.each( (f) -> println(f) )
fruits.map( (f) -> uCase(f) )
fruits.filter( (f) -> f.startsWith("a") )
fruits.reduce( (acc, f) -> acc & "," & f, "" )
// Inline array literal
var nums = [ 1, 2, 3, 4, 5 ]
// Spread (v1.12+)
var more = [ ...nums, 6, 7 ]When calling a Java method that accepts Object... args (varargs), you must pass a BoxLang array — a bare single value will not work:
// WRONG — bare value
storage.query( "SELECT * FROM users WHERE id = ?", userId )
// CORRECT — wrapped in an array
storage.query( "SELECT * FROM users WHERE id = ?", [userId] )
// Multiple params
storage.query( "SELECT * FROM users WHERE role = ? AND active = ?", [role, active] )Semicolons are optional at the end of statements and are considered noisy. Do not add them to variable declarations, function calls, return statements, or control-flow blocks.
// BAD — noisy semicolons
var name = "BoxLang";
var total = items.len();
return total;
// GOOD — clean, no semicolons
var name = "BoxLang"
var total = items.len()
return totalSemicolons ARE required (or conventional) in two places:
bx:header name="Content-Type" value="application/json";
bx:location url="/login" addToken=false;
bx:abort; class MyComponent {
bx:property name="title" type="string" default="";
bx:property name="count" type="numeric" default=0;
}BoxLang is dynamically typed with optional type enforcement:
// Type annotations (optional)
string function greet( required string name ) {
return "Hello, #name#!"
}
// Auto-casting
var num = "42" + 0 // 42 (string auto-cast to number)
var bool = "true" // truthy
var date = "2024-01-15" // auto-cast to date in date functions
// Type checking
isNumeric( val )
isDate( val )
isArray( val )
isStruct( val )
isNull( val )
getMetaData( obj ).name // introspect type// Array destructuring
var [first, second, ...rest] = myArray
var [a, b] = [1, 2]
// Struct destructuring
var { name, age } = person
var { name: fullName, age: years } = person // rename
// Spread in function calls
var args = [1, 2, 3]
sum( ...args )
// Spread in array/struct literals
var combined = [...arr1, ...arr2]
var merged = {...struct1, ...struct2}
// For-loop destructuring
for ( var [key, val] in myStruct ) { ... }
for ( var [index, item] in myArray ) { ... }// Single-line comment
/* Multi-line
comment */
/**
* Doc-comment (used for annotation metadata)
* @param name The user's name
* @return Greeting string
*/BIFs are globally available without imports. Call them directly or as member functions:
// Function-style
len( myArray )
arrayAppend( myArray, item )
structKeyExists( myStruct, "key" )
// Member-function style (preferred)
myArray.len()
myArray.append( item )
myStruct.keyExists( "key" )
// List all available BIFs
writeDump( getFunctionList() )writeOutput( "Hello" ) // write to output buffer
println( "Hello" ) // write + newline (scripts)
dump( var=myVar ) // debug dump
writeDump( myVar ) // alias for dump
abort // stop executionfunction KeywordInside a class body, the function keyword is optional. BoxLang supports a concise declaration style with optional colon-based return type annotations:
class MathService {
// Concise declaration — no "function" keyword
add( numeric a, numeric b ) {
return a + b
}
// With return-type annotation (colon syntax)
multiply( required numeric a, required numeric b ):numeric {
return a * b
}
// With default parameter value and return type
power( required numeric base, numeric exponent = 2 ):numeric {
return base ^ exponent
}
// Void-like — no return type declared
logOperation( required string operation ) {
writeLog( "Operation: #operation#" )
}
}Available return types: string, numeric, boolean, array, struct, query, date, void, any, or a fully-qualified class name.
function Keyword (Still Valid)class Service {
function calculate( required numeric value ):numeric {
return value * 2
}
}Both styles are equivalent. Prefer the concise style inside classes; use the function keyword for standalone script-level functions and closures.
| Pitfall | Wrong | Correct |
|---|---|---|
| Array indexing | arr[ 0 ] | arr[ 1 ] or arr.first() |
| Trailing semicolons | var x = 1; | var x = 1 |
| Varargs calls | query( sql, singleVal ) | query( sql, [singleVal] ) |
| CFML functions in BoxLang | cfheader( ... ) | bx:header name=... value=...; |
Java-style // not needed | n/a | Both // and /* */ work |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.