Supporting Literal Initialization for Custom Types in Swift
What are Swift Literals and how do they work?
In this iOS guide, I am going to explain Swift literals, and I am going to reinforce the following topics by giving examples in order.
- What are the Swift literals?
- How do they work?
- Standard literals
- Literal initialization for custom types
What Are the Swift Literals?
Literals are digits of characters that describe constant values to be stored in properties. Literals are used to initialize or assign value to variables or constants.
How Do They Work?
In the Swift standard library, type aliases of primitive types are created. Whenever we assign any value to a variable with no type information, Swift uses those type aliases to determine what type to use for the expression.
Standard Literals
A literal is a representation of a value in source code, such as a number or a string.
Swift provides the following kinds of literals:
ExpressibleByArrayLiteral
ExpressibleByDictionaryLiteral
ExpressibleByIntegerLiteral
ExpressibleByFloatLiteral
ExpressibleByBooleanLiteral
ExpressibleByNilLiteral
ExpressibleByStringLiteral
ExpressibleByExtendedGraphemeClusterLiteral
ExpressibleByStringInterpolation
Let’s explain them step by step together with short examples.
1. ExpressibleByArrayLiteral
Declaration as a protocol:
associatedtype ArrayLiteralElement
The type of the elements of an array literal:
protocol ExpressibleByArrayLiteral
An array literal is a simple way of expressing a list of values. Simply surround a comma-separated list of values, instances, or literals with square brackets to create an array literal. You can use an array literal anywhere an instance of an ExpressibleByArrayLiteral type is expected: as a value assigned to a variable or constant, as a parameter to a method or initializer, or even as the subject of a nonmutating operation like map(_:) or filter(_:).
Arrays, sets, and option set all conform to ExpressibleByArrayLiteral, and your own custom types can as well. Here’s an example of creating a set and an array using array literals:
1.1 Type inference of array literals
Whenever possible, Swift’s compiler infers the full intended type of your array literal. Because Array
is the default type for an array literal, without writing any other code, you can declare an array with a particular element type by providing one or more values.
In this example, the compiler infers the full type of each array literal.
2. ExpressibleByDictionaryLiteral
Declaration as a protocol.
associatedtype Key
The key type of a dictionary literal.
associatedtype Value
The value type of a dictionary literal.
protocol ExpressibleByDictionaryLiteral
A dictionary literal is a simple way of writing a list of key-value pairs. You write each key-value pair with a colon (:
) separating the key and the value. The dictionary literal is made up of one or more key-value pairs, separated by commas and surrounded with square brackets.
To declare a dictionary, assign a dictionary literal to a variable or constant:
3. ExpressibleByIntegerLiteral
Declaration as a protocol.
associatedtype IntegerLiteralType
A type that represents an integer literal.
protocol ExpressibleByIntegerLiteral
The standard library integer and floating-point types, such as Int
and Double
, conform to the ExpressibleByIntegerLiteral
protocol. You can initialize a variable or constant of any of these types by assigning an integer literal.
4. ExpressibleByFloatLiteral
Declaration as a protocol.
associatedtype FloatLiteralType
A type that represents a floating-point literal.
protocol ExpressibleByFloatLiteral
The standard library floating-point types — Float
, Double
, and Float80
where available—all conform to the ExpressibleByFloatLiteral
protocol. You can initialize a variable or constant of any of these types by assigning a floating-point literal.
5. ExpressibleByBooleanLiteral
Declaration as a protocol.
associatedtype BooleanLiteralType
A type that represents a Boolean literal, such as Bool
.
protocol ExpressibleByBooleanLiteral
Bool
, DarwinBoolean
, ObjCBool
, and WindowsBool
are treated as Boolean values. Expanding this set to include types that represent more than simple Boolean values is discouraged.
To add ExpressibleByBooleanLiteral
conformance to your custom type, implement the init(booleanLiteral:)
initializer that creates an instance of your type with the given Boolean value.
6. ExpressibleByNilLiteral
Declaration as a protocol.
protocol ExpressibleByNilLiteral
nil
has a specific meaning in Swift—the absence of a value. Only the Optional
type conforms to ExpressibleByNilLiteral
. ExpressibleByNilLiteral
conformance for types that use nil
for other purposes is discouraged.
7. ExpressibleByStringLiteral
Declaration as a protocol.
associatedtype StringLiteralType
A type that represents a string literal.
protocol ExpressibleByStringLiteral
The String
and StaticString
types conform to the ExpressibleByStringLiteral
protocol. You can initialize a variable or constant of either of these types using a string literal of any length.
8. ExpressibleByExtendedGraphemeClusterLiteral
Declaration as a protocol.
associatedtype ExtendedGraphemeClusterLiteralType
A type that represents an extended grapheme cluster literal.
protocol ExpressibleByExtendedGraphemeClusterLiteral
An extended grapheme cluster is a group of one or more Unicode scalar values that approximates a single user-perceived character. Many individual characters, such as “é”, “김”, and “🇮🇳”, can be made up of multiple Unicode scalar values. These code points are combined by Unicode’s boundary algorithms into extended grapheme clusters.
The String
, StaticString
, and Character
types conform to the ExpressibleByExtendedGraphemeClusterLiteral
protocol. You can initialize a variable or constant of any of these types using a string literal that holds a single character.
9. ExpressibleByStringInterpolation
Declaration as a protocol.
associatedtype StringInterpolation
The type each segment of a string literal containing interpolations should be appended to.
protocol ExpressibleByStringInterpolation
Use string interpolation to include one or more expressions in a string literal, wrapped in a set of parentheses and prefixed by a backslash. For example:
Literal Initialization for Custom types
If you have a custom type like below struct you can initialize as literal.
For example, I will define CustomInteger struct.
And you can implement ExpressibleByIntegerLiteral
protocol to Date class as an extension. It will be more useful.
Conclusion
Swift contains a group of ExpressibleByLiteral
protocols that are used for custom types to be initialized with a matching literal.
Supporting initialization by literals when appropriate can significantly improve the ergonomics of custom types, making them feel like they’re built-in.
Initialization with Literals can make your Swift code more clean and direct.
Thanks for reading!