Skip to main content

Standard Library Reference

The constellation-lang standard library provides commonly-used functions for pipeline orchestration.

Most Commonly Used Functions

The functions you will use most often are: add, concat, gt/lt for comparisons, and/or/not for boolean logic, and list-length/list-first for collections. Start with these before exploring the full library.

Finding the Right Function

By Task

I want to...FunctionExample
Transform textUppercase, Lowercase, TrimUppercase("hello")"HELLO"
Work with numbersAdd, Multiply, Max, MinAdd(1, 2)3
Process listsMap, Filter, Reduce, LengthLength([1,2,3])3
Format stringsConcat, FormatConcat("a", "b")"ab"
Handle nullsCoalesce, IsEmptyCoalesce(null, "default")
Compare valuesEquals, GreaterThan, ContainsContains("abc", "b")true

By Category

The standard library is organized into categories:

  • String functions — Text manipulation and formatting
  • Numeric functions — Arithmetic and math operations
  • List functions — Collection processing with higher-order functions
  • Logic functions — Boolean operations and comparisons
  • Utility functions — Type conversion and null handling

Using the Standard Library

Quick Start

import io.constellation.lang.stdlib.StdLib

// Create a compiler with all stdlib functions registered
val compiler = StdLib.compiler

val source = """
in a: Int
in b: Int
sum = add(a, b)
isGreater = gt(sum, b)
out isGreater
"""

compiler.compile(source, "my-dag")

Selective Registration

Register only specific functions:

import io.constellation.lang.LangCompiler
import io.constellation.lang.stdlib._

val compiler = LangCompilerBuilder()
.withFunction(MathOps.addSignature)
.withFunction(MathOps.subtractSignature)
.withFunction(CompareOps.gtSignature)
.build

Function Reference

Type Signature Convention

Type signatures use arrow notation: (param1: Type1, param2: Type2) -> ReturnType. Generic types like List<Int> indicate the element type. All functions are pure unless noted otherwise.

Math Operations

FunctionType SignatureDescription
add(a: Int, b: Int) -> IntAdd two integers
subtract(a: Int, b: Int) -> IntSubtract b from a
multiply(a: Int, b: Int) -> IntMultiply two integers
divide(a: Int, b: Int) -> IntInteger division
max(a: Int, b: Int) -> IntMaximum of two integers
min(a: Int, b: Int) -> IntMinimum of two integers
abs(value: Int) -> IntAbsolute value
modulo(a: Int, b: Int) -> IntRemainder after division
round(value: Float) -> IntRound float to nearest integer
negate(value: Int) -> IntNegate a number

Error Behavior

FunctionError ConditionBehavior
divideb = 0Raises ArithmeticException with message "Division by zero in stdlib.divide"
modulob = 0Raises ArithmeticException with message "Division by zero in stdlib.modulo"

Edge Cases

FunctionEdge CaseResult
addadd(0, 0)0
addLarge numbers near Long.MaxValueMay overflow (no bounds checking)
subtractsubtract(-5, -3)-2
multiplymultiply(x, 0)0
multiplymultiply(-4, -3)12
dividedivide(0, 5)0
dividedivide(7, 3)2 (truncates toward zero)
dividedivide(-10, 3)-3 (truncates toward zero)
maxmax(5, 5)5
maxmax(-10, -5)-5
minmin(5, 5)5
minmin(-10, -5)-10
absabs(0)0
absabs(-5)5
absabs(Long.MinValue)Undefined (overflow)
modulomodulo(6, 3)0 (exact divisibility)
negatenegate(0)0
negatenegate(-5)5
roundround(3.5)4 (rounds half up)
roundround(-2.7)-3

Performance Notes

All math operations are O(1) pure functions with no memory allocation beyond the result.

Examples:

in x: Int
in y: Int

sum = add(x, y)
diff = subtract(x, y)
product = multiply(x, y)
quotient = divide(x, y)
maximum = max(x, y)
minimum = min(x, y)
absolute = abs(x)
remainder = modulo(x, y)
negated = negate(x)

out sum

Safe Division Pattern:

