protocol SomeView {
associatedtype ViewModel
}
private function foo<T: SomeView>(view: T) where T.ViewModel == Void {
}
But it's not possible to do:
private function foo<T: SomeView>(view: T, viewModel: T.ViewModel) where T.ViewModel != Void {
}
It seems like it's possible to constraint a type to being another type. Then it should be possible to do the opposite. A type is either a type or not, there's no in-between.
or is there some other way of deciding which method can be called based on a type constraint?
The problem with negative constraints is that they don't allow you to write any useful generic algorithms. They tell you what a type isn't or can't do, and nothing about what it is or can do (which is what you actually need to know).
You can absolutely add constraints on associated types, though - either at the protocol level or at the algorithm level:
Using overloads, the single-type overload will only be used in cases where it's visible at the call site that both arguments are the same type, since Swift picks a single overload per call site.
You could instead test the value of the types in a condition inside a single function definition:
func doSomething<T, U>(one: T, two: U) {
if T.self != U.self {
/*handle different case*/
} else {
let twoAsT = unsafeBitCast(two, to: T.self)
/*handle same case*/
}
}
I'd like for us to eventually have proper language support for testing type conditions like this in a way that doesn't need the bitcast afterward.
And thanks for your quick response. I didn't expect anyone to actually try out the code. Sometimes in tests I have to do two asserts, first to see if the type cast works and then to see if it's equal. I'm trying to do that in one step.
I would also like to keep the nice short syntax of not having to fully specify the type of the second parameter.
Maybe I just change the name of the function instead of doing override.Feels like a fail though
func doSomething<T, U>(one: T, two: U) {
if let twoAsT = two as? T {
/*handle same case*/
} else if let oneAsU = one as? U {
/*handle same case*/
} else {
/*handle different case*/
}
}
Why both if's? – to handle case with subclasses properly:
class A {}
class B: A {}
doSomething(one: B(), two: A())
doSomething(one: A(), two: B())
assuming you want to treat these two lines the same way.
In the end I changed the name instead of overriding.
But what I'm looking for is something that can use the doSomething<T> function.
Because swift has type inference you won't need to fully specify the type of the second argument if they are considered to be the same.
Maybe this can't actually happen though, so I used a different name for doSomethingElse<T, U> and it doesn't look too bad. Maybe it is even better that way on second thought.