- 2.1 – Type system
- 2.2 – Simple types
- 2.3 – Collection types
- 2.4 – Functional types
- 2.4.1 – Parsing complex types
- 2.5 – Type conversion
This chapter describes how DeltaScript handles types and their values.
A type is a classification that specifies the kind of value a variable can hold and the operations that can be performed on it. In programming languages, types are used to enforce constraints on the values that can be represented by expressions§4, ensuring that operations on these expressions and their values are semantically correct.
A sequence of characters written in the code to refer to a type is known as a type identifier. For example, the type identifier for an integer is int, while the type identifier for a set of characters is char{}.
Types in DeltaScript can be broadly categorized into three main groups: simple types§2.2, collection types§2.3, and functional types§2.4.
DeltaScript is type-safe and statically typed, meaning that type checking§7.3 is performed at compile-timea rather than at runtime. This ensures that type errors are caught early in the development process, leading to more reliable and maintainable code.
While DeltaScript requires explicit type declarations in many cases, it also supports type inference in certain contexts. This allows the language to deduce the type of a variable or expression based on the context in which it is used, reducing the need for redundant type annotations.
An example of this is in iterator loops§5.7.4. The iterator variable can be declared without a type, as its type can be inferred from the collection.
Example 1:
() { string aretharized = ""; for (letter in "RESPECT") aretharized += letter + "."; print(aretharized); }The iterator variable
letteris inferred to be of typechar, because the collection is astring.
Example 2:
() { color[] cs = [ #ff0000, #28283c, rgba(169, 75, 0x80, 0x3b) ]; for (c in cs) print("Value: " + value(c)); } value(color c -> int) -> max([ c.red, c.green, c.blue ])This script calculates the value
of each color in the array
cson an integer scale from 0 to 255. The iterator variablecis inferred to be of typecolor, because the collection is an array of colorscolor[].
The type system in DeltaScript is designed to be extensible, allowing for the addition of new types§8.3.1 and the extension of built-in types§8.3.2 through language extensions. This makes DeltaScript highly adaptable to various application domains and use cases.
Simple types are types whose identifiers consist of a single word and no punctuation. These types are simple in contrast to collection types and functional types, which are considered complex. Simple types comprise built-in
types like bool and int, as well as new types defined by extensions to DeltaScript§8.3.1.
The following simple types are built into the base language
:
bool- one of two possible truth values
: true or falsechar- a UTF-8
charactercolor- a 32-bit RGBA color
float- a 64-bit (double precision) floating-point number
image- a bitmap
; a matrix
of pixels represented as colorsint- a 32-bit signed integer
string- a sequence of zero or more characters
Simple types can be further subdivided into primitive types and composite types.
Primitive types (bool, char, float, and int) represent primitive data values; they cannot be broken down into smaller units.
Composite types (image, string) represent objects
, which are composed of multiple primitive data values. Objects have mutable states, meaning their internal data can change without altering the object's identity. For example, an object of the type image can have one of its pixels change color without becoming a different image object. Extension types are also usually composite.
Many composite types also define member functions§6.3.5 and properties
. The member functions and properties of the built-in composite types are detailed in DeltaScript's standard library.
color does not fall neatly into either category. Fundamentally, color represents a 32-bit integer. However, the type defines additional behaviours in the form of properties that give it the characteristics of a composite type.
Collection types represent collections of elements. They allow for the storage and manipulation of multiple values in a structured manner.
A collection's elements must all be of the same typeb. A collection's elements mustn't be of a simple type; functions and collections themselves can also be grouped into collections.
The basic collection types in DeltaScript are arrays, lists, and sets. Each of these collection types contains elements of a single type, and is constrained by different rules determining how its elements can be accessed, arranged, added, or removed.
Maps, also known as dictionaries, are a special type of collection that represent associations between keys and values.
The member functions of collection types are detailed in the standard library.
An array is an ordered collection of fixed length
.
Ordered means that elements in an array are arranged in a certain order, and that individual elements can be accessed via their index - their position in the array. DeltaScript uses zero-based numbering
, which means that the initialc element in an ordered collection has an index of 0.
Example:
() { int[] squares = [ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ]; print(squares[0]); // prints "1" print(squares[1]); // prints "4" print(squares[9]); // prints "100" }
Fixed length means that an array can neither grow, nor shrink. It will always have the same number of allocated elements, even if some indices do not contain elements.
Arrays are represented by square brackets []. An array of elements of an arbitrary type T would be declared with the type identifier T[].
Like an array§2.3.1, a list is an ordered collection. However, unlike an array, the size
of a list is dynamic. This means that it can grow and shrink: elements can be added and removed.
Lists are represented by angle brackets []. A list of elements of an arbitrary type T would be declared with the type identifier T<>.
Like a list, a set is a collection of dynamic size. However, unlike a list, a set is unordered. Elements in a set have no order, and thus cannot be retrieved from an index.
Unlike arrays and lists, each element in a set
is unique; a set cannot contain two elements of the same value or object.
Sets are represented by curly brackets / braces {}. A set of elements of an arbitrary type T would be declared with the type identifier T{}.
A map, or dictionary, is a collection of associations, or mappings, between keys and values. Like lists and sets, the size of a map is dynamic. They are also unordered. A value can be retrieved from the map by providing the corresponding key.
Maps are represented by curly brackets / braces and a colon separating their key and value types. A map of keys of an arbitrary type K and values of an arbitrary type V would be declared with the type identifier {K:V}.
Functional types represent value-returning functions§6.2.1, including both named helper functions and anonymous functions. They enable the definition and invocation of reusable code blocks.
Functional type identifiers consist of optional comma-separated parameter types, followed by an arrow, followed by a return type, all enclosed in parentheses. A functional type with the arbitrary parameter types P1, P2, etc. and the arbitrary return type R would be declared with the type identifier (P1, P2, ... -> R).
Examples:
(int -> string)- a function that accepts an integer as a parameter and returns a string(float, float -> bool)- a function that accepts two floating-point numbers as parameters and returns a boolean(-> int)- a function with no parameters that returns an integer((float -> int), float[] -> int[])- a function that accepts a floating-point number to integer function and an array of floating-point numbers as parameters and returns an array of integers
Planned:
Future language versions may support functional types for void functions§6.2.2.
It is important for DeltaScript programmers to be able to parse complex type identifiers§2.1 in order to correctly conceptualize what they represent.
In these examples, the "outermost" type is bolded:
int[]- an array of integerschar{}[]- an array of sets of characterschar[]{}- a set of arrays of characters{string:int}<>- a list of maps mapping strings to integers{bool[]:bool}- a map mapping arrays of booleans to booleans(float, float -> int)[]- an array of functions that accept two floating-point numbers as parameters and return integers(int, int, bool -> int[])- a function that accepts an integer, an integer, and a boolean as parameters and returns an array of integers
Type conversion is when a value of a certain type is converted to a correspondent value of another type, either implicitly or explicitly.
DeltaScript supports both implicit and explicit type conversion. Implicit type conversion occurs automatically when it is safe to do so, while explicit type conversion (casting) requires the programmer to specify the desired type. Type conversion is not universal; only certain types can be converted to certain other types.
These are all the type conversions that are possible in DeltaScript:
| From | To | Value conversion |
|---|---|---|
bool |
string |
true values converted to "true", false values to "false" |
char |
int |
Converts a character to its Unicode decimal (base-10) value |
char |
string |
Converts a character to the equivalent one-character string |
float |
int |
Truncates a float to its integer component |
float |
string |
Represents a float as a string in decimal point notation |
int |
char |
Derives a character from its Unicode decimal value |
int |
float |
Trivial |
int |
string |
Trivial |
Implicit type conversion usually occurs when operands of different types are operated on by a (binary) operator§4.5.2.
Example:
() { print(27.25 + 12); // prints "39.25" }The operand
27.25is afloat, and the operand12is anint. Before this addition operation is performed,12is converted to the equivalentfloat(12f/12.0). That way, the operation is an addition offloatrather than an addition ofint. An addition offloatpreserves the fractional component of27.25(0.25), which would have been truncated had27.25been converted into an integer (27) instead.
Any value of any type can be implicitly converted to a string value.
Explicit type conversion, or casting, is when a programmer specifies in the source code that the value of an expression should be converted to another type. This is achieved with a cast expression§4.6, where the desired type is enclosed in parentheses before the expression whose value is to be converted.
Example:
() { print((int) 27.25 + 12); // prints "39" }The precedence of the expression
(int) 27.25 + 12looks like this:((int) 27.25) + 12. The cast operation is performed first; thefloat27.25is truncated to anintwith a value of27. Now, as both operands of the addition operation (27and12) areint, the operation is an addition ofint.
- a - The term "compile-time" is used here, however, depending on the language implementation, DeltaScript code may be either compiled or interpreted. Either way, type checking is performed prior to runtime – the execution of the script.
- b - This applies to arrays, lists, and sets. Maps/dictionaries have two element types: one for keys and one for values. All keys in a map must be of the same type, and all values must be of the same type. However, keys and values mustn't be of the same type.
- c - Because the ordinal number "first" doesn't correspond with the index 0, some people refer to the initial element of an ordered collection in a zero-based language as the "zeroth" element. However, this specification uses "first" to mean initial, i.e. at index 0.