Digit as operator-character to support fixed-length types

What do people think of adding digits 0...9 to the set of permitted operator (non-leading) characters?

In the absence of fixed-length array types I was hoping e.g., to abuse custom postfix operators for type-safe access using digits. I.e., given

  postfix operator @0
  postfix operator @1
  ...

then e.g., a type supporting n elements could implement operators @0...@n-1, in some optimized fashion.

The result is type-safe and efficient.

It would seem limited effectively to literals and some captures, but I can imagine some useful derived types when the underlying type has internal structure (like Eytzinger).

(I'd exclude this in dot-prefixed operators, as much as I like the look, to avoid all sorts of ambiguities.)

As a side-note, the documentation lists the ASCII operator chars as

/ | = | - | + | ! | * | % | < | > | & | | | ^ | ~ | ?

While the code has more (including @ used above) with the context-sensitive checks, roughly in

https://github.com/apple/swift/blob/main/lib/Parse/Lexer.cpp#L2698

I don't understand the need. I'd rather see subscript implemented on tuples!

for i in 0 ..< count {
	// normally tuple.0, tuple.1, etc
	print(tuple[i])
}
4 Likes

@ isn’t an operator character today; it’s only used for attributes. That doesn’t mean it can’t become one, only that it’s a bigger change than allowing digits.

2 Likes

I can see wanting that, too, but that's kinda the other direction.

Comparing an implementation like _FixedArray access, below, a type's implementation of a specific @n =n access operation would have no invariant check and a known stride, so it should optimize nicely.

@inline(__always)
get {
  let count = self.count // for exclusive access
  _internalInvariant(i >= 0 && i < count)
  let res: T = withUnsafeBytes(of: storage) {
    (rawPtr: UnsafeRawBufferPointer) -> T in
    let stride = MemoryLayout<T>.stride
    _internalInvariant(rawPtr.count == 16*stride, "layout mismatch?")
    let bufPtr = UnsafeBufferPointer(
      start: rawPtr.baseAddress!.assumingMemoryBound(to: T.self),
      count: count)
    return bufPtr[_unchecked: i]
  }
  return res
}

https://github.com/apple/swift/blob/1306f2b32ad1c5db56e975a57c4bcd51a39ef3e8/stdlib/public/core/FixedArray.swift#L58-L71

But you could do this without custom operators using a convention like .f0 for indexes or XnnYnn for vector/matrix, and no one has, so perhaps there is indeed no need.