APL Data-Binding Syntax

APL data binding expressions occur inside JSON strings and take the form "${expression}". Any number of expressions may occur inside a string, such as "${2}+${2} = ${2+2}". Expressions are evaluated within the current data-binding context. The data-binding context is a global dictionary that supports booleans, numbers, strings, arrays, objects, null, and references to defined resources.

Supported value types


An identifier is a name used to identify a data-binding variable. Identifiers must follow the C identifier naming convention: [a-zA-Z_][a-zA-Z0-9_]*. That is, the identifier must start with an upper or lower-case ASCII letter or underscore and may be followed by zero or more ASCII letters, numbers, or the underscore:


String literals

Strings are defined using either single or double quotes. The starting and ending quote must match. Quotes, carriage returns, and line-feeds may be escaped.

	${"Double-quoted string"}
	${'Single-quoted string'}
	${"Inner quote: \" or '"}

Expressions may be nested inside of a string.

	${"Two plus two is ${2+2}"}


Positive, negative, and floating point numbers are supported. Scientific notation is not supported. All numbers are internally stored as doubles:



Boolean values of true and false are supported.



The null constant is supported.



Resources defined in the data-binding context use the reserved character "@". For example:

${@isLandscape ? @myWideValue : @myNarrowValue}

APL packages define resources exposed in data-binding.

Absolute dimensions

A dimensional suffix converts a number into an absolute viewport dimension. The valid dimensional suffixes are "dp", "px", "vh", and "vw":

${23 dp}     // 23 display-independent pixels
${10 px}     // 10 pixels
${50 vw}     // 50% of the width of the viewport
${100vh}     // 100% of the height of the viewport

Dimensional suffixes must be attached to a number, not a more complex expression. For example ${(20*20) dp} is not valid, but ${20*20dp} is valid.

Truthy and Coercion

Data-binding expressions involve a number of different types. These types may be converted into other types. The following table gives an example of the different conversions (note that this assumes a viewport width of 512dp and a dpi of 320):

Object Example As Boolean As Number As String As Color As Dimension
Null null false 0 "" transparent 0dp
Boolean true true 1 "true" transparent 0dp
Boolean false false 0 "false" transparent 0dp
Number 23 true 23 "23" #00000017 23dp
Number 0 false 0 "0" transparent 0dp
String "My dog" true 0 "My dog" transparent 0dp
String "" false 0 "" transparent 0dp
String "-2.3" true -2.3 "-2.3" transparent -2.3dp
String "red" true 0 "red" #ff0000ff 0dp
String "50vw" true 50 "50vw" transparent 256dp
Array [] true 0 "" transparent 0dp
Map {} true 0 "" transparent 0dp
Color red true 0 "#ff0000ff" #ff0000ff 0dp
Dimension 32px true 16 "16dp" transparent 16dp
Dimension 0vh false 0 "0dp" transparent 0dp
Dimension 23% true 0.23 "23%" transparent 23%
Dimension 0% false 0 "0%" transparent 0%
Dimension auto true 0 "auto" transparent auto
Anything else ... true 0 "" transparent 0dp

Boolean coercion

A truthy value is a value that is considered true when evaluated in a boolean context. All values are truthy except for false, 0, "", a zero absolute or relative dimension, and null.

Number coercion

The Boolean "true" value is converted to the number 1. String values are converted using the C++ std::stod method (note that this is influenced by the locale). Absolute dimensions convert to the number of dp in the absolute dimension; relative dimensions convert to the percentage value (e.g., 32% -> 0.32). Everything else converts to 0.

String coercion

Internal types are converted to strings using the rules in the following table:

Object Example Result Description
Null null '' The null value is not displayed.
Boolean true false 'true' 'false' Boolean true & false are displayed as strings.
Number -23 '-23' Integers have no decimal places.
  1/3 '0.333333' Non-integers have decimal places.
