Podcast
Questions and Answers
Which of the following is NOT a characteristic of a Swift protocol?
Which of the following is NOT a characteristic of a Swift protocol?
- Specifies requirements for conforming types to implement.
- Provides concrete implementations for all its requirements. (correct)
- Can be adopted by classes, structures, and enumerations.
- Defines a blueprint of methods and properties.
A protocol requiring a gettable and settable property can be satisfied by a constant stored property.
A protocol requiring a gettable and settable property can be satisfied by a constant stored property.
False (B)
In a protocol definition, what keyword is used to prefix type property requirements?
In a protocol definition, what keyword is used to prefix type property requirements?
static
A method marked with the keyword ______
in a protocol definition indicates that conforming value types are allowed to modify their instances.
A method marked with the keyword ______
in a protocol definition indicates that conforming value types are allowed to modify their instances.
Match the protocol feature with its purpose:
Match the protocol feature with its purpose:
Which keyword is used when implementing a protocol initializer requirement in a class?
Which keyword is used when implementing a protocol initializer requirement in a class?
A nonfailable initializer requirement in a protocol can only be satisfied by a nonfailable initializer in a conforming type.
A nonfailable initializer requirement in a protocol can only be satisfied by a nonfailable initializer in a conforming type.
What is the term for a design pattern where a class or structure hands off responsibilities to an instance of another type, facilitated by a protocol?
What is the term for a design pattern where a class or structure hands off responsibilities to an instance of another type, facilitated by a protocol?
To prevent strong reference cycles, delegates are often declared as ______
references.
To prevent strong reference cycles, delegates are often declared as ______
references.
Match the type of protocol with its application.
Match the type of protocol with its application.
What operator is used to check if an instance conforms to a protocol at runtime?
What operator is used to check if an instance conforms to a protocol at runtime?
When using an optional protocol requirement, the type of a method (Int) -> String
automatically becomes (Int?) -> String?
When using an optional protocol requirement, the type of a method (Int) -> String
automatically becomes (Int?) -> String?
What attribute must both a protocol and its optional requirements be marked with to enable optional requirements?
What attribute must both a protocol and its optional requirements be marked with to enable optional requirements?
When a protocol extension provides a default implementation for a protocol requirement, and a conforming type provides its own implementation, the ______ implementation is used.
When a protocol extension provides a default implementation for a protocol requirement, and a conforming type provides its own implementation, the ______ implementation is used.
Associate each operator with its function in protocol conformance:
Associate each operator with its function in protocol conformance:
What is the primary benefit of using protocol extensions in Swift?
What is the primary benefit of using protocol extensions in Swift?
Adding constraints to protocol extensions allows you to provide specialized implementations for conforming types that meet specific criteria.
Adding constraints to protocol extensions allows you to provide specialized implementations for conforming types that meet specific criteria.
What is the syntax for creating a protocol composition that requires a type to conform to both ProtocolA
and ProtocolB
?
What is the syntax for creating a protocol composition that requires a type to conform to both ProtocolA
and ProtocolB
?
A generic type can ______ conform to a protocol by listing constraints in an extension using a generic where
clause.
A generic type can ______ conform to a protocol by listing constraints in an extension using a generic where
clause.
Match the concept with its description regarding synthesized protocol implementations.
Match the concept with its description regarding synthesized protocol implementations.
What is the effect of declaring protocol adoption with an empty extension?
What is the effect of declaring protocol adoption with an empty extension?
If a subclass overrides a designated initalizer from a superclass, it does not need to use the override keyword when implementing a matching initializer requirement from a protocol.
If a subclass overrides a designated initalizer from a superclass, it does not need to use the override keyword when implementing a matching initializer requirement from a protocol.
What is a 'boxed protocol type'?
What is a 'boxed protocol type'?
Delegation can be used to respond to a particular ______, or to retrieve data from an external source without needing to know the underlying type of that source.
Delegation can be used to respond to a particular ______, or to retrieve data from an external source without needing to know the underlying type of that source.
Match the concept with the output regarding SnakesAndLadders
example
Match the concept with the output regarding SnakesAndLadders
example
You can limit protocol adoption to class types (and not structures or enumerations) by adding the _______ protocol to a protocol’s inheritance list.
You can limit protocol adoption to class types (and not structures or enumerations) by adding the _______ protocol to a protocol’s inheritance list.
Protocol Composition defines a new protocol type.
Protocol Composition defines a new protocol type.
The objects
array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea protocol. What is the downside of this?
The objects
array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea protocol. What is the downside of this?
Optional requirements are ________ by the optional
modifier as part of the protocol’s definition.
Optional requirements are ________ by the optional
modifier as part of the protocol’s definition.
Match the description for the Counter
explanation in the text.
Match the description for the Counter
explanation in the text.
What will print to console?
What will print to console?
Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol.
Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol.
If a conforming type provides its own implementation of a required method or property over the extension, which implementation will be used?
If a conforming type provides its own implementation of a required method or property over the extension, which implementation will be used?
By constraining a collection’s elements to the Equatable protocol, a part of the Swift standard library, you can use the == and != ______ to check for equality and inequality between two elements.
By constraining a collection’s elements to the Equatable protocol, a part of the Swift standard library, you can use the == and != ______ to check for equality and inequality between two elements.
Match the following to be accurate.
Match the following to be accurate.
You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the _____ code for the existing type.
You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the _____ code for the existing type.
The protocol name is provided after the type name, separated by a semicolon.
The protocol name is provided after the type name, separated by a semicolon.
A generic type may be able to satisfy the requirements of a protocol only under certain conditions, such as when the type’s generic parameter conforms to the ___________.
A generic type may be able to satisfy the requirements of a protocol only under certain conditions, such as when the type’s generic parameter conforms to the ___________.
Swift can automatically provide the protocol conformance for Equatable, Hashable, and ________ in many simple cases.
Swift can automatically provide the protocol conformance for Equatable, Hashable, and ________ in many simple cases.
Match the following:
Match the following:
Flashcards
What is a protocol?
What is a protocol?
A blueprint of methods, properties, and requirements for a task.
What does it mean to adopt a protocol?
What does it mean to adopt a protocol?
The act of a class, struct, or enum adopting a protocol.
What does it mean to conform to a protocol?
What does it mean to conform to a protocol?
Satisfying all requirements of a protocol.
How are protocols defined?
How are protocols defined?
Signup and view all the flashcards
How do custom types adopt protocols?
How do custom types adopt protocols?
Signup and view all the flashcards
How does a class adopt protocols with a superclass?
How does a class adopt protocols with a superclass?
Signup and view all the flashcards
What are property requirements in protocols?
What are property requirements in protocols?
Signup and view all the flashcards
How are property requirements declared?
How are property requirements declared?
Signup and view all the flashcards
How are type property requirements defined in protocols?
How are type property requirements defined in protocols?
Signup and view all the flashcards
What are method requirements in protocols?
What are method requirements in protocols?
Signup and view all the flashcards
Type method requirements
Type method requirements
Signup and view all the flashcards
How are type method requirements defined in protocols?
How are type method requirements defined in protocols?
Signup and view all the flashcards
How to define mutating method requirements?
How to define mutating method requirements?
Signup and view all the flashcards
Initializer Requirements
Initializer Requirements
Signup and view all the flashcards
How to implement a protocol initializer requirement in a class?
How to implement a protocol initializer requirement in a class?
Signup and view all the flashcards
How do subclasses implement a protocol initializer requirement?
How do subclasses implement a protocol initializer requirement?
Signup and view all the flashcards
What type of initializer can satisfy a failable initializer requirement?
What type of initializer can satisfy a failable initializer requirement?
Signup and view all the flashcards
Protocols as Types
Protocols as Types
Signup and view all the flashcards
What is Delegation?
What is Delegation?
Signup and view all the flashcards
Why are delegates declared as weak references?
Why are delegates declared as weak references?
Signup and view all the flashcards
What is the first step to implementing delegation?
What is the first step to implementing delegation?
Signup and view all the flashcards
Adding Protocol Conformance with an Extension
Adding Protocol Conformance with an Extension
Signup and view all the flashcards
How to conditionally conform to a protocol?
How to conditionally conform to a protocol?
Signup and view all the flashcards
How do you declare protocol adoption if a type already conforms?
How do you declare protocol adoption if a type already conforms?
Signup and view all the flashcards
Which protocols can Swift automatically provide conformance for?
Which protocols can Swift automatically provide conformance for?
Signup and view all the flashcards
For what types does Swift synthesize Equatable?
For what types does Swift synthesize Equatable?
Signup and view all the flashcards
For what types does Swift synthesize Hashable?
For what types does Swift synthesize Hashable?
Signup and view all the flashcards
For what types does Swift synthesize Comparable?
For what types does Swift synthesize Comparable?
Signup and view all the flashcards
How do you define a class-only protocol?
How do you define a class-only protocol?
Signup and view all the flashcards
What is Protocol Composition?
What is Protocol Composition?
Signup and view all the flashcards
How do you check for protocol conformance?
How do you check for protocol conformance?
Signup and view all the flashcards
How to define Optional Protocol Requirements?
How to define Optional Protocol Requirements?
Signup and view all the flashcards
What is the benefit of Protocol Extensions?
What is the benefit of Protocol Extensions?
Signup and view all the flashcards
What can you provide using protocol extensions?
What can you provide using protocol extensions?
Signup and view all the flashcards
How to add Constraints to Protocol Extensions?
How to add Constraints to Protocol Extensions?
Signup and view all the flashcards
Study Notes
- A protocol defines a blueprint of methods, properties, and requirements.
- Classes, structures, or enumerations can adopt protocols to provide implementations.
- A type conforms to a protocol if it satisfies all of the protocol's requirements.
- Protocols can be extended to implement requirements or add functionality.
Protocol Syntax
- Protocols are defined similarly to classes, structures, and enumerations.
protocol SomeProtocol {
// protocol definition goes here
}
- Types adopt protocols by listing protocol names after the type name, separated by a colon.
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
- If a class has a superclass, list the superclass before any protocols.
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// class definition goes here
}
Property Requirements
- Protocols can require conforming types to provide properties with specific names and types.
- Protocols do not specify stored or computed properties, only the name and type.
- Protocols specify if properties must be gettable or gettable and settable.
- A gettable and settable property cannot be fulfilled by a constant stored property or a read-only computed property.
- Gettable properties can be satisfied by any kind of property, even if also settable.
- Property requirements are declared with the
var
keyword. - Gettable and settable properties are indicated by
{ get set }
and gettable properties by{ get }
.
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
- Type property requirements must be prefixed with the
static
keyword in the protocol.
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
FullyNamed
protocol example.
protocol FullyNamed {
var fullName: String { get }
}
- Requires a conforming type to have a gettable instance property called
fullName
of typeString
.
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed"
Person
structure adopts and conforms to theFullyNamed
protocol.
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName is "USS Enterprise"
Starship
class adopts and conforms to theFullyNamed
protocol, implementingfullName
as a computed property.
Method Requirements
- Protocols can require specific instance methods and type methods to be implemented.
- Methods are defined without curly braces or a body in the protocol.
- Variadic parameters are allowed, but default values are not.
- Type method requirements are prefixed with the
static
keyword in the protocol.
protocol SomeProtocol {
static func someTypeMethod()
}
RandomNumberGenerator
protocol example.
protocol RandomNumberGenerator {
func random() -> Double
}
- Requires a conforming type to have an instance method called
random
that returns aDouble
value.
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Prints "Here's a random number: 0.3746499199817101"
print("And another one: \(generator.random())")
// Prints "And another one: 0.729023776863283"
LinearCongruentialGenerator
class adopts and conforms toRandomNumberGenerator
.
Mutating Method Requirements
- Methods that modify the instance they belong to are marked with the
mutating
keyword. - Include the
mutating
keyword in the protocol to allow structures and enumerations to conform.
protocol Togglable {
mutating func toggle()
}
Togglable
protocol definition example.
enum OnOffSwitch: Togglable {
case off, on
mutating func toggle() {
switch self {
case.off:
self =.on
case.on:
self =.off
}
}
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
// lightSwitch is now equal to.on
OnOffSwitch
enumeration adopts and conforms toTogglable
, implementing a mutatingtoggle
method.
Initializer Requirements
- Protocols can require specific initializers to be implemented.
- Defined like normal initializers but without curly braces or a body.
protocol SomeProtocol {
init(someParameter: Int)
}
Class Implementations of Protocol Initializer Requirements
- Initializer implementation must be marked with the
required
modifier.
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
- The
required
modifier ensures subclasses also conform to the protocol. - If a subclass overrides a designated initializer and implements a protocol initializer, use both
required
andoverride
modifiers.
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}
Failable Initializer Requirements
- Protocols can define failable initializer requirements.
- A failable initializer requirement can be satisfied by a failable or nonfailable initializer.
- A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.
Protocols as Types
- Protocols can be used as types in code.
- Protocols are commonly used as generic constraints.
- Protocols can be used as opaque types, hiding the underlying type's identity.
- Protocols can be used as boxed protocol types, which allows for runtime flexibility.
Delegation
- Delegation is a design pattern where an object hands off responsibilities to another type.
- This is implemented using a protocol that encapsulates the delegated responsibilities.
class DiceGame {
let sides: Int
let generator = LinearCongruentialGenerator()
weak var delegate: Delegate?
init(sides: Int) {
self.sides = sides
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
func play(rounds: Int) {
delegate?.gameDidStart(self)
for round in 1...rounds {
let player1 = roll()
let player2 = roll()
if player1 == player2 {
delegate?.game(self, didEndRound: round, winner: nil)
} else if player1 > player2 {
delegate?.game(self, didEndRound: round, winner: 1)
} else {
delegate?.game(self, didEndRound: round, winner: 2)
}
}
delegate?.gameDidEnd(self)
}
protocol Delegate: AnyObject {
func gameDidStart(_ game: DiceGame)
func game(_ game: DiceGame, didEndRound round: Int, winner: Int?)
func gameDidEnd(_ game: DiceGame)
}
}
DiceGame
class andDiceGame.Delegate
protocol example to track game progress.- Delegates are declared as weak references to prevent strong reference cycles.
class DiceGameTracker: DiceGame.Delegate {
var playerScore1 = 0
var playerScore2 = 0
func gameDidStart(_ game: DiceGame) {
print("Started a new game")
playerScore1 = 0
playerScore2 = 0
}
func game(_ game: DiceGame, didEndRound round: Int, winner: Int?) {
switch winner {
case 1:
playerScore1 += 1
print("Player 1 won round \(round)")
case 2: playerScore2 += 1
print("Player 2 won round \(round)")
default:
print("The round was a draw")
}
}
func gameDidEnd(_ game: DiceGame) {
if playerScore1 == playerScore2 {
print("The game ended in a draw.")
} else if playerScore1 > playerScore2 {
print("Player 1 won!")
} else {
print("Player 2 won!")
}
}
}
DiceGameTracker
class adoptsDiceGame.Delegate
to track and report game events.
Adding Protocol Conformance with an Extension
- Extensions allow existing types to adopt and conform to new protocols.
protocol TextRepresentable {
var textualDescription: String { get }
}
TextRepresentable
protocol example.
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
Dice
class extended to adoptTextRepresentable
.
Conditionally Conforming to a Protocol
- Generic types can conditionally conform to a protocol when specific conditions are met.
extension Array: TextRepresentable where Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// Prints "[A 6-sided dice, A 12-sided dice]"
- The
Array
type conforms toTextRepresentable
only when its elements also conform toTextRepresentable
.
Declaring Protocol Adoption with an Extension
- Types that already meet protocol requirements can adopt the protocol with an empty extension.
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
Hamster
structure, which is then extended to conform toTextRepresentable
.
Adopting a Protocol Using a Synthesized Implementation
- Swift can automatically provide protocol conformance for
Equatable
,Hashable
, andComparable
. - For
Equatable
, structures withEquatable
stored properties and enumerations with or withoutEquatable
associated types receive synthesized implementations of==
and!=
.
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
// Prints "These two vectors are also equivalent."
Vector3D
structure gets synthesized implementation ofEquatable
due to itsEquatable
properties.- Structures/enums with
Hashable
properties/associated types getHashable
synthesis. - Enums without raw values get
Comparable
synthesis.
Collection of Protocols
- Types can adopt multiple protocols through inheritance.
- Types can selectively inherit certain parameters from multiple protocols but not all.
Collection inheritance prettyTextualDescription
- Types an adopt and inherit parameters from multiple protocols.
protocol PrettyTextRepresentable: TextRepresentable {
var prettyTextualDescription: String { get }
}
- inherits from text representable for more detailed description
extension SnakesAndLadders: PrettyTextRepresentable {
var prettyTextualDescription: String {
var output = textualDescription + ":\n"
for square in board {
switch square {
case let ladder where ladder > 0:
output += "â–² "
case let snake where snake < 0:
output += "â–¼ "
default:
output += "â—‹ "
}
}
return output
}
}
- snakes and ladders implements the detailed textual description with symbols
Class-Only Protocols
- can restrict protocol adoption to class types by adding the AnyObject protocol to a protocol’s inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
- makes it so only class types can use the protocol, not structs or enums
Protocol Composition
- can require a type to conform to multiple protocols at the same time
- done via simple ampersand
- the type must conform to every single protocol
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Prints "Happy birthday, Malcolm, you're 21!"
- has to conform to named and aged, but works
Checking for Protocol Conformance
- use "is" operator to check conformance, and "as" to cast
- "is" just returns true / false
- "as?" returns an optional, nil if it does not conform
- "as!" force casts, so it errors if it fails
protocol HasArea {
var area: Double { get }
}
- define the properties for area with a double get statement
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
}
- implement has area to compute and return a double
class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}
- a class does not contain the properties or conform
let objects: [AnyObject] = [
Circle(radius: 2.0),
Country(area: 243_610),
Animal(legs: 4)
]
- create objects to apply conformance check for
for object in objects {
if let objectWithArea = object as? HasArea {
print("Area is \(objectWithArea.area)")
} else {
print("Something that doesn't have an area")
}
}
// Area is 12.5663708
// Area is 243610.0
// Something that doesn't have an area
- cycle through and determine properties and data associated
Optional Protocol Requirements
- can define optional requirements for the protocols
- do not have to be implemented by conforming types
- optional requirements are prefaced by the optional modifier
- both the protocol and optional requirements must be marked with the @objc attribute
- protocols with this can only be applied to classes, not structs or enums
- when methods or properties are used in this context, the entire function type is wrapper in an optional
- optional chaining can be used to account for missing implementations
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
- example with both an optional type, and variable that are optional to the protocol
Counter Optional Protocol Example
- counter class and example on how to implement optional protocols in swift
class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.increment?(forCount: count) {
count += amount
} else if let amount = dataSource?.fixedIncrement {
count += amount
}
}
}
- an incrementer for counter data with a null check
class ThreeSource: NSObject, CounterDataSource {
let fixedIncrement = 3
}
- A simple implementation with increment of 3
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
counter.increment()
print(counter.count)
}
// 3
// 6
// 9
// 12
- for loop increases by 3 demonstrating functionality
class TowardsZeroSource: NSObject, CounterDataSource {
func increment(forCount count: Int) -> Int {
if count == 0 {
return 0
} else if count < 0 {
return 1
} else {
return -1
}
}
}
- complex data source example that counts to 0 from negative numbers
Protocol Extensions
- extends protocols to provide methods, initializers, subscripts, and computed properties
- defines behavior on protocols themselves, not conformance or global functions
extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}
- generate random boolean from random, all conforming types automatically get method
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Prints "Here's a random number: 0.3746499199817101"
print("And here's a random Boolean: \(generator.randomBool())")
// Prints "And here's a random Boolean: true"
- print tests the bool and ensures works
- Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol
Providing Default Implementations
- provides default implementation to any method or computed property requirement
- if its implemented on the type itself, then extensions default implement is ignored
extension PrettyTextRepresentable {
var prettyTextualDescription: String {
return textualDescription
}
}
- example of a type returning the standard implementation for textdescription
Adding Constraints to Protocol Extensions
- only available on conforming types that satisfy specific contraints
- generic Where clause must be implemented
extension Collection where Element: Equatable {
func allEqual() -> Bool {
for element in self {
if element != self.first {
return false
}
}
return true
}
}
- example for checking elements in a given collection via a return bool
let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]
- numbers for testing
print(equalNumbers.allEqual())
// Prints "true"
print(differentNumbers.allEqual())
// Prints "false"
- tests that appropriately return true of false
Studying That Suits You
Use AI to generate personalized quizzes and flashcards to suit your learning preferences.