boxlang-core-dev-bif-development

Installation
SKILL.md

BoxLang BIF Development

Overview

Built-in functions (BIFs) are globally available functions in BoxLang — no imports needed. When placed in a module's bifs/ directory, they are automatically discovered and registered at module load time. BIFs can be implemented in either BoxLang or Java.

BoxLang BIF

Minimal Example

// bifs/Greet.bx
// File name = function name (case-insensitive: greet, Greet, GREET all work)

@BoxBIF
class {

    function invoke( required string name ) {
        return "Hello, #arguments.name#!"
    }

}
// Usage anywhere in BoxLang (no import)
greet( "Ada" )   // "Hello, Ada!"

Full-Featured BoxLang BIF

// bifs/StringTitleCase.bx
@BoxBIF
class {

    /**
     * Converts a string to title case.
     *
     * @str The input string
     * @delimiters Word delimiters (default: space)
     * @return Title-cased string
     */
    string function invoke(
        required string str,
        string delimiters = " "
    ) {
        if ( !len( arguments.str ) ) return ""

        var words = listToArray( arguments.str, arguments.delimiters )
        return words
            .map( (w) -> uCase( left(w,1) ) & lCase( mid(w,2,len(w)) ) )
            .toList( arguments.delimiters )
    }

}

Java BIF

For performance-critical functions or when you need deep JVM access:

// src/main/java/com/example/bifs/StringTitleCase.java
package com.example.bifs;

import ortus.boxlang.runtime.bifs.BIF;
import ortus.boxlang.runtime.bifs.BoxBIF;
import ortus.boxlang.runtime.bifs.BoxMember;
import ortus.boxlang.runtime.context.IBoxContext;
import ortus.boxlang.runtime.scopes.ArgumentsScope;
import ortus.boxlang.runtime.scopes.Key;
import ortus.boxlang.runtime.types.Argument;
import ortus.boxlang.runtime.types.BoxLangType;

@BoxBIF
// Optional: also register as a member function on String
@BoxMember( type = BoxLangType.STRING, name = "titleCase" )
public class StringTitleCase extends BIF {

    // Declare argument metadata
    public StringTitleCase() {
        super();
        declaredArguments = new Argument[] {
            new Argument( true,  "string", Key.of( "str" ) ),
            new Argument( false, "string", Key.of( "delimiters" ), " " )
        };
    }

    /**
     * @param context   Current execution context
     * @param arguments Function arguments scope
     */
    @Override
    public Object invoke( IBoxContext context, ArgumentsScope arguments ) {
        String str        = arguments.getAsString( Key.of( "str" ) );
        String delimiters = arguments.getAsString( Key.of( "delimiters" ) );

        if ( str == null || str.isEmpty() ) return "";

        String[] words = str.split( "[" + delimiters + "]" );
        StringBuilder sb = new StringBuilder();
        for ( int i = 0; i < words.length; i++ ) {
            if ( i > 0 ) sb.append( delimiters.charAt( 0 ) );
            if ( !words[i].isEmpty() ) {
                sb.append( Character.toUpperCase( words[i].charAt(0) ) );
                sb.append( words[i].substring(1).toLowerCase() );
            }
        }
        return sb.toString();
    }
}

With @BoxMember, the BIF is also callable as a member function:

"hello world".titleCase()  // "Hello World"
titleCase( "hello world" ) // "Hello World" (BIF style)

Key Java Classes for BIF Development

Class/Interface Package Purpose
BIF ortus.boxlang.runtime.bifs Base class for all BIFs
@BoxBIF ortus.boxlang.runtime.bifs Marks a class as a BIF
@BoxMember ortus.boxlang.runtime.bifs Registers as member function
IBoxContext ortus.boxlang.runtime.context Current execution context
ArgumentsScope ortus.boxlang.runtime.scopes Typed argument access
Key ortus.boxlang.runtime.scopes String key interning
Argument ortus.boxlang.runtime.types Argument descriptor
BoxLangType ortus.boxlang.runtime.types Enum of BoxLang types
BoxRuntime ortus.boxlang.runtime Runtime singleton

