If we add something like this, precedent from @dynamicCallable
implies we should use an @attribute
, potentially something like @callable
or @functionConvertible
.
That could potentially take two forms:
- Any method of a certain name (e.g.
_
,call
,typeFunc
) becomes "callable", so a type could declare multiple callable methods and become convertible with multiple function types:
@callable
extension KeyPath {
func call(with root: Root) -> Value { ... }
func call(with root: Root) -> Root { ... }
// in this hypothetical implementation, `KeyPath` could
// represent either `(Root) -> Value` or `(Root) -> Root`
}
-
@callable
could be parameterized, so only one specific method would participate in the behavior and the type would only be convertible with one specific function type:
@callable(map(_:))
struct KeyPath<Root, Value> {
func map(_ root: Root) -> Value { ... }
// in this hypothetical implementation, `KeyPath` could
// only represent `(Root) -> Value`.
}
Either way, the call-site behavior of types expressing this attribute seems fairly reasonable:
\String.count("value")
// interpreted as \String.count.call(with: "value")
["a", "bb", "ccc"].map(\.count)
// interpreted as ["a", "bb", "ccc"].map(\.count.call(with:))
I'm not a compiler engineer by any means, but it seems like parameterizing the @callable
behavior to one specific function signature could have better performance implications (with respect to type inference)
(partial cross-post from Sort Collection
using KeyPath
)