in numerator: Int
in denominator: Int

# Check for zero before dividing to avoid runtime errors
isZero = eq-int(denominator, 0)
safeResult = if (isZero) 0 else divide(numerator, denominator)

out safeResult

String Operations

FunctionType SignatureDescription
concat(a: String, b: String) -> StringConcatenate two strings
string-length(value: String) -> IntGet string length (character count)
join(list: List<String>, separator: String) -> StringJoin strings with delimiter
split(value: String, substring: String) -> List<String>Split string by delimiter
contains(value: String, substring: String) -> BooleanCheck if string contains substring
trim(value: String) -> StringTrim leading and trailing whitespace
replace(value: String, target: String, replacement: String) -> StringReplace all occurrences

Edge Cases

FunctionEdge CaseResult
concatconcat("", "")""
concatconcat("", "hello")"hello"
concatUnicode stringsFully supported
string-lengthstring-length("")0
string-lengthUnicode (e.g., Chinese)Character count, not byte count
string-lengthstring-length("hello world")11 (includes space)
joinEmpty list""
joinSingle element listElement without separator
splitEmpty delimiterReturns original string in single-element list
splitDelimiter not foundReturns original string in single-element list
splitConsecutive delimitersIncludes empty strings in result
containscontains("hello", "")true (empty string is always contained)
containscontains("", "x")false
trimtrim("")""
trimtrim(" ")"" (whitespace-only becomes empty)
trimtrim(" hello ")"hello"
replaceNo match foundReturns original string unchanged
replacereplace("aaa", "a", "b")"bbb" (replaces all occurrences)

Error Guarantees

All string operations are safe and never raise exceptions. They handle empty strings and Unicode gracefully.

Performance Notes

  • concat: O(n+m) where n and m are string lengths
  • string-length: O(1)
  • join: O(total length of all strings)
  • split: O(n) where n is string length; uses regex quoting internally for safe literal matching
  • contains: O(n*m) worst case
  • trim: O(n)
  • replace: O(n*m) worst case, creates new string

Examples:

in firstName: String
in lastName: String

fullName = concat(firstName, lastName)
nameLength = string-length(fullName)
trimmed = trim(fullName)
hasSpace = contains(fullName, " ")
cleaned = replace(fullName, " ", "-")

out fullName

Joining a List of Strings:

in words: List<String>
in separator: String

sentence = join(words, separator)

out sentence

Splitting a String:

in csv: String

# Split CSV line by comma
fields = split(csv, ",")

out fields

Boolean Operations

FunctionType SignatureDescription
and(a: Boolean, b: Boolean) -> BooleanLogical AND
or(a: Boolean, b: Boolean) -> BooleanLogical OR
not(value: Boolean) -> BooleanLogical NOT

Truth Tables

and(a, b):

abResult
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

or(a, b):

abResult
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse

not(value):

valueResult
truefalse
falsetrue

Error Guarantees

Boolean operations are always safe and cannot fail.

Performance Notes

All boolean operations are O(1) constant time, pure functions.

Examples:

in isActive: Boolean
in isVerified: Boolean

canProceed = and(isActive, isVerified)
hasAccess = or(isActive, isVerified)
isInactive = not(isActive)

out canProceed

Comparison Operations

FunctionType SignatureDescription
eq-int(a: Int, b: Int) -> BooleanCheck if integers are equal
eq-string(a: String, b: String) -> BooleanCheck if strings are equal
gt(a: Int, b: Int) -> BooleanCheck if a > b
lt(a: Int, b: Int) -> BooleanCheck if a < b
gte(a: Int, b: Int) -> BooleanCheck if a >= b
lte(a: Int, b: Int) -> BooleanCheck if a <= b

Edge Cases

FunctionEdge CaseResult
eq-inteq-int(0, 0)true
eq-inteq-int(-5, -5)true
eq-stringeq-string("", "")true
eq-stringeq-string("Hello", "hello")false (case-sensitive)
eq-stringUnicode stringsFully supported
gtgt(5, 5)false
gtgt(-5, -10)true
ltlt(5, 5)false
ltlt(-10, -5)true
gtegte(5, 5)true
ltelte(5, 5)true

