Overloading operator ()

Hi,

I'm working on a project where I'd like use the parentheses as method identifier.

C++ equivalent: void operator()()

I've tried overloading it but it looks like the compiler doesn't allow it.

Am I doing it wrong or is this feature not implemented yet ?

Thanks,
Ismail

Can you elaborate a little bit more on what Swift code you wish to be able to write? () is not an operator in swift but an empty tuple aka typealias Void = ()

Basically, I'd like to have a method in my class that use () as an identifier.
I'd like to be able to call my instantiated object this way:

let obj : Object()
let s = obj("test")

Would a subscript serve your needs here?

class MyObject {
  subscript (_ value: String) -> SomeType { ... }
}

let object = MyObject()
let s = object["test"]

I don't think Swift will ever support parentheses in that way. It's kind of strange and it reads ambiguous.

Yeah in my case I'd do the job perfectly, but what if my class is also a Collection.

It would be great to have the () option.

Your type can have as much subscripts as you'd like, the only limitation that you can reach is that some subscripts can become ambiguous at call-site but you can explicitly tell the compiler the types to resolve such collisions. In other situation you can add a view type to your class that will provide the functionality you need.

class MyObject {
  struct DataView {
    let object: MyObject
    subscript (_ value: String) -> Data { ... }
  }
  var data: DataView { return DataView(object: self) }
}

let object = MyObject()
let s = object.data["test"]
2 Likes

We literally just accepted SE–0216 “Introduce user-defined dynamically "callable" types” two days ago. It would be wildly incongruous to let people define wholly dynamic “callable” behavior, but to somehow decide that *statically* callable types would not fit in the language.

Of course statically-callable types make sense, of course they fit in the language, and of course square-brackets are a poor substitute for round ones in this scenario. After all, if square brackets were good enough for “callable” types, then we would’ve demanded that SE–0216 use square brackets.

But we didn’t.

Because square brackets are the wrong symbol for “callable” types.

The right symbol is a pair of parentheses, just like we use when calling any other function or method. When a user-defined type represents a function, it deserves and ought to be able to use parentheses when it is “called”.

For example:

class DifferentiableFunction<T: FloatingPoint> {
  var f: (T) -> T
  var df: DifferentiableFunction?
  init(f: @escaping (T) -> T) { self.f = f }

  // This should be “callable” with parentheses not square brackets:
  subscript(x: T) -> T { return f(x) }
}
5 Likes

Thx for mentioning it Nevin, when I replied I only had the dynamic lookup attribute in mind and to be honest I never looked that closely into that last proposal.

Btw. did you forget the attributes on your example type?

That is the "functor", or function object, concept in C++. We haven't had that concept in Swift. The subscript suggestion from @DevAndArtist doesn't really match because a subscript access implies more of a sub-object, while a functor is more of a mapping (like conventional functions and closures).

But, as @Nevin said, we have taken steps that may lead to a Swift functor concept someday.

2 Likes

You can use
public func callAsFunction() { /* your code */ }

https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID622

2 Likes

This terser, anonymous function syntax, proposed by @davdroman

struct Foo () {
    func (...)
}

feels much better than these verbose, supported alternatives:

struct Foo () {
   func callAsFunction (...)
}

// Or
@dynamicCallable
struct Foo () {
   func dynamicallyCall (withArguments: ...)
}

This was all discussed in the proposals for these features. That doesn’t mean it’ll never change, but a four-year-old “Using Swift” thread isn’t the place to relitigate it.

3 Likes