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

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