Error Guarantees

Comparison operations are always safe and cannot fail.

Performance Notes

All comparison operations are O(1) for integers. String equality is O(min(n,m)) where n and m are string lengths.

Examples:

in score: Int
in threshold: Int
in expected: String
in actual: String

isAbove = gt(score, threshold)
isBelow = lt(score, threshold)
isEqual = eq-int(score, threshold)
matches = eq-string(expected, actual)

# Use with conditional
result = if (isAbove) score else threshold

out result

List Operations

FunctionType SignatureDescription
list-length(list: List<Int>) -> IntGet list length
list-first(list: List<Int>) -> IntGet first element
list-last(list: List<Int>) -> IntGet last element
list-is-empty(list: List<Int>) -> BooleanCheck if list is empty
list-sum(list: List<Int>) -> IntSum all elements
list-concat(a: List<Int>, b: List<Int>) -> List<Int>Concatenate two lists
list-contains(list: List<Int>, value: Int) -> BooleanCheck if element exists
list-reverse(list: List<Int>) -> List<Int>Reverse list order

Error Behavior

FunctionError ConditionBehavior
list-firstEmpty listRaises NoSuchElementException with message "stdlib.list-first: list is empty"
list-lastEmpty listRaises NoSuchElementException with message "stdlib.list-last: list is empty"

Edge Cases

FunctionEdge CaseResult
list-lengthEmpty list0
list-lengthSingle element1
list-is-emptyEmpty listtrue
list-is-emptyNon-empty listfalse
list-sumEmpty list0 (identity for addition)
list-sumNegative numbersSummed correctly
list-containsEmpty listfalse
list-reverseEmpty list[] (empty list)
list-reverseSingle elementSame list
list-concatBoth empty[]
list-concatFirst emptyReturns second list
list-concatSecond emptyReturns first list

Safe List Access Pattern

in numbers: List<Int>

# Always check before accessing first/last
isEmpty = list-is-empty(numbers)
safeFirst = if (isEmpty) 0 else list-first(numbers)

out safeFirst

Performance Notes

FunctionTime ComplexitySpace Complexity
list-lengthO(1)O(1)
list-firstO(1)O(1)
list-lastO(1)O(1)
list-is-emptyO(1)O(1)
list-sumO(n)O(1)
list-concatO(n+m)O(n+m)
list-containsO(n)O(1)
list-reverseO(n)O(n)

Examples:

in numbers: List<Int>

count = list-length(numbers)
first = list-first(numbers)
last = list-last(numbers)
isEmpty = list-is-empty(numbers)
total = list-sum(numbers)
reversed = list-reverse(numbers)

out count

Concatenating Lists:

in listA: List<Int>
in listB: List<Int>

combined = list-concat(listA, listB)

out combined

Type Conversion Operations

FunctionType SignatureDescription
to-string(value: Int) -> StringConvert integer to string
to-int(value: Float) -> IntTruncate float to integer
to-float(value: Int) -> FloatConvert integer to float

Edge Cases

FunctionEdge CaseResult
to-stringto-string(0)"0"
to-stringto-string(-7)"-7"
to-intto-int(3.7)3 (truncates toward zero)
to-intto-int(-3.7)-3 (truncates toward zero)
to-intto-int(0.0)0
to-floatto-float(0)0.0
to-floatto-float(-7)-7.0

Error Guarantees

Type conversion operations are always safe and cannot fail.

Note: to-int truncates toward zero (not floor), so -3.7 becomes -3, not -4.

Performance Notes

All type conversions are O(1) except to-string which is O(log n) where n is the magnitude of the integer.

Examples:

in count: Int
in measurement: Float

label = to-string(count)
truncated = to-int(measurement)
precise = to-float(count)

out label

Higher-Order Functions

tip

Higher-order functions like filter, map, all, and any are processed specially by the compiler and use InlineTransform at runtime. They short-circuit when possible (e.g., any stops on first true).

