2

This seems like it should work to me. All I am trying to do is make the Rule protocol able to performRule on whatever struct adopts that Rule protocol and then return a boolean. However, with the way my code is currently I cannot access any properties on the performRule(:value) value parameter. I feel like I am missing an important concept or something is buggy. You should be able to copy the code below into a playground to see the issue for yourself.

import Foundation

protocol NumberCalculation {
    var number : NSNumber { get set }
}

protocol Rule {
    var invalidMessage : String { get set }
    func performRule<T>(value: T) -> Bool
}

struct GreaterThanRule : Rule, NumberCalculation  {
    var invalidMessage: String
    var number : NSNumber

    init(valueMustBeGreaterThan value: NSNumber, withInvalidMessage message : String = "") {
        number = value
        invalidMessage = message
    }

    func performRule<NSNumber>(value: NSNumber) -> Bool {
        number.decimalValue // works 
        value.decimalValue // doesn't work
        return true
    }
}
0

1 Answer 1

2

Saying <NSNumber> defines a new generic placeholder type in your performRule(value:) method, which, as you've named it NSNumber, will shadow Foundation's NSNumber class – meaning that the value: parameter is of type your generic placeholder, not Foundation's NSNumber.

If you want it so that types conforming to Rule can choose their own type for the parameter of the performRule(value:) method – then you want an associated type, not a generic placeholder.

protocol NumberCalculation {
    var number : NSNumber { get set }
}

protocol Rule {

    // define associated type that conforming types must satisfy
    // by providing a type to replace it with
    associatedtype Value
    var invalidMessage : String { get set }
    func performRule(value: Value) -> Bool
}

struct GreaterThanRule : Rule, NumberCalculation {

    var invalidMessage: String
    var number : NSNumber

    init(valueMustBeGreaterThan value: NSNumber, withInvalidMessage message : String = "") {
        number = value
        invalidMessage = message
    }

    // satisfy associated type implicitly by annotating the type of the parameter
    // as NSNumber – the compiler will infer that Value == NSNumber.
    func performRule(value: NSNumber) -> Bool {
        number.decimalValue // works
        value.decimalValue // also works!
        return true
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I will look further into associatedtypes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.