Short Answer
I'm sure you've already used existentials a lot before without noticing it.
A re-worded answer of Max is that for:
var rec: Shape = Rectangle() // Example A
only Shape
properties can be accessed. While for:
func addShape<T: Shape>() -> T // Example B
Any property of T
can be accessed. Because T
adopts Shape
then all properties of Shape
can also be accessed as well.
The first example is an existential the second is not.
Example of real code:
protocol Shape {
var width: Double { get }
var height: Double { get }
}
struct Rectangle: Shape {
var width: Double
var height: Double
var area: Double
}
let rec1: Shape = Rectangle(width: 1, height: 2, area: 2)
rec1.area // ❌
However:
let rec2 = Rectangle(width: 1, height: 2, area: 2)
func addShape<T: Shape>(_ shape: T) -> T {
print(type(of: shape)) // Rectangle
return shape
}
let rec3 = addShape(rec2)
print(rec3.area) // ✅
I'd argue that for most Swift users, we all understand Abstract class and Concrete class. This extra jargon makes it slightly confusing.
The trickiness is that with the 2nd example, to the compiler, the type you return isn't Shape
, it's Rectangle
i.e. the function signature transforms to this:
func addShape(_ shape: Rectangle) -> Rectangle {
This is only possible because of (constrained) generics.
Yet for rec: Shape = Whatever()
to the compiler the type is Shape
regardless of the assigning type. <-- Box Type
tldr when it comes to protocols, you're either using
- constrained generics
- existential
and for the most part you don't care about the differences between the two. It's just that in some more low level swift protocol discussions the term existential comes up as a way to be more specific about certain Swift protocol usage.
Why is it named Existential?
The term "existential" in computer science and programming is borrowed from philosophy, where it refers to the concept of existence and being. In the context of programming, "existential" is used to describe a type that represents the existence of any specific type, without specifying which type it is.
The term is used to reflect the idea that, by wrapping a value in an existential type, you are abstracting away its specific type and only acknowledging its existence.
In other words, an existential type provides a way to handle values of different types in a unified way, while ignoring their specific type information†. This allows you to work with values in a more generic and flexible manner, which can be useful in many situations, such as when creating collections of heterogeneous values, or when working with values of unknown or dynamic types.
The other day I took my kid to an shop. She asked what are you having, and I didn't know the flavor I picked, so I didn't say it's strawberry flavored nor chocolate, I just said "I'm having an ice-cream". She wasn't happy with my answer...
I just specified that it's an ice-cream without saying its flavor. My daughter could no longer determine if it was Red, or Brown. If it was having a fruit flavor or not. I gave her existential-like information.
Had I told her it's a chocolate, then I would have gave her specific information. Which is then not existential.
†: In Example B, we're not ignoring the specific type information.
Special thanks to a friend who helped me come up with this answer