FunctionType SignatureDescription
filter(List<Int>, (Int) => Boolean) -> List<Int>Keep elements matching predicate
map(List<Int>, (Int) => Int) -> List<Int>Transform each element
all(List<Int>, (Int) => Boolean) -> BooleanCheck all elements match
any(List<Int>, (Int) => Boolean) -> BooleanCheck any element matches

Edge Cases

FunctionEdge CaseResult
filterEmpty list[]
filterNo matches[]
mapEmpty list[]
allEmpty listtrue (vacuous truth)
anyEmpty listfalse

Implementation Notes

Higher-order functions are processed specially by the compiler. They use InlineTransform at runtime (e.g., FilterTransform, MapTransform) rather than traditional Module implementations.

Performance Notes

FunctionTime ComplexitySpace Complexity
filterO(n)O(k) where k = matching elements
mapO(n)O(n)
allO(n) worst case, short-circuits on first falseO(1)
anyO(n) worst case, short-circuits on first trueO(1)

Examples:

use stdlib.collection
use stdlib.compare
use stdlib.math

in numbers: List<Int>

positives = filter(numbers, (x) => gt(x, 0))
doubled = map(numbers, (x) => multiply(x, 2))
allPositive = all(numbers, (x) => gt(x, 0))
anyNegative = any(numbers, (x) => lt(x, 0))

out positives

Chaining Higher-Order Functions:

use stdlib.collection
use stdlib.compare
use stdlib.math

in numbers: List<Int>

# Filter then map: get absolute values of negative numbers
negatives = filter(numbers, (x) => lt(x, 0))
absolutes = map(negatives, (x) => abs(x))

out absolutes

Utility Operations

FunctionType SignatureDescription
identity(value: String) -> StringPass-through (returns input unchanged)
log(message: String) -> StringLog message and pass through

Edge Cases

FunctionEdge CaseResult
identityEmpty string""
identityUnicodePassed through unchanged
logEmpty messageLogs empty line, returns ""

Error Guarantees

Utility operations are always safe and cannot fail.

Implementation Notes

  • identity is a pure function with no side effects
  • log prints to stdout with prefix [constellation-lang] and returns the input unchanged

Examples:

in message: String

# Log for debugging
logged = log(message)

# Identity (useful for type coercion or pipeline passthrough)
same = identity(message)

out logged

Common Patterns

Conditional Logic with Comparisons

in score: Int

threshold = 50
isPass = gt(score, threshold)
result = if (isPass) score else threshold

out result

Chaining Operations

in a: Int
in b: Int
in c: Int

# Compute (a + b) * c
sum = add(a, b)
product = multiply(sum, c)

out product

String Processing

in firstName: String
in lastName: String

# Create "lastName, firstName"
separator = ", "
temp = concat(lastName, separator)
fullName = concat(temp, firstName)
trimmed = trim(fullName)

out trimmed

Boolean Gates

in isAuthenticated: Boolean
in hasPermission: Boolean
in isAdmin: Boolean

# Check: (authenticated AND permission) OR admin
hasAccess = and(isAuthenticated, hasPermission)
canProceed = or(hasAccess, isAdmin)

out canProceed

Safe Division

in numerator: Int
in denominator: Int

# Avoid division by zero
isZero = eq-int(denominator, 0)
safeQuotient = if (isZero) 0 else divide(numerator, denominator)

out safeQuotient

Safe List Access

in numbers: List<Int>

# Get first element or default to 0
isEmpty = list-is-empty(numbers)
firstOrDefault = if (isEmpty) 0 else list-first(numbers)

out firstOrDefault

Data Aggregation

in values: List<Int>

count = list-length(values)
total = list-sum(values)

# Note: For average, you'd need float division which requires
# converting total to float first
totalFloat = to-float(total)
countFloat = to-float(count)

out total

Namespaces

All stdlib functions are organized into namespaces:

