Bixby Developer Center

Guides

Using Expression Language

Bixby's Expression Language (EL) allows you to work with your capsule's concepts and actions in layouts, strategies, and dialogs by using simple expressions.

Here's an example of a simple layout including Expression Language:

layout {
mode (Summary)
match: Recipe (this)
content {
section {
title {
template ("#{value(name)}")
}
content {
if (exists(totalTime)) {
single-line {
text {
value ("Total Time: #{value(totalTime)} minutes")
}
}
}
if (exists(recipe.servings)) {
single-line {
text {
value ("Servings: #{value(servings)}")
}
}
}
}
}
}
}
  • The match pattern binds the value of Recipe to the variable this. Many EL functions that access slots (properties on a concept or inputs on an action) will look for them on this if no variable is specified.
  • Slots of this are accessed with the . operator, as seen in this.name.
  • The function exists(totalTime) is used to check whether the slot this.totalTime has a value. If the match expression had bound Recipe to a name other than this, it would need to be explicitly specified here. So, if the match pattern had been Recipe (r), we would have had to use˙ exists(r.totalTime).
  • EL is embedded in strings with the #{} notation: #{value(totalTime)} returns the value of this.totalTime.

Functions

Expression Language includes functions for testing node values, formatting them in a variety of ways in templates, working with geospatial information, and more. For a full list of EL functions, read the Expression Language Reference.

Operators

EL provides a set of typical operators you can use in expressions for comparisons, mathematics, and logic.

  • Arithmetic: +, -, *, /, % (modulo division), div, mod, unary -
  • Logic: and, &&, or, ||, not, !
  • Comparisons: ==, eq, !=, ne, <, lt, >, gt, <=, le, >=, ge.
  • Empty: The empty prefix operator can be used to determine whether a value is null or empty.
  • Ternary conditional: A ? B : C. Evaluate to B if A is true, otherwise evaluate to C. A shorthand equivalent to if (a) then return b else return c.

Comparisons can be made against other values or against Boolean, string, integer, or floating-point literals.

if (size(legs) == 1) {
template ("Nonstop")
} else {
template ("#{integer(size(legs) -1)} stops")
}

Here is a more complex example that uses logic, comparisons, and ternary conditionals:

template("#{value(info.Prop1)} #{(exists(info.Prop1Val) && info.Prop1Val > -1 ? info.Prop1Val : 'empty')}")

The ternary conditional in this example is specifically this statement: exists(info.Prop1Val) && info.Prop1Val > -1 ? info.Prop1Val : 'empty'. The entire template will print both the value of info.Prop1 and info.Prop1Val, if info.Prop1Val exists and has a value greater than -1. The template will print just info.Prop1 otherwise. This is a convenient way to have a template dynamically print information.

Accessors

A slot can be either of the following:

  • A property of a concept, such as the sum property on the RollResult concept in the Dice sample capsule in the Quick Start Guide.
  • An input on an action.

Slots can be accessed in one of two ways:

  • The . operator: node.slot
  • The [ ] operator: node['slot']
if (this.description == 'NoMatchedAlarm') {
// description slot on the node bound to "clock" is equal to 'NoMatchedAlarm'
}

You can also use the . operator to refer to symbol values in enums. In this example, textposition is an enum:

image-card {
aspect-ratio (4:3)
image-url ("[#{value(param.image.url)}]")

// either
text-position (Overlay) // can only be one of the allowed values [Below, Overlay]

// or
text-position {
if (param.textposition == 'cover') {
value (Overlay) // can only be one of the allowed values [Below, Overlay]
} else {
value (Bottom) // can only be one of the allowed values [Below, Overlay]
}
}
Caution

The bracket operator for accessors should be used with single-quoted strings rather than double-quoted strings.

Do: value(this['property'])

Don't: value(this["property"])

EL in Bixby Language

Expression Language can be used with certain keys: match patterns, conditionals such as if blocks, and inside strings. In addition, the values returned by EL expressions can be bound using the $expr() construct.

In this example, moon.MoonPhase is bound to this, and the name property is accessed with the . operator:

match: moon.MoonPhase (this)
if (exists(this.name) && this.name == 'New Moon') {
...
}

In this example, #{} is used to inject an EL expression into advice:

match: time.DateTime (time)
advice ("#{isPast(time) ? 0.1 : 0.9}")
Note

You might see EL embedded in strings using either #{} or ${}. The first form is similar to Ruby's ERB and other template languages; the second form is the Unified Expression Language standard. There is no difference in functionality between the two forms.

Lastly, this code example binds time.Date to date and the output of the moon.GetMoonPhaseDate action to action, and uses both of them in a dialog macro expression.

match: time.Date (date) {
from-output: moon.GetMoonPhaseDate(action)
}
...
expression("The next #{value(action.moonName)} is on #{value(date)}")

The $expr() construct takes an EL expression as an argument and returns its value. This can be used in a typed or untyped form. This example, from the sample transactional capsule, comes from the GetSize constructor action:

action (GetSize) {
type (Constructor)
collect {
input (size) {
type(Size)
min(Required)
max(One)
plan-behavior (Never)
prompt-behavior (AlwaysSelection)
//Lists all available options
default-init {
intent {
goal: Size
value-set: Size { Size(ExtraSmall) Size(Small) Size(Medium) Size(Large) Size(ExtraLarge) }
}
}
}
}
output (PromptedSize) {
evaluate { $expr(size) }
}
}

View master on GitHub

The typed expression form of $expr() lets you coerce the returned value to a specific concept. For instance, the following view coerces the value of query to be a location.SearchTerm:

input-view {
match: DestinationPoint

message ("Where would you like to go?")

render {
macro (location:Autocomplete) {
param (noResultText) {
dialog-template ("No results")
}
param (placeholder) {
dialog-template ("Search for locations")
}
select-button-text {
template ("Ok")
}
}
}
}

View master on GitHub

Special EL Variables

There are several variables available in EL that can be used to access contextual information about the user and device.

Suppose you wanted to set a concept's value to the user's current location. You could set a myLocation concept to that value by creating an action file that takes this computed-input block:

computed-input (myLocation) {
min (Required) max(One)
type (geo.CurrentLocation)

compute {
if (exists($user.currentLocation)) {
intent {
goal: geo.CurrentLocation
value-set: geo.CurrentLocation { $expr($user.currentLocation) }
}
}
}
}
Note

Your capsule will need to request the device-location-access permission to be able to access the user's CurrentLocation. For more information, read the Grant Capsule Permissions Developers' Guide.

For a list of special EL variables, read the Expression Language Reference.

EL and Bixby Developer Studio

Bixby Developer Studio will highlight Expression Language constructs when they appear in Bixby Language files, and provide real-time validation.