I'm not sure I'll be able to come up with any better examples than what's discussed in that thread, but perhaps I'll be able to phrase things differently on another attempt.
The information that is intended to be provided by any Foo as opposed to Foo is emphasis on the fact that the underlying dynamic type of foo will be one of (potentially many) types that conform to Foo, which in some cases prevents us from doing things with values of type any Foo that it seems like we should be able to do from a naive look at the Foo protocol.
Before any was introduced, we used the bare protocol name Foo to talk about two distinct things:
- The set of functionality that all types conforming to
Foo share (as in func f<T: P>(_ t: T)).
- The type of a variable which can hold any
P-conforming instance (as in let foo: Foo above).
But consider if Foo were defined as follows:
protocol Foo {
func doSomething(with other: Self)
}
This protocol would be conformed to by providing an implementation of doSomething(with:) that accepts a value of the same type as the conforming type. So a structs R and S would conform with different signatures for doSomething(with:) as:
struct S: Foo {
func doSomething(with other: S) {
}
}
struct R: Foo {
func doSomething(with other: R) {
}
}
But now suppose we had the following function:
func makeFoo(useS: Bool) -> Foo {
if useS {
return S()
} else {
return R()
}
}
What happens if we try to do
makeFoo(useS: true).doSomething(with: makeFoo(useS: false)
?
An quick look at the protocol Foo might suggest this should work—after all, the (static) type of makeFoo(useS:) is always Foo, and doSomething(with:) accepts a value of type Self, so why shouldn't it work to pass a value of type Foo to doSomething(with:).
But as you can see from the setup, there's no implementation which we could possibly invoke for thus use of doSomething(with:). S.doSomething(with:) only accepts values of type S, and makeFoo(useS: false) is going to give us a value of (dynamic) type R. So this must fail to compile.
By writing makeFoo(useS:) as returning any Foo, it is (hopefully) a bit clearer why the failure happens here. The function doesn't just produce a value of type Foo, it produces a value of 'any' type that conforms to Foo—which means that any Foo may not actually satisfy the requirements needed to conform to Foo.