Types
Scowl is a statically-typed language. The data type of every feature is known at compile-time. The compiler will catch type errors and prevent an invalid topology from being deployed.
Basic Types
Scowl supports the following basic types:
Type | Example #1 | Example #2 |
---|---|---|
bool |
true |
false |
int |
5 |
-7 |
float |
4.2 |
-3.0 |
string |
"hello" |
'World🌎' |
time |
Time("June 26, 2011") |
FromUnixSeconds(100000) |
Nullability
In Scowl, all types are treated as nullable. Hence, null
is considered a valid
value of each type. To create a null value of a specific type:
Type | Null Constructor |
---|---|
bool |
Bool(null) |
int |
Int(null) |
float |
Float(null) |
string |
String(null) |
time |
Time(null) |
Besides literal nulls, the primary way null values are introduced is by way of a missing or null JSON input. See Optional Inputs for details on how these values are handled.
Number Promotion
Many common transformations combine int
and float
values together. Scowl makes it easy
to work with numbers without requiring explicit promotion.
When an int
value needs to be promoted to a float
for the operation to be valid, Scowl will do so automatically.
Expression | Result |
---|---|
1 + 1.0 |
2.0 |
Maximum(3, 2.0) |
3.0 |
Complex Types
Scowl supports array, struct, and map complex data types.
Array
An array is a list type with elements accessed by index.
Expression | Result Type |
---|---|
[1, 2, 3] |
[int] |
[4.0, null, 6.0] |
[float] |
["hello"] |
[string] |
To access elements of an array by index, use the ArrayIndex and ArraySlice operators.
To determine the length of an array, use the Len
function.
Struct
A struct is a record type with named fields.
Expression | Result Type |
---|---|
{lat: 34.0901, lng: -118.4065} |
{lat: float, lng: float} |
{foo: 5, bar: "six", baz: false} |
{foo: int, bar: string, baz: bool} |
{now: EventTime()} |
{now: time} |
To access fields of a struct by name, use the .
operator:
Expression | Result |
---|---|
geo.lng |
34.0901 |
my_struct.bar |
"six" |
time_val.now |
2022-03-17T12:20:25.645035-05:00 |
Attempting to access a non-existent field raises a compile-time error.
Map
A map is a dictionary type with string-indexed elements.
Expression | Result Type |
---|---|
map{"lat": 34.0901, "lng": -118.4065} |
map{string: float} |
map{"now": EventTime(), "later": null} |
map{string: time} |
map{"foo": 5, "bar": "six"} |
error: all elements must be the same type |
Note that string
is the only map key type currently supported. For future-compatibility,
the key type is explicitly represented in the map
type.
To access fields of a struct by name, use the []
operator:
Expression | Result |
---|---|
geo['lng'] |
34.0901 |
time_val["now"] |
2022-03-17T12:20:25.645035-05:00 |
Attempting to access a missing element raises a run-time error.
Nesting Types
Complex types may be arbitrarily nested inside each other:
For example, the following expression:
map{
"science fiction": [
{
author: "Weir, Andy",
title: "Project Hail Mary"
},
{
author: "Adams, Douglas",
title: "Hitchhiker's Guide to the Galaxy"
}
],
"historical fiction": [
{
author: "Pressfield, Steven",
title: "Gates of Fire"
}
]
}
has the Scowl type:
map{string: [{author: string, title: string}]
User-Defined Types
Basic and complex types may be assigned to a named identifier to be reused elsewhere in the code, e.g.:
type degrees float
type geopoint {lat: degrees, lng: degrees}
type customer {
name: string,
billing_geo: geopoint,
shipping_geo: geopoint
}
JSON Input
The primary use case for user-defined types is code reuse in JSON Input features.
User-defined type specifications may include Optional designations and Default Values, e.g.:
type address {
street: string,
city: string,
state: string?, -- state is optional
zip: int? -- zip is optional
}
billing_address := $.billing as address
shipping_address := $.shipping as address? -- shipping address is optional
Scope
Regardless of whether a type
definition appears inside or outside an event
scope,
the type has global scope. It is available to be used across the entire
Scowl program, in any event's feature definitions.
Type Inference
Scowl is able to infer the type of nearly every expression without the need to specify any explicit types.
For example:
foo := 1 + 1 -- infers foo is an int
bar := "hello" + "world" -- infers bar is a string
baz := Maximum(3, 2.0) -- infers baz is a float
Besides null literals, the only time a user must declare a data type explicitly is in a JSON input variable. See JSON Input section.
Inspecting Type
To fetch a string-valued representation of a feature's type, you can use
the Type
function.