2
2
.
.
5
5
.
.
6
6
O
O
p
p
a
a
q
q
u
u
e
e
R
R
e
e
t
t
u
u
r
r
n
n
T
T
y
y
p
p
e
e
(
(
s
s
o
o
m
m
e
e
P
P
r
r
o
o
t
t
o
o
c
c
o
o
l
l
)
)
I
I
n
n
f
f
o
o
Opaque Return Type is when Function returns some Protocol.
It is called Opaque because caller doesn't know which specific Concrete Type (that implements specified Protocol) is
always going to be returned by the Function.
U
U
s
s
a
a
g
g
e
e
Always return the same Concrete Type
If Function returns Opaque Type it will always return the same Concrete Type that implements specified Protocol.
Which Concrete Type depends on Function's implementation (it is nowhere explicitly declared).
But Compiler can check your code to make sure that you are always returning the same Concrete Type as intended.
Return Protocols that use associatedtype
Protocols that use associatedtype can't be used as Function return value (because Compiler doesn't know exact type).
But you can add keyword some to create Opaque Return Type because then Compiler will infer which concrete type that
implements that Protocol is going to be returned every time. It is as if Function returns Concrete Type but which one
specifically is defined by Function Implementation rather then explicitly declaring it as Function's return Type.
P
P
r
r
o
o
t
t
o
o
c
c
o
o
l
l
v
v
s
s
s
s
o
o
m
m
e
e
P
P
r
r
o
o
t
t
o
o
c
c
o
o
l
l
If Function returns
Protocol (Animal) it means it can return any Type that implements that Protocol (Dog, Cat).
First time you call Function it might return instance of Dog Class, and second time it might return instance of Cat Class.
some Protocol (some Animal) it means it will always return the same Type that implements Protocol.
Every time you call the Function it will always return instance of a Dog Class (which is more restrictive).
So if you accidently write your Function so that it might return both Dog or Cat you will get Compiler error.
G
G
e
e
n
n
e
e
r
r
i
i
c
c
v
v
s
s
O
O
p
p
a
a
q
q
u
u
e
e
T
T
y
y
p
p
e
e
You can think of Opaque Return Type as being the reverse of a Generic Type
Generic Type allows caller to define concrete type of function parameters & return value.
Type is abstracted away from the function implementation (Function doesn't know which type will be used).
Opaque Return Type allows Function to define which concrete type will be returned.
Type is abstracted away from the caller (caller doesn't know which concrete type is always being returned).
Content
Example: Protocol vs some Protocol
Example: associatedtype
E
E
x
x
a
a
m
m
p
p
l
l
e
e
:
:
P
P
r
r
o
o
t
t
o
o
c
c
o
o
l
l
v
v
s
s
s
s
o
o
m
m
e
e
P
P
r
r
o
o
t
t
o
o
c
c
o
o
l
l
In this example we create Function that returns Animal Protocol which means it can return Dog or Cat.
Test.swift
protocol Animal {
func makeSound()
}
struct Dog : Animal {
func makeSound() { print("Bark") }
}
struct Cat : Animal {
func makeSound() { print("Meow") }
}
func giveBirth(code: Int) -> Animal {
if (code == 1) { return Dog() }
else { return Cat() }
}
giveBirth(code: 1)
If we change the code by adding some Animal we get below error.
To fix the error we can change implementation of giveBirth() function to always return the same struct Dog.
Error
Function declares an opaque return type, but the return statements in its body do not have matching
underlying types
Test.swift
func giveBirth(code: Int) -> some Animal {
if (code == 1) { return Dog() }
else { return Dog() }
}
E
E
x
x
a
a
m
m
p
p
l
l
e
e
:
:
a
a
s
s
s
s
o
o
c
c
i
i
a
a
t
t
e
e
d
d
t
t
y
y
p
p
e
e
Below example throws error if we don’t use some before the Animal.
This is because Protocols that use associatedtype can't be used as Function return value.
By using keyword some Compiler will infer that Function giveBirth() actually always returns concrete Type Dog.
Error
Protocol 'Animal' can only be used as a generic constraint because it has Self or associated type
requirements
Test.swift
protocol Animal {
associatedtype mytype
func makeSound(duration: mytype)
}
struct Dog : Animal {
func makeSound(duration: Int) { print("Bark") }
}
struct Cat : Animal {
func makeSound(duration: Float) { print("Meow") }
}
func giveBirth(code: Int) -> some Animal {
if (code == 1) { return Dog() }
else { return Dog() }
}
giveBirth(code: 1)