It's singled out as specifically not allowed, but I can't find rationale. Is there any explicit, specific mention of the reason for this?
Swift prevents some operators from being defined because they would otherwise conflict with existing language features:
&
is reserved for inout
arguments!
is reserved for optional unwrapping?
is reserved for optional chaining?
is reserved for the ternary operator<
and postfix >
are reserved for defining generic argument lists=
is reserved unconditionally for assignment?
and unconditional ->
are reserved, but not actually used in the languageI'm not sure if this is explicitly documented anywhere, but I tend to search through the compiler source for this sort of thing.
If you try to compile
// Test.swift
prefix operator <
the compiler will error:
error: cannot declare a custom prefix '<' operator
prefix operator <
^
We can use the message to find where this error comes from in the Swift compiler: searching for "cannot declare a custom"
in the source code brings up a result in DiagnosticsSema.def
(where diagnostic messages from the semantic validation stage of the compiler are written):
ERROR(redefining_builtin_operator,none,
"cannot declare a custom %0 '%1' operator", (StringRef, StringRef))
Searching redefining_builtin_operator
then brings up two hits in AttributeChecker::checkOperatorAttribute
, each following a check for isBuiltinOperator
.
isBuiltinOperator
itself then gives us the above list of reserved operators:
/// Return true if this is a builtin operator that cannot be defined in user
/// code.
static bool isBuiltinOperator(StringRef name, DeclAttribute *attr) {
return ((isa<PrefixAttr>(attr) && name == "&") || // lvalue to inout
(isa<PostfixAttr>(attr) && name == "!") || // optional unwrapping
// FIXME: Not actually a builtin operator, but should probably
// be allowed and accounted for in Sema?
(isa<PrefixAttr>(attr) && name == "?") ||
(isa<PostfixAttr>(attr) && name == "?") || // optional chaining
(isa<InfixAttr>(attr) && name == "?") || // ternary operator
(isa<PostfixAttr>(attr) && name == ">") || // generic argument list
(isa<PrefixAttr>(attr) && name == "<") || // generic argument list
name == "=" || // Assignment
// FIXME: Should probably be allowed in expression position?
name == "->");
}
From a parsing standpoint, I think prefix <
and postfix >
could theoretically be allowed as operators, but I think this is largely prevented to avoid possible confusion when reading source code that would otherwise look ambiguous or incorrect to a human.