Names in the Alexa Conversations Description Language
In Alexa Conversations Description Language (ACDL), you can declare names for expressions. Name declarations let you reuse expressions in the same or different ACDL files by referring to the declared name, instead of repeating the corresponding expression.
The examples on this page use the following Person
type declaration.
type Person {
String firstName
String lastName
}
Name declaration
Action declarations, type declarations, dialog declarations, and named expressions are all name declarations. In other words, you give them a name when you make the declaration.
The name of the following action declaration is getWeather
.
action WeatherResult getWeather(US_CITY cityName, DATE, date)
The name of the following type declaration is Person
.
type Person {
String firstName
String lastName
}
The name of the following dialog declaration is Weather
.
dialog Nothing Weather {
...
}
Named expressions
You declare a new name with <name> = <expression>
syntax. You must declare the name without a namespace qualifier, because the name is always associated with the namespace declared in the corresponding file.
Valid expressions
A name declaration is valid if the name conforms to the rules applicable to an identifier, and if the expression is valid. If the declaration is valid, the declared name is of the same type as the expression used in the declaration. The following example shows you how to give the name jane
to an expression that represents a Person
. In other words, you declare the name jane
to be of the type Person
.
dialog Nothing MyDialog {
sample {
jane = Person { firstName = "Jane", lastName = "Doe" }
myAction(jane)
}
}
Invalid expressions
The following example declares the name jane
. This declaration, however, is part of an invalid expression. It's invalid because the Person
type declaration has two required properties, firstName
and lastName
, neither of which is included in this expression. To correct the error, you must supply both required Person
properties.
dialog Nothing MyDialog {
sample {
jane = Person {} // This is invalid.
}
}
You can't declare a name with an expression of type Nothing
. In the following example, nothing
is a literal and is the only possible value of type Nothing
.
myName = nothing // This is invalid
You also can't declare names for expressions that return the Nothing
type, as shown in the following example.
action Nothing setUserCityPreference(US_CITY userCity)
dialog MyDialog {
sample {
...
result = setUserCityPreference(cityName) // Invalid because setUserCityPreference returns Nothing
...
}
}
Name equivalents
When you use a previously declared name as the expression in a new name declaration, you essentially declare another name for the original expression. In the following example, both lane
and jane
are names of the same Person
expression.
dialog Nothing MyDialog {
sample {
jane = Person { firstName = "Jane", lastName = "Doe" }
lane = jane
// lane and jane are names of the same Person expression.
}
}
The following example is equivalent to the previous example. That is, lane
and jane
are names for the same expression.
dialog Nothing MyDialog {
sample {
jane = Person { firstName = "Jane", lastName = "Doe" }
lane = Person { firstName = "Jane", lastName = "Doe" }
}
}
Fully qualified names
A fully qualified name is one that includes its namespace qualifier as a prefix. In other words, the name's prefix is the name of the namespace that contains the declaration.
The following example shows how to use a fully qualified name.
namespace org.example.mydialog
sample {
//org.example.actions.getFirstName is a fully qualified name and can be used without an import declaration
firstName = org.example.actions.getFirstName()
}
Compare the preceding example to the following one, which uses an import
statement instead of a fully qualified name.
namespace org.example.mydialog
import org.example.actions.getFirstName
sample {
//getFirstName is imported above, so it can be referenced without the fully qualified name.
firstName = getFirstName()
}
In an ACDL file, you need not include an import
statement if you use a fully qualified name that refers to declarations from other namespaces. Fully qualified names have a maximum length of 64 characters.
Scope
You declare every name within a scope. The visibility of each name (that is, whether it can appear in an expression) depends on the scope in which you declare it. The following list shows the available scopes.
Namespace scope
The namespace scope is the top-level scope. If you declare a name at the top level, you can reference that name throughout any file in that namespace without using the namespace qualifier. If you declare a name within a narrower (block) scope, however, you can't reference the name outside the block.
In the following example, weatherEvent
is declared within a namespace scope. You can reference weatherEvent
elsewhere in the same namespace scope without a namespace qualifier. In other namespace scopes, you can reference it only by its fully qualified name or by using import
.
namespace com.weatherbot.dialogs
import com.amazon.alexa.conversations.expect
weatherEvent = utterances(..)
dialog Nothing Weather {
sample {
wr = expect(Invoke, weatherEvent)
}
}
In the following example, weatherEvent
is declared in the com.weatherbot.samples
namespace. In the com.weatherbot.dialogs
namespace, it's referenced by its fully qualified name, com.weatherbot.samples.weatherEvent
.
//file: WeatherSamples.acdl
namespace com.weatherbot.samples
import com.amazon.alexa.conversations.utterances
weatherEvent = utterances(..)
//file: Weather.acdl
namespace com.weatherbot.dialogs
import com.amazon.alexa.conversations.expect
dialog Nothing Weather {
sample {
wr = expect(Invoke, com.weatherbot.samples.weatherEvent)
}
}
The order in which you declare names in a given namespace scope doesn't matter. In the following example, nameB
and nameA
are declared in the same namespace scope. The declarations are valid, then, even though nameB
is declared before nameA
.
namespace com.weatherbot.dialogs
nameB = nameA
nameA = "hello"
Block scope
A block scope spans the set of expressions declared within an expression block.
When you declare a name inside a block scope, the name is visible from the point at which you declare it through the end of the block. In addition, a block scope inherits names declared at a higher level. The namespace scope is the top-level scope, so all blocks inherit the names declared at that level.
In the following example, weatherResponse
is scoped to the namespace, and weatherResult
is scoped to the
current block (the sample).
namespace com.weatherbot.dialogs
import com.amazon.alexa.conversations.response
import com.amazon.alexa.conversations.MultiModalResponse
weatherResponse = MultiModalResponse {apla = weatherPrompt}
dialog Nothing Weather {
sample {
weatherResult = getWeather(...)
response(weatherResponse, Notify {actionName = getWeather}, payload = WeatherPayload {result = weatherResult})
}
}
Names declared within a block scope aren't visible outside that scope. In the following example, both declarations of weatherResult
are visible within their respective blocks. However, weatherResult
is invalid when used in the sample
block that contains the declarations.
namespace com.weatherbot.dialogs
dialog Nothing Weather {
sample {
if (condition) {
weatherResult = getWeatherWithRainInfo(...)
} else {
weatherResult = getWeather(...)
}
result = weatherResult // Invalid because weatherResult is used outside the block where it's declared
}
}
The following valid example shows how to use weatherResult
within each block scope.
namespace com.weatherbot.dialogs
dialog Nothing Weather {
sample {
...
if (condition) {
weatherResult = getWeatherWithRainInfo(...)
result = weatherResult
...
} else {
weatherResult = getWeather(...)
result = weatherResult
..
}
}
}
Name redeclaration
You can't redeclare a name with the same scope or a narrower scope. The following example is invalid because weatherResponse
already exists within the namespace scope.
namespace com.weatherbot.dialogs
import com.amazon.alexa.conversations.MultiModalResponse
weatherResponse = MultiModalResponse {...}
dialog Nothing Weather {
sample {
...
weatherResponse = MultiModalResponse {...} // Invalid because weatherResponse already exists within the namespace scope.
...
}
}
Similarly, the following example is invalid because it redeclares the weatherResponse
imported from the namespace com.weatherbot.responses
.
namespace com.weatherbot.dialogs
import com.weatherbot.responses.weatherResponse
import com.amazon.alexa.conversations.response
dialog Nothing Weather {
sample {
...
weatherResponse = MultiModalResponse {...} // Invalid because weatherResponse is imported from another namespace
response(weatherResponse, ...)
}
}
Circular dependencies
ACDL doesn't allow circular dependencies between declarations. The compiler flags any circular dependencies as errors. You can make declarations out of order in ACDL, but this flexibility can produce unexpected circular dependencies between declarations in a given namespace.
A circular dependency can be direct or indirect. The following example shows a direct circular dependency (nameA -> nameB -> nameA
).
namespace org.example.mydialog
// This is invalid.
nameA = nameB
nameB = nameA
The following example shows an indirect circular dependency (nameA -> nameB -> nameC -> nameA
).
namespace org.example.mydialog
// This is invalid.
nameA = nameB
nameB = nameC
nameC = nameA
Related topics
- Types in the Alexa Conversations Description Language
- Namespaces in the Alexa Conversations Description Language
- Get Started with the Alexa Conversations Description Language
Last updated: Nov 27, 2023