Gotchas
This page documents important Jyro behaviours and the correct way to handle them.
1. Empty arrays and objects are truthy
Jyro treats all arrays and objects as truthy - even empty ones. This means an if check on a collection always passes, regardless of whether it contains any elements.
Check the length explicitly instead:
# INCORRECT - always enters the block, even when Data.items is []
if Data.items then ... end
# CORRECT - tests whether the array actually has elements
if Length(Data.items) > 0 then ... end
2. ToNumber returns null for invalid input
When ToNumber cannot parse a string as a number it returns null, not 0. Code that assumes a numeric result without checking will propagate null through subsequent calculations.
Always test the return value before using it:
var num = ToNumber(Data.input)
if num is null then
fail "Invalid number: " + Data.input
end
3. Division by zero terminates the script
Division or modulo by zero throws an immediate runtime error that terminates the script. There is no special infinity or NaN value.
Guard every division with a zero check:
if count != 0 then
Data.average = total / count
else
Data.average = 0
end
4. All array functions return new arrays
Every standard library function that operates on an array returns a new array. The original is never mutated. Assign the return value to capture the result.
Assign the result back to the variable:
var items = [3, 1, 2]
Sort(items) # items is STILL [3, 1, 2] - result discarded
var sorted = Sort(items) # sorted is [1, 2, 3]
var items = [1, 2]
Append(items, 3) # items is STILL [1, 2] - result discarded
items = Append(items, 3) # NOW items is [1, 2, 3]
5. Cannot modify a collection during iteration
Reassigning the array that a foreach loop is iterating over causes a runtime error. The iterator holds a reference to the original collection and detects the mutation.
Collect changes into a separate array, then apply them after the loop:
# INCORRECT - runtime error: modifying the iterated collection
foreach item in Data.items do
Data.items = Append(Data.items, item)
end
# CORRECT - accumulate into a separate array, merge afterwards
var additions = []
foreach item in Data.items do
if item.shouldDuplicate then
additions = Append(additions, item)
end
end
foreach addition in additions do
Data.items = Append(Data.items, addition)
end
6. Nested properties need intermediate objects
Assigning to a deeply nested path like Data.a.b.c fails if the intermediate objects (Data.a, Data.a.b) do not already exist. Jyro does not auto-create parent objects on assignment.
Create each level explicitly, or assign a nested literal:
# INCORRECT - runtime error if Data.deep doesn't exist
Data.deep.nested.value = "x"
# CORRECT - build the path one level at a time
Data.deep = {}
Data.deep.nested = {}
Data.deep.nested.value = "x"
# ALSO CORRECT - assign the whole structure as a literal
Data.deep = {"nested": {"value": "x"}}
7. Missing then after if/elseif
The then keyword is required after every if and elseif condition. Omitting it causes a parse error.
# INCORRECT - parse error
if x > 0
...
end
# CORRECT
if x > 0 then
...
end
8. Missing do after while/for/foreach
Loop statements require the do keyword after the condition or iteration clause. Omitting it causes a parse error.
# INCORRECT - parse error
while x > 0
...
end
# CORRECT
while x > 0 do
...
end
9. Missing end for blocks
Every if, while, for, foreach, and switch block must be closed with end. A missing end causes a parse error at the end of the script or at the start of the next block.
10. No string interpolation
Jyro does not support template syntax like ${name} or {name} inside strings. These are treated as literal characters, not variable references. Use the + operator to concatenate values into strings:
# INCORRECT - produces the literal text "${name}", not the variable's value
"Hello ${name}"
"Hello {name}"
# CORRECT - concatenation converts the variable to a string
"Hello " + name
11. Min/Max/Sum/Average take arrays, not multiple arguments
The aggregate math functions each accept a single array argument, not variadic arguments.
Wrap the values in an array literal:
# INCORRECT - too many arguments
Sum(1, 2, 3)
Min(a, b)
# CORRECT - pass a single array
Sum([1, 2, 3])
Min([a, b])
12. Merge takes an array of objects
Like the aggregate math functions, Merge accepts a single array of objects to merge together. It does not accept multiple object arguments.
# INCORRECT - too many arguments
Merge(obj1, obj2)
# CORRECT - pass an array of objects (later entries override earlier ones)
Merge([obj1, obj2])
13. GroupBy takes a field name string, not a lambda
GroupBy groups objects by a named field and expects a plain string, not a lambda expression. This is consistent with other field-based query functions like WhereByField and SortByField.
# INCORRECT - GroupBy does not accept lambdas
GroupBy(arr, x => x.category)
# CORRECT - pass the field name as a string
GroupBy(arr, "category")
14. Regex patterns - no \d, \w, \s
Jyro processes string escape sequences before the string reaches the regex engine. Sequences like \d, \w, and \s are resolved during string parsing, so they do not reach the regex engine as metacharacters. Use equivalent character classes instead:
# INCORRECT - \d is resolved by the string parser before reaching regex
RegexMatch(text, "\d+")
# CORRECT - character class reaches the regex engine intact
RegexMatch(text, "[0-9]+")
See Strings - Regex Pattern Escaping for the full substitution table.
15. return/fail message must be on the same line
The return and fail keywords accept an optional string message, but it must appear on the same line. A string on the next line is parsed as a separate expression statement, not as the message.
# INCORRECT - "message" is a standalone expression, not the return message
return
"message"
# CORRECT - message on the same line
return "message"
16. For loop bounds are exclusive
The upper bound of to and the lower bound of downto are exclusive, similar to < and > respectively. The loop variable never reaches the boundary value. To include the boundary, adjust it by one:
for i in 0 to 5 do # iterates: 0, 1, 2, 3, 4 (NOT 5)
...
end
for i in 5 downto 0 do # iterates: 5, 4, 3, 2, 1 (NOT 0)
...
end
# To include 5:
for i in 0 to 5 + 1 do # iterates: 0, 1, 2, 3, 4, 5
...
end
17. Function names are PascalCase and case-sensitive
All standard library functions use PascalCase naming (e.g. ToUpper, WhereByField). Function lookup is case-sensitive, so toupper or toUpper will fail with an “unknown function” error.
# INCORRECT - case mismatch
toupper("hello")
toUpper("hello")
# CORRECT
ToUpper("hello")
18. No semicolons
Statements are separated by newlines. Semicolons are not part of the syntax and will cause a parse error if used.
19. fail is for business logic, not debugging
The fail keyword terminates the script with an error status and is intended for signalling validation failures and business rule violations to the host application. It is not a debugging tool - use Data properties to write diagnostic output instead.