Constraining the conforming type of a protocol

Hi,

I had a question about defining protocols. Originally I wrote:

protocol Toggling where Self: Equatable {
  static var all: [Self] { get }
  func toggled() -> Self
  mutating func toggle()
}

extension Toggling {

  func toggled() -> Self {
    let current = Self.all.index(of: self) ?? 0
    let next = (current + 1) % Self.all.count
    return Self.all[next]
  }

  mutating func toggle() {
    self = toggled()
  }
}

This resulted in a bunch of errors.

Playground execution failed:
                         ^
error: Toggler.playground:7:28: error: cannot invoke 'index' with an argument list of type '(of: Self)'
    let current = Self.all.index(of: self) ?? 0
                           ^

Toggler.playground:7:28: note: expected an argument list of type '(of: Self.Element)'
    let current = Self.all.index(of: self) ?? 0

This approach worked:

protocol Toggling {
  static var all: [Self] { get }
  func toggled() -> Self
  mutating func toggle()
}

extension Toggling where Self: Equatable {

  func toggled() -> Self {
    let current = Self.all.index(of: self) ?? 0
    let next = (current + 1) % Self.all.count
    return Self.all[next]
  }

  mutating func toggle() {
    self = toggled()
  }
}

This version is probably better anyway but I am wondering if the first approach should have shown an error at the point of trying to attach the constraint to the protocol declaration. Any insights on this?

Thank you,
Ray Fix

What you’re trying to do should be equivalent to this:

protocol Toggling : Equatable {
  …
}

It’s a bug that placing the constraint on ‘Self’ does not have the same effect though; do you mind filing a JIRA?

Slava

···

On Jul 29, 2017, at 12:24 PM, Ray Fix via swift-users <swift-users@swift.org> wrote:

Hi,

I had a question about defining protocols. Originally I wrote:

protocol Toggling where Self: Equatable {
  static var all: [Self] { get }
  func toggled() -> Self
  mutating func toggle()
}

extension Toggling {

  func toggled() -> Self {
    let current = Self.all.index(of: self) ?? 0
    let next = (current + 1) % Self.all.count
    return Self.all[next]
  }

  mutating func toggle() {
    self = toggled()
  }
}

This resulted in a bunch of errors.

Playground execution failed:
                         ^
error: Toggler.playground:7:28: error: cannot invoke 'index' with an argument list of type '(of: Self)'
    let current = Self.all.index(of: self) ?? 0
                           ^

Toggler.playground:7:28: note: expected an argument list of type '(of: Self.Element)'
    let current = Self.all.index(of: self) ?? 0

This approach worked:

protocol Toggling {
  static var all: [Self] { get }
  func toggled() -> Self
  mutating func toggle()
}

extension Toggling where Self: Equatable {

  func toggled() -> Self {
    let current = Self.all.index(of: self) ?? 0
    let next = (current + 1) % Self.all.count
    return Self.all[next]
  }

  mutating func toggle() {
    self = toggled()
  }
}

This version is probably better anyway but I am wondering if the first approach should have shown an error at the point of trying to attach the constraint to the protocol declaration. Any insights on this?

Thank you,
Ray Fix

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Cool. Thanks for your comment. Done.

Ray

···

On Jul 29, 2017, at 5:55 PM, Slava Pestov <spestov@apple.com> wrote:

What you’re trying to do should be equivalent to this:

protocol Toggling : Equatable {
  …
}

It’s a bug that placing the constraint on ‘Self’ does not have the same effect though; do you mind filing a JIRA?

Slava

On Jul 29, 2017, at 12:24 PM, Ray Fix via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi,

I had a question about defining protocols. Originally I wrote:

protocol Toggling where Self: Equatable {
  static var all: [Self] { get }
  func toggled() -> Self
  mutating func toggle()
}

extension Toggling {

  func toggled() -> Self {
    let current = Self.all.index(of: self) ?? 0
    let next = (current + 1) % Self.all.count
    return Self.all[next]
  }

  mutating func toggle() {
    self = toggled()
  }
}

This resulted in a bunch of errors.

Playground execution failed:
                         ^
error: Toggler.playground:7:28: error: cannot invoke 'index' with an argument list of type '(of: Self)'
    let current = Self.all.index(of: self) ?? 0
                           ^

Toggler.playground:7:28: note: expected an argument list of type '(of: Self.Element)'
    let current = Self.all.index(of: self) ?? 0

This approach worked:

protocol Toggling {
  static var all: [Self] { get }
  func toggled() -> Self
  mutating func toggle()
}

extension Toggling where Self: Equatable {

  func toggled() -> Self {
    let current = Self.all.index(of: self) ?? 0
    let next = (current + 1) % Self.all.count
    return Self.all[next]
  }

  mutating func toggle() {
    self = toggled()
  }
}

This version is probably better anyway but I am wondering if the first approach should have shown an error at the point of trying to attach the constraint to the protocol declaration. Any insights on this?

Thank you,
Ray Fix

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

IMHO, there is a very subtle difference between :

protocol Toggling : Equatable
{
  …
}

extension Toggling
{
  …
}

… and :

protocol Toggling
{
  …
}

extension Toggling where Self : Equatable
{
  …
}

The first says that any type that implements Toggling also implements Equatable.

The second says that an implementing type can be Toggling without necessarily having to be Equatable.

Either way around, you are providing a default implementation for toggled() and toggle(), but, with the first version, toggled requires that Self is also Equatable.

Therefore, you are saying that, because the default implementation of Toggling demands that Self is Equatable, you have to also state that everything that is Toggling is also Equatable.

Since :

protocol Toggling where Self : Equatable

… is functionally identical to :

protocol Toggling : Equatable

… why would you want to use a more verbose way of saying the same thing ?

I would venture to suggest that there is no need for the longer syntax and that your bug report is not necessary

:-)

Joanna

···

--
Joanna Carter
Carter Consulting