Accessing BoxRuntime Services From a BIF

import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.cache.providers.ICacheProvider;
import ortus.boxlang.runtime.services.CacheService;

@BoxBIF
public class CachedFetch extends BIF {

    private BoxRuntime runtime = BoxRuntime.getInstance();

    @Override
    public Object invoke( IBoxContext context, ArgumentsScope arguments ) {
        String url = arguments.getAsString( Key.of( "url" ) );

        CacheService cacheService = runtime.getCacheService();
        ICacheProvider cache      = cacheService.getDefaultCache();

        Object cached = cache.get( Key.of( url ) );
        if ( cached != null ) return cached;

        // Fetch data...
        Object result = fetchFromUrl( url );
        cache.set( Key.of( url ), result, 300L, 0L );  // 300s TTL
        return result;
    }
}

Accessing Context Services

@Override
public Object invoke( IBoxContext context, ArgumentsScope arguments ) {
    // Get the current request scope
    IScope requestScope = context.getScopeNearby( RequestScope.name );

    // Get the application scope
    IScope appScope = context.getScopeNearby( ApplicationScope.name );

    // Get the session scope
    IScope sessionScope = context.getScopeNearby( SessionScope.name );

    // Resolve a variable
    Object val = context.scopeFindNearby( Key.of( "myVar" ), null ).value();

    // Invoke another function
    Object result = context.invokeFunction( Key.of( "len" ), new Object[]{ "hello" } );

    return result;
}

BoxLang BIF with Runtime Access

// bifs/GetAppSetting.bx
@BoxBIF
class {

    function invoke( required string key, any defaultValue = "" ) {
        // Access the BoxRuntime
        var runtime  = boxRuntime
        var appScope = getApplicationScope()  // available in web context

        return appScope.keyExists( arguments.key )
            ? appScope[ arguments.key ]
            : arguments.defaultValue
    }

}

Registering a BIF Alias

// Register under multiple names via multiple @BoxBIF annotations
@BoxBIF
@BoxBIF( alias = "strTitleCase" )
@BoxBIF( alias = "toTitleCase" )
public class StringTitleCase extends BIF { ... }

Member Function Registration

Member functions are BIFs callable on a specific type using dot notation:

@BoxBIF
@BoxMember( type = BoxLangType.ARRAY,  name = "shuffle" )   // array.shuffle()
@BoxMember( type = BoxLangType.STRING, name = "toSlug" )    // str.toSlug()
@BoxMember( type = BoxLangType.STRUCT, name = "deepMerge" ) // struct.deepMerge()
public class MyBIF extends BIF { ... }
[3,1,2].shuffle()
"Hello World".toSlug()   // "hello-world"
config.deepMerge( overrides )

BIF Argument Types

// Argument types available in ortus.boxlang.runtime.types.Argument
new Argument( required, type, key )
new Argument( required, type, key, defaultValue )

// Types: "any", "string", "numeric", "boolean", "array", "struct",
//        "query", "date", "function", "closure", "lambda", "class"

Testing Your BIF

// tests/specs/MyBIFTest.bx
class extends="testbox.system.BaseSpec" {

    function run() {
        describe( "greet BIF", function() {

            it( "should greet a person by name", function() {
                expect( greet("Ada") ).toBe( "Hello, Ada!" )
            })

            it( "should handle empty name", function() {
                expect( greet("") ).toBe( "Hello, !" )
            })

            it( "should be callable as member function", function() {
                expect( "Ada".titleCase() ).toBe( "Ada" )
                expect( "hello world".titleCase() ).toBe( "Hello World" )
            })

        })
    }

}
box testbox run

Discovering Registered BIFs

// List all registered BIFs (including your custom ones)
writeDump( getFunctionList() )

// Check if a specific BIF exists
if ( structKeyExists( getFunctionList(), "greet" ) ) {
    writeOutput( "greet BIF is registered!" )
}

References

Related skills

More from ortus-boxlang/skills

Installs
4
First Seen
Apr 21, 2026