String "My "dog" " 'My "dog" ' String values
Array [...] '' Arrays are not displayed.
Map {...} '' Maps are not displayed
Color red '#ff0000ff' Colors are shown in #rrggbbaa format.
Dimension 23 dp '20dp' Absolute dimensions are shown with the suffix 'dp'
Dimension 20 % '20%' Percentage dimensions are shown with the suffix '%'
Dimension auto 'auto' The auto dimension is shown as 'auto'
Anything else ${Math.min} '' Math functions are not shown.

The specific format of non-integer numbers is not defined, but should follow closely the C++ standard for sprintf(buf, "%f", value). It may change based on the locale.

Color coercion

Color values are stored internally as 32-bit RGBA values. Numeric values will are treated as unsigned 32-bit integers and converted directly. String values are parsed according to the rules in Data Types - Color.

Absolute dimension coercion

Numeric values are assumed to be measurements in "dp" and are converted to absolute dimensions. String values are parsed according to the rules in Data Types - Dimension. All other values are 0.

Relative dimension coercion

Numeric values are assumed to be percentages and are converted directly. For example, 0.5 converts to 50%. Strings are parsed according to the rules in Data Types - Dimension. All other values are 0.


APL supports different types of operators: arithmetic, logical, comparison, and ternary.

Arithmetic operators

The standard arithmetic operations for addition, subtraction, multiplication, division, and remainder are supported:

${1+2}  // 3
${1-2}  // -1
${1*2}  // 2
${1/2}  // 0.5
${1%2}  // 1.

Addition and subtraction work for pairs of numbers, absolute dimensions, and relative dimensions. When a number is combined with either an absolute or relative dimension, the number is coerced into the appropriate dimension.

The addition operator also acts as a string-concatenation operator if either the left or right operand is a string.

${27+''}     // '27'
${1+' dog'}  // '1 dog'
${'have '+3} // 'have 3'

Multiplication, division, and the remainder operator work for pairs of numbers. Multiplication also works if the one of the operands is a dimension (either relative or absolute) and the other is a number; the result is a dimension. Division also works if the first operand is a dimension (either relative or absolute) and the second is a number; the result is a dimension.

The remainder operator behaves as in JavaScript. That is,

${10 % 3}  // 1
${-1 % 2}  // -1
${3 % -6}  // 3
${6.5 % 2} // 0.5

Logical operators

The standard logical and/or/not operators are supported.

${true || false}   // true
${true && false}   // false
${!true}           // false

The && returns the first operand if it is not truthy and the second otherwise. The || operator returns the first operand if it is truthy and the second otherwise.

${7 && 2}    // 2
${null && 3} // null
${7 || 2}    // 7
${0 || -16}  // -16

Comparison Operators

Comparison operators return boolean values.

${1 < 2}
${75 <= 100}
${3 > -1}
${4 >= 4}
${myNullValue == null}
${(2>1) == true}
${1 != 2}

The comparison operators do not apply to arrays and objects.

Null coalescing

The ?? operator is the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right-hand operand. The null-coalescing operator may be chained:

${person.name ?? person.surname ?? 'Hey, you!'}

The null-coalescing operator will return the left-hand operand if it is anything but null:

${1==2 ?? 'Dog'}   // returns false
${1==2 || 'Dog'}   // returns 'Dog'

Ternary Operator

The ternary conditional operator ${a ? b : c} evaluates the left-hand operand. If it evaluates to true or a truthy value, the middle operand is returned. Otherwise the right-hand operand is returned.

${person.rank > 8 ? 'General' : 'Private'}

Array and Object access


Array access uses the [] operator, where the operand should be an integer. Arrays also support the .length operator to return the length of the array. Accessing an element outside of the array bounds returns null.

${myArray[4]}     // 5th element in the array (0-indexed)
${myArray.length} // Length of the array
${myArray[-1])}   // Last element in the array
${myArray[myArray.length]}  // Returns null (out of bounds)

