Names in the Alexa Conversations Description Language
In Alexa Conversations Description Language (ACDL), you can declare names for expressions. Name declarations enable you to reuse expressions in the same or different ACDL files by referring to the declared name, instead of by repeating the corresponding expression.
The examples on this page use the following Person
type declaration.
type Person {
String firstName
String lastName
}
- Declare names
- Named expressions
- Fully qualified names
- Scope of a name declaration
- Name redeclaration
- Circular dependency
- Related topics
Declare names
Action declarations, type declarations, dialog declarations, and named expressions are all name declarations. In other words, they are given a name by using a 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 new names by using <name> = <expression>
syntax. You can only declare names without
the namespace qualifier, because names are always associated with the namespace declared in the corresponding file.
If a declaration is valid, the declared name is of the type of the expression used in the declaration. The following example shows how you give the name jane
to an expression that represents a Person
. In other words, you declare the name jane
to be of type Person
.
dialog Nothing MyDialog {
sample {
jane = Person { firstName = "Jane", lastName = "Doe" }
myAction(jane)
}
}
A name declaration is valid if the name conforms to the rules applicable to an identifier, and the expression is valid.
The following example declares jane
as the name of an invalid expression. The Person
type declaration has two required properties, firstName
, and lastName
, neither of which the expression includes.
dialog Nothing MyDialog {
sample {
jane = Person {} // This is invalid.
}
}
To correct the error, you must provide expressions for the Person
properties, firstName
, and lastName
, as shown previously.
You can't declare a name with an expression of type Nothing
. In the following example, nothing
is a literal, 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
...
}
}
When you use a previously declared name as the expression in the declaration of a new name, you're effectively declaring 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 the name prefixed by its namespace qualifier (that is, the name of the namespace that contains the declaration). In an ACDL file, you can refer to declarations from other namespaces by using the fully qualified name instead of by using an import
statement. Fully qualified names have a maximum length of 64 characters.
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 previous example to the following example, 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()
}
Scope of a name declaration
You declare every name in 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 the name throughout any file with the same namespace without using the namespace qualifier. However, if you declare a name within a narrower (block) scope, you can't reference the name outside the block.
In the following example, weatherEvent
is declared within a namespace scope, so you can reference it elsewhere in the same namespace scope without using its namespace qualifier. You can reference weatherEvent
in other namespace scopes by its fully qualified name or by importing it using an 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 and
referenced in the com.weatherbot.dialogs
namespace 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 the namespace scope doesn't matter. In the following example, the declarations of nameB
and nameA
are valid even though nameA
is declared after nameB
, because they are declared in the namespace scope.
namespace com.weatherbot.dialogs
nameB = nameA
nameA = "hello"
Block scope
A block scope spans the set of expressions declared within an expression block.
A name that you declare inside a block scope is visible from the point at which you declare the name until the end of that block. The block scope also inherits names declared in a higher-level scope. The namespace scope is the top-level scope and therefore all blocks inherit names declared in the namespace scope.
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 that you declare within a block scope aren't visible outside of that scope. In the following example, both declarations of weatherResult
are visible within the corresponding blocks, but referencing the name in the encompassing sample
block is not valid.
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 you can 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 isn't valid because weatherResponse
is previously declared at the namespace scope.
namespace com.weatherbot.dialogs
import com.amazon.alexa.conversations.MultiModalResponse
weatherResponse = MultiModalResponse {...}
dialog Nothing Weather {
sample {
...
weatherResponse = MultiModalResponse {...} // Invalid because weatherResponse is previously declared in the namespace scope
...
}
}
Similarly, the following example isn't valid because it's equivalent to redeclaring 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 dependency
ACDL doesn't allow circular dependencies between declarations. The compiler flags any circular dependencies as errors. An inadvertent circular dependency can occur between declarations in a namespace scope, because the order of declarations doesn't matter.
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