Generic struct func - Use 2 different implementations

Hi,

Overview

  • I have a generic struct Box
  • I have a function func f1(newValue: T)
  • I would like call 2 different implementations depending on whether T is String or not.

Questions:

  1. Is my attempt the correct way and does it guarantee to execute correctly all the time?
  2. Or what is the right way?

My Attempt:

I am not sure if this is the correct way.

struct Box<T> {
    var value: T
    
    func f1(newValue: T) {
        print("non-string func value = \(newValue)")
    }
}

extension Box where T == String {
    func f1(newValue: T) {
        print("String func value = \(newValue)")
    }
}

Invoking

let b1 = Box(value: 10)
let b2 = Box(value: "aaa")

b1.f1(newValue: 25)
b2.f1(newValue: "bbb")

Output

non-string func value = 25
String func value = bbb

No, it's incorrect; there has been some discussion to warn users about. Box<String>.f1 simply shadows Box<T>.f1. This means that there is no dynamic dispatch. E.g.

func callF1<T>(_ box: Box<T>, _ newValue: T) {
  box.f1(newValue: newValue) // Always call non-string f1
}

callF1(Box(value: 1), 2) // non-string
callF1(Box(value: "1"), "2") // non-string

You can simply check if T.self == String.self, though I'm not sure that's the fastest approach.

2 Likes

@filip-sakel Thanks a lot for that clarification.

Yeah T.self == String.self is one way to handle that String logic.

I think I will follow that approach if there is no better way.

1 Like

For more complex cases you can always create a protocol e.g. StringBox, that Box conditionally conforms to where T == String. Then, by conditionally casting self as? StringBox you can check for more complex values. For example, by having a conformance where T: StringProtocol you can customize your function based on whether your value conforms to a given protocol. However, I don’t know how efficient this is, you might have to benchmark against the aforementioned metatype comparison.

1 Like

Thanks a lot!! @filip-sakel

I will give it a try I think it should be fine for my use case