Operator alias

Let's say we have an operator like this:

prefix operator <>

extension Optional {
    static prefix func <>(opt: Optional<Wrapped>) -> Bool {
        return opt != nil
  }
}

It allows us to write:

if <>someOptional { }, instead of if someOptional != nil { }

( <!> could be defined to check if an optional is nil )

I'm imagining a simple alias definition to look like this:

#prefix <> ok

It simply means that ok will be interpreted as <> by the compiler.

To make it explicit that it is an alias, the compiler could show
the alias in italics, or in a distinct color.

if someOptional != nil { } can then be written like this:

if ok someOptional { }

Interestingly, it could now become convenient to apply more than
one prefix or postfix operator, without the need for parentheses.

#prefix ! not

if someOptional == nil { } can then be written like this:

if not ok someOptional { }

An alias of this sort could do anything that operators can do.
You could more or less create a new language with it. It can
also make it more obvious what an operator is intended to do.

This will totally circumvent the allowed operators characters in the Swift syntax.

I don't really have strong opinions on whether the current character set restriction is useful or not, but if you think that e.g ok should be a valid operator name, I think a better approach would be to pitch changes to the Swift syntax that expand that set, rather than creating elaborate workarounds that will only lead to dialects.

1 Like

Swift doesn't allow white space between prefix / postfix operators and what they are applied to, (BTW, why?) so just changing the allowed character set would not be enough.

Why only prefix / postfix operators btw? If infix operators were allowed we could have had:

x and not y
x not equal y

etc

Aliasing an existing operator to a new operator is one thing, but that new operator would have to abide by the existing grammar for operators. IIUC we're not likely to loosen that, and it's unlikely that we'll allow more things via operator aliases than we allow as plain operators.

  • Replace logical operators (&&, ||, !, etc.) with words like "and", "or", "not", and allow non-punctuation operators and infix functions: The operator and identifier grammars are intentionally partitioned in Swift, which is a key part of how user-defined overloaded operators are supported. Requiring the compiler to see the "operator" declaration to know how to parse a file would break the ability to be able to parse a Swift file without parsing all of its imports. This has a major negative effect on tooling support. While not needing infix support, not would need operator or keyword status to omit the parentheses as ! can, and not somePredicate()visually binds too loosely compared to !somePredicate().

Commonly Rejected Changes

5 Likes

Because it avoids parsing ambiguity. foo ++bar is clearly lexed as identifier prefix-operator identifier, and foo ++ bar is clearly lexed as identifier infix-operator identifier.

4 Likes

@sveinhal Good points. I agree that there's a risk of ending up
with different dialects, but since we can already define custom
operators, that in itself could also lead to dialects. For example,
Swift programmers in general wouldn't understand what <> means.
A lot of other things (including macros) can be examples of this
sort of idiosyncrasy.

@tera I should have made it clear that the pitch was intended for
all three types of operators; so, infix operators are, of course,
also part of the pitch. When I thought about this proposal, I had
a language called APL in mind. APL makes a distinction between
so-called monadic (prefix) and dyadic (infix) functions.

@Karl Thanks, I was aware of that page, and the pitch was
actually trying to circumvent that it would be difficult to introduce
all these new keywords. I don't know if, and to what degree this
pitch might solve problems of the kind that you quoted.

@ksluder The current operators show clearly which of the
three types (prefix, postfix, infix) it is, because of how they use
whitespace. The aliases should therefore ideally have names
that give you a hint of what type they are.

There are some theoretical benefits of being able to parse a file without parsing it fully although I don't see yet a real practical benefit. For example if I type some gibberish:

1 &^* 2

Xcode reasonably quickly (in about a second) tells me that this operator is not found (and to do that it needs to scan though all imports in the project). To not scan every time Xcode cache could maintain a list of currently operators and update that list during edits (perhaps it's doing this already). Understandably the compilation speed (including that happening in the IDE during typing) would be a bit slower as now every name is potentially an operator, but that would only be the case if this feature is used (e.g. if the list of "current" operator aliases is empty compiler could take the quick path and not treat every name as a potential operator).

1 Like