NamespaceFunctions
stdlib.mathadd, subtract, multiply, divide, max, min, abs, modulo, round, negate
stdlib.stringconcat, string-length, join, split, contains, trim, replace
stdlib.compareeq-int, eq-string, gt, lt, gte, lte
stdlib.booland, or, not
stdlib.listlist-length, list-first, list-last, list-is-empty, list-sum, list-concat, list-contains, list-reverse
stdlib.collectionfilter, map, all, any
stdlib.convertto-string, to-int, to-float
stdlibidentity
stdlib.debuglog

Module Details

Each stdlib function is implemented as a Constellation module. The modules are registered with these names:

FunctionModule Name
addstdlib.add
subtractstdlib.subtract
multiplystdlib.multiply
dividestdlib.divide
maxstdlib.max
minstdlib.min
absstdlib.abs
modulostdlib.modulo
roundstdlib.round
negatestdlib.negate
concatstdlib.concat
string-lengthstdlib.string-length
joinstdlib.join
splitstdlib.split
containsstdlib.contains
trimstdlib.trim
replacestdlib.replace
andstdlib.and
orstdlib.or
notstdlib.not
eq-intstdlib.eq-int
eq-stringstdlib.eq-string
gtstdlib.gt
ltstdlib.lt
gtestdlib.gte
ltestdlib.lte
list-lengthstdlib.list-length
list-firststdlib.list-first
list-laststdlib.list-last
list-is-emptystdlib.list-is-empty
list-sumstdlib.list-sum
list-concatstdlib.list-concat
list-containsstdlib.list-contains
list-reversestdlib.list-reverse
to-stringstdlib.to-string
to-intstdlib.to-int
to-floatstdlib.to-float
identitystdlib.identity
logstdlib.log

Error Handling Summary

Functions That Can Raise Errors

FunctionException TypeConditionMessage
divideArithmeticExceptionDivisor is zero"Division by zero in stdlib.divide"
moduloArithmeticExceptionDivisor is zero"Division by zero in stdlib.modulo"
list-firstNoSuchElementExceptionList is empty"stdlib.list-first: list is empty"
list-lastNoSuchElementExceptionList is empty"stdlib.list-last: list is empty"

Functions That Are Always Safe

All other functions are guaranteed not to raise exceptions when given valid typed inputs:

  • All math functions except divide and modulo
  • All string functions
  • All boolean functions
  • All comparison functions
  • All list functions except list-first and list-last
  • All type conversion functions
  • All higher-order functions
  • All utility functions

Type System Notes

Integer Type

Integers in constellation-lang use Long (64-bit signed) internally:

  • Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
  • Overflow behavior: Standard JVM wraparound (no automatic detection)

Float Type

Floats use Double (64-bit IEEE 754) internally:

  • Full double-precision floating-point support
  • Special values: NaN, Infinity, -Infinity are supported

String Type

Strings are Java String objects:

  • Full Unicode support (UTF-16 internally)
  • string-length returns character count (Unicode code units), not byte count

List Type

Lists use immutable Vector[CValue] internally:

  • Efficient random access: O(log n)
  • Efficient append/prepend: O(log n)
  • Memory efficient for large lists

Extending the Standard Library

Add custom functions following the same pattern:

import io.constellation.ModuleBuilder
import io.constellation.lang.semantic._

object MyModule {
case class In(value: Int)
case class Out(result: Int)

val module = ModuleBuilder
.metadata("my-namespace.my-function", "Description", 1, 0)
.tags("custom")
.implementationPure[In, Out](in => Out(in.value * 2))
.build

val signature = FunctionSignature(
name = "my-function",
params = List("value" -> SemanticType.SInt),
returns = SemanticType.SInt,
moduleName = "my-namespace.my-function"
)
}

Register with the compiler:

val compiler = StdLib.registerAll(LangCompilerBuilder())
.withFunction(MyModule.signature)
.build

Best Practices for Custom Functions

  1. Use descriptive names - Function names should clearly indicate purpose
  2. Document edge cases - Specify behavior for empty inputs, zeros, etc.
  3. Prefer pure implementations - Use implementationPure when possible
  4. Handle errors gracefully - Raise meaningful exceptions with clear messages
  5. Follow naming conventions - Use lowercase-with-hyphens for function names