Background
From API docs:
ExpressibleByNilLiteral
A type that can be initialized using the nil literal, nil.
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.
Facts
- The description of this API doc does not discourage the use of
ExpressibleByNilLiteral for the purpose of using nil to represent the absence of a value.
ExpressibleByNilLiteral is a public API without any underscore to discourage the use.
- Pointer types used to be
nil-convertible, and SE-0055 changed this and had discussions about removing ExpressibleByNilLiteral completely.
- There are only two types in the standard library that conform to
ExpressibleByNilLiteral: Optional and ImplicitlyUnwrappedOptional.
Problems
The Python interop library made PythonObject expressible by integer literal, float literal, boolean literal, string literal and array literal. This enables the following:
let x: PythonObject = true
// Python: x = [True]
let y: PythonObject = [true, false, 1, 2.1, []]
// Python: y = [True, False, 1, 2.1, []]
True and False are Python constant objects. PythonObject is made expressible by boolean literal because it is nice syntactic sugar, and True and true are semantically the same.
There's another common constant object: None. According to Python's official documentation, None represents the absence of a value. This is exactly the same as the meaning of nil in Swift, according to the Swift documentation. So, is it reasonable to make PythonObject conform to ExpressibleByNilLiteral? If so, this would enable the following:
let array: PythonObject = [1, nil, true, 2.1]
// Python: array = [1, None, True, 2.1]
However, this may introduce confusion, for example:
var dict: [String : PythonObject] = ...
dict["x"] = nil
In this case, it is possible that while the user is referring to Python's None, they are actually removing a value from the dictionary.
Some would argue that nil literal conversion should only be used for Optional, ImplicitlyUnwrappedOptional and _OptionalNilComparisonType, as this was also mentioned in SE-0055.
If so, why is ExpressibleByNilLiteral still a public API and should we consider removing it or prepending an underscore to it? If not, when does conforming to ExpressibleByNilLiteral make sense?
This purpose of this post is to kick off a discussion about the purpose of ExpressibleByNilLiteral as a public API.