Difference between any and some

I apologise if this sounds elementary, but Swift is not my native language :slight_smile:

I am having difficulties in understanding the difference between any and some.

For example, given:

protocol Bar {
   associatedtype Foo
   var selfy : Self {get}
   func bar (_: Foo)
}

I don't have any problem understanding this:

func bar () -> some Bar {
   ...
}

But, this bothers me:

func foo (u: any Bar) {
   ...
}

func foo (u: some Bar) {
   ...
}

What's the difference between the function parameters and corresponding arguments semantically?

And, if I write this (most natural variant):

func foo (u: Bar) {
   ...
}

The compiler says: Use of protocol 'Bar' as a type must be written 'any Bar'.

But why?

And with this:

struct S1 : Bar {
   ...
}

struct C1 : Bar {
   ...
}

foo (u: C1 ())
foo (u: S1 ())

let p1 = S1 ()
let p2 = C1 ()
foo (u: p1)
foo (u: p2)

Which foo (u: ...) gets called?

Thank you in advance.

Because using the most natural syntax for the less frequently used feature leads to people unintentionally reaching for the wrong thing. You usually want some.

In the future, perhaps some T could be written as just plain T, but switching that over all at once would have led to lots of confusion where older code still compiled but now had a different meaning.

2 Likes

When the some or any appears at the top level, very little. The some form allows you to talk about the associated type directly, for example by calling bar().

However, there is a big difference between

func foo(u: [any Bar]) {}

and

func foo(u: [some Bar]) {}

The first function takes a heterogenous array where each element can be of any concrete type conforming to Bar.

The second function accepts a homogeneous array where all elements are some concrete type conforming to Bar.

So if you have

protocol Animal {}
struct Chicken: Animal {}
struct Horse: Animal {}

Then you can call the first function with [Chicken(), Horse()], and the second function only with [Chicken(), Chicken()].

A bare protocol name P is the older syntax which is equivalent to any P as of Swift 5.6.

If you haven't already, I suggest watching Embrace Swift generics - WWDC22 - Videos - Apple Developer.

11 Likes

Another way of conceptualizing the difference is to think of both some Bar and any Bar as "boxes" that contain a value of a type conforming to Bar.

  • some indicates a box whose contained value has a type known to the compiler at compile time.

  • any indicates a box whose contained value has a type not known to the compiler at compile time.

Either way, you the programmer don't know the type of the value when you write the code where you use the box. You can't see inside the box — it's "opaque".

However, the compiler's knowledge allows the code generated for some Bar to be simpler and more efficient, since there's only one possibility. For any Bar, there has to be a run-time check or branch or switch or dispatch on the actual type every time the value is pulled out of the box.

There are more nuances, especially for any Bar for historical reasons, but I think the above is the essence of the distinction.

10 Likes