2

As the Swift Language Guide points out generic types can be constraint to classes or protocols like this:

public class MyGenericClass<T:Equatable> {
    func printEquality(a:T, b:T) {
        if a == b {
            print("equal")
        } else {
            print("not equal")
        }
    }
}

Can I somehow restrict T to be a struct?

My use case is an observer class for value types that should only be used by structs.

As a side note: I know that there are e.g. class-only protocols, that are only implementable by classes. This is not really related, but shows that there is sometimes a special way to reach a goal.

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition goes here
}
Klaas
  • 22,394
  • 11
  • 96
  • 107
  • Inheritance is related only to classes ( reference types ). SomeInheritedProtocol has no sense in Swift. Related to protocols is conformance. However runtime check if instance of some type conforms to AnyObject protocol or not is available using is operator – user3441734 Feb 26 '16 at 16:57
  • Closely related: http://stackoverflow.com/questions/33623104/how-to-restrict-a-protocol-to-value-types-only: – Martin R Feb 26 '16 at 17:05
  • @user3441734 the code snippet is a quote from the "Protocols" chapter in the Swift Language Guide. – Klaas Feb 27 '16 at 10:22
  • yes, you are right. they talks about protocol inheritance ... my bad. – user3441734 Feb 27 '16 at 10:44

2 Answers2

2

You can't (as of Swift 2.2).

It's simply not possible. There's no struct version of AnyObject, i.e. an AnyValue protocol (automatically implemented for all value types).

I've faced this exact problem myself, and I'm sorry to say that there's no solution other than to strictly abide by an informal protocol. Here's to hoping Swift 3 solves this.

Vatsal Manot
  • 17,695
  • 9
  • 44
  • 80
1

The other answer answers this well (i.e.: you can't (yet?)).

I thought I'd add that you can, however, mimic at least the behaviour of this using runtime introspection and failable initializers; such that initialization of your generic class will succeed only if T is a structure (conforming to Equatable).

public class MyGenericClass<T: Equatable> {
    var foo: T

    init?(bar: T) {
        foo = bar

        if Mirror(reflecting: foo).displayStyle != .Struct {
            return nil
        }
    }
}

struct Foo : Equatable {
    let foo = 1
}
func ==(lhs: Foo, rhs: Foo) -> Bool { return lhs.foo == rhs.foo }

/* Example */
if let _ = MyGenericClass<Int>(bar: 1) {
    print("Integer")
}
if let _ = MyGenericClass<Foo>(bar: Foo()) {
    print("Foo-Struct")
}
// prints only "Foo-Struct"

You could interpret failed initialization as non-conformance of your generic T to "only allow T to be structures", and possibly use optional binding (/...) to use this with your observer class in practice.

dfrib
  • 70,367
  • 12
  • 127
  • 192
  • in Swift an Int is actually struct, Double is actually struct etc. You can check conformance to AnyObject (and nonconformance) with If bar is AnyObject { // bar is reference type, class } else { // bar is value type, struct } don't mix type and displayStyle !!! – user3441734 Feb 26 '16 at 16:31
  • @user3441734 I interpreted the OP:s question as concerning constraining a protocol "to be a struct" in the sense of explicit struct types (not native types that are, inherently, behind the hood, structs). Reflecting on native value types will return `nil` for `.displayStyle`, hence allowing only "pure structs" in the example above. If the OP had asked for _"constraining a generic only to value types"_ (but no mention of structs, in particular), then the `AnyObject` solution is a good way to go. As I interpret this question, however, this asking to cover all value types (incl. native ones). – dfrib Feb 26 '16 at 23:01
  • @dfri thanks for your solution. I was thinking about something similar as well. – Klaas Feb 27 '16 at 10:27
  • @Klaas Happy to help. – dfrib Feb 27 '16 at 11:06