How to refer to a subscript getter

how do you refer to a type’s instance subscript getter?

self.indices[key].map(self.subscript(_:))
// error: no property or method named 'subscript'; 
// did you mean to use the subscript operator?
3 Likes

Just this?

self.indices[key].map { self[$0] }

right, that’s what i’m writing right now, but that’s not a reference to the subscript getter, it’s an anonymous function that wraps a call to the subscript getter.

1 Like

I see, makes sense. Does it lead to a different ASM (in those cases when it works, with a non subscript method)?

It's never been possible.

Same situation for callAsFunction.

The closest the language allows to what you need is to supply an argument, effectively turning a subscript into a property. In the case of a () -> subscript, this syntax is just empty brackets.

struct S {
  subscript() -> Void {
    get { () }
    nonmutating set { }
  }
}


\S.[] // ReferenceWritableKeyPath<S, ()>
[S()].map(\.[])
S()[keyPath: \.[]] = ()

No similar feature exists for callAsFunction. Having both () and [] in this language is an anachronism.

1 Like

Is your fear that it will run slower?

I didn't measure any performance differences between map(xxx) and map { xxx } in the following test:

test
import Foundation

struct Foo {
    func foobar(_ numbers: [Int]) -> Int {
        numbers
            .map(subscript2)
//            .map { subscript2($0) }
            .reduce(0) { $0 &+ $1}
    }
    
    func subscript2(_ i: Int) -> Int {
        i &* 2 &+ 5678
    }
}

let foo = Foo()

let numbers = (0 ... 10000000).map { $0 &* 3 &+ 1234 }
var result = 0
let start = CFAbsoluteTimeGetCurrent()
for _ in 0 ..< 100 {
    result &+= foo.foobar(numbers)
}
let elapsed = CFAbsoluteTimeGetCurrent() - start
print("elapsed \(Int(elapsed * 1000)) ms (result: \(result))")

1 Like

can’t you reference it with instance.callAsFunction(label1:label2:)? if i remember right, this was the justification for requiring people to declare it as a named function and not a “magic” declaration like func () -> ().

1 Like

As they go over in that thread, yes, and as with methods, you generally don't need explicit labels. The problem is not in lack of possibility of member access, but in ergonomics and consistency.

  1. Subscript getters should be accessible as closures.

  2. "callAsFunction" instances should be accessible as closures.

  3. Subscripts should be deprecated, and functions should have had setters added.
    (1 will not be necessary if this happens instead, but I'm not optimistic.)


Note, you can overload callAsFunction for getters. I can't tell what you're working with in your post. The most ubiquitous overload is

extension Collection {
  func callAsFunction(_ index: Index) -> Element {
    self[index]
  }
}

[1, 2][0]
[1, 2](0)