Passing a negative index counts backwards through the array.

${a[-1] == a[a.length - 1]}  // True


Objects support the . operator and the [] array access operator with string values.

${myObject.name}    // The 'name' property of myObject
${myObject['name']} // The 'name' property of myObject

If the property is not defined, null is returned.

Calling the . or [] operator on null returns null.

${myNullObject.address.zipcode}  // Returns null

The right-side operand of the dot operator must be a valid identifier.

Function calls

Data-binding supports a limited number of built-in functions. Functions are of the form:

functionName( arg1, arg2, … )

Functions do not have to have arguments. A function returns a single value. Some functional expressions are shown here:

${Math.floor(1.1)}       // 1
${Math.ceil(1.2)}        // 2
${Math.round(1.2)}       // 1
${Math.min(1,2,3,4)}     // 1
${Math.max(1,2,3,4)}     // 4
${String.toUpperCase('Hello')}    // HELLO
${String.toLowerCase('Hello')}    // hello
${String.slice('Hello', 1, -1)}   // ell

Built-in functions

Some mathematical and string functions are built in to APL.

Property Description Example
Math.abs(x) Return the absolute value of x ${Math.abs(-2.3)} == 2.3
Math.acos(x) The arccosine of x ${Math.acos(1)} == 0
Math.asin(x) The arcsine of x ${Math.asin(0)} == 0
Math.atan(x) The arctangent of x ${Math.atan(1)} == 0.7853981633974483
Math.ceil(x) Return the smallest integer greater than or equal to x. ${Math.ceil(2.3)} == 3
Math.clamp(x,y,z) Return x if y<x, z if y>z, and otherwise y. ${Math.clamp(1, 22.3, 10)} == 10
Math.cos(x) The cosine of x ${Math.cos(0)} == 1
Math.floor(x) Return the largest integer less than or equal to x. ${Math.floor(2.3)} = 2
Math.max(x1,x2,…) Return the largest argument ${Math.max(2,3)} == 3
Math.min(x1,x2,…) Return the smallest argument ${Math.min(2,3)} == 2
Math.PI The value of PI 3.141592653589793
Math.random() A random number between 0 and 1 ${Math.random()} == 0.7113654073137101 (the actual random number returned will be different)
Math.round(x) Return the nearest integer to x ${Math.round(2.3)} == 2
Math.sign(x) The sign of x: -1, 0, or 1 ${Math.sign(-43.1) == -1}
Math.sin(x) The sine of x ${Math.sin(Math.PI/6)} == 0.5
Math.sqrt(x) The square root of x ${Math.sqrt(9)} == 3
Math.tan(x) The tangent of x ${Math.tan(Math.PI/4)} == 0.5
String.slice(x,y[,z]) Return the subset of x starting at index y and extending to but not including index z. If z is omitted, the remainder of the string is returned. If y is a negative number, select from the end of the string. ${String.slice('berry', 2, 4)} == 'rr' ${String.slice('berry', -2)} == 'ry'
String.toLowerCase(x) Return a lower-case version of x ${String.toLowerCase('bEn')} == "ben"
String.toUpperCase(x) Return an upper-case version of x. ${String.toUpperCase('bEn')} == "BEN"

Data-binding string conversion

Because APL is serialized in JSON, all data-bound expressions are defined inside of a JSON string:

  "MY_EXPRESSION": "${....}"

If there are no spaces between the quotation marks and the data-binding expression, then the result of the expression is the result of the data-binding evaluation. For example:

"${true}"               -> Boolean true
"${2+4}"                -> Number 6
"${0 <= 1 && 'three'}"  -> String 'three'

When extra spaces are in the string outside of the data-binding expression or when two data-binding expressions are juxtaposed, the result is a string concatenation:

" ${true}"     -> String ' true'
"${2+4} "      -> String '6 '
"${2+1}${1+2}" -> String '33'