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 theOptional
type conforms toExpressibleByNilLiteral
.ExpressibleByNilLiteral
conformance for types that usenil
for other purposes is discouraged.
Facts
- The description of this API doc does not discourage the use of
ExpressibleByNilLiteral
for the purpose of usingnil
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 removingExpressibleByNilLiteral
completely. - There are only two types in the standard library that conform to
ExpressibleByNilLiteral
:Optional
andImplicitlyUnwrappedOptional
.
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.