Using string alias
string-alias
is a type alias annotations for feature variables in the feature manifest language. It defines a named set of strings which can be used and validated elsewhere in the feature manifest.
It is named as a special case of typealiasing found in many languages.
typealias QueryName = String
val queries = mapOf<QueryName, String>()
In this kotlin example above, we are able to use QueryName
wherever we're able to use String
, and vice versa: there is nothing else linking QueryName
with queries
.
string-alias
defines a named set of valid strings
In FML, the string-alias
belongs to the variable definition.
queries:
string-alias: QueryName
type: Map<QueryName, String>
default:
ALWAYS: 'true'
Here, QueryName
is defined as the set of String
s that are keys in the queries
map.
In the example above, we're defining a map of named queries. The default has one entry in.
Where QueryName
is used again, its value is checked against this membership test, by the FML:
available-if:
type: QueryName
default: ALWAYS
Note that had the queries
map been empty, we could not have provided a default value for available-if
.
Now that the QueryName
string-alias has been defined, it can be used in conjunction with any structural type definition for example:
available-if:
type: Option<QueryName>
default: null
This means that available-if
can be either a valid QueryName
or null
.
available-if:
type: List<QueryName>
default: []
This means that available-if
can be a list of valid QueryName
strings.
The named set is used to validate strings by experimenter
Over time, the number of queries can grow in the FML:
queries:
string-alias: QueryName
type: Map<QueryName, String>
default:
ALWAYS: 'true'
USER_RECENTLY_INSTALLED: days_since_install < 7
USER_EN_SPEAKER: 'en' in locale
USER_DE_SPEAKER: 'de' in locale
Defining QueryName
allows experimenter to validate a feature configuration before it reaches the application:
{
"available-if": [
"USER_RECENTLY_INSTALLED",
"USER_ES_SPEAKER"
]
}
In the above example, experimenter shows the user an error:
Invalid value "USER_ES_SPEAKER" for type QueryName; did you mean one of "ALWAYS", "USER_DE_SPEAKER", "USER_EN_SPEAKER" or "USER_RECENTLY_INSTALLED"?
The named set can be added to by FML authors or experiment owners
This can be fixed by adding a query to the queries
map in the FML file or the user can add it directly in the feature configuration:
{
"queries": {
"USER_ES_SPEAKER": "'es' in locale"
},
"available-if": [
"USER_RECENTLY_INSTALLED",
"USER_ES_SPEAKER"
]
}
Defining the named set of valid strings
We've seen how a string-alias can be used, and how QueryName
was defined as a key in a map.
The valid set of strings can be defined by any existing structural types. Some contrived examples follow:
surfaces:
type: List<SurfaceName>
string-alias: SurfaceName
default: []
Any use of SurfaceName
must be contained in the list of surfaces
. This may be used as an alternative to an enum, used in a library, but whose variants are defined in an app, thereby breaking the compile-time dependency from library to app.
experiment-slug:
type: ExperimentSlug
string-alias: ExperimentSlug
default: '{experiment}'
Any use of ExperimentSlug
must be the default value. In conjunction with an Option<>
at the usage site, this lets us specify either an exact value or null
.
For completeness, the string alias named set can be defined as:
MyStringAlias
: a single valueMap<MyStringAlias, _>
: keys in a mapMap<_, MyStringAlias>
: values in a mapList<MyStringAlias>
: items in a listOption<MyStringAliase>
: an optionMap<_, List<StringAlias>>
: combinations of these structural types.
Only one string-alias can be defined per feature variable. The following– using one variable to define two named sets of strings– is not possible at this time.
available-events:
string-alias: EventCategory, EventName
type: Map<EventCategory, List<EventName>>
String aliases can be used in nested objects
features:
my-onboarding-feature:
variables:
queries:
type: Map<QueryName>
string-alias: QueryName
default: {}
cards:
type: Map<CardKey, CardData>
string-alias: CardKey
objects:
CardData:
fields:
exclude-if:
type: List<QueryName>
default: []
include-if:
type: List<QueryName>
default: []
String-alias can only be defined in a feature variable. The object can only be used, directly or indirectly, by a feature which defines the string-aliases it uses.