CustomStringConvertible
Part of the Object Oriented Programming section of Coddy's Swift journey. Lesson 37 of 57.
When you print a value, Swift shows its type and properties by default, and for a class only the type name. Conforming to CustomStringConvertible and providing description controls the text:
struct Money {
let cents: Int
}
struct Price: CustomStringConvertible {
let cents: Int
var description: String { "$\(cents / 100).\(cents % 100)" }
}
print(Money(cents: 1250))
print(Price(cents: 1250))Output:
Money(cents: 1250)
$12.50description is used by print, by string interpolation and by String(describing:), so one property controls every place the value is shown:
struct Point: CustomStringConvertible {
let x: Int, y: Int
var description: String { "(\(x), \(y))" }
}
let p = Point(x: 2, y: 5)
print("start at \(p)")
print([p, Point(x: 0, y: 0)])
print(String(describing: p).count)Output:
start at (2, 5)
[(2, 5), (0, 0)]
6Classes benefit most, because printing a class instance otherwise shows only its type name:
class Account {
let owner: String
var balance: Int
init(owner: String, balance: Int) { self.owner = owner; self.balance = balance }
}
class NamedAccount: CustomStringConvertible {
let owner: String
var balance: Int
init(owner: String, balance: Int) { self.owner = owner; self.balance = balance }
var description: String { "\(owner): \(balance)" }
}
print(Account(owner: "Ada", balance: 5))
print(NamedAccount(owner: "Ada", balance: 5))Output:
main.Account
Ada: 5Keep description short and readable for people. It is not meant for parsing, and it should not change the value:
enum Status: CustomStringConvertible {
case active, suspended
var description: String {
switch self {
case .active: return "active"
case .suspended: return "suspended"
}
}
}Challenge
EasyMake the struct Fraction (numerator, denominator) conform to CustomStringConvertible. Its description shows the fraction in lowest terms: 6/8 prints as 3/4, 4/2 as 2, 0/5 as 0, and a negative fraction keeps the sign in front (-1/2). Write a helper gcd(_:_:) for the reduction.
The supplied code reads fractions a/b, one per line, and prints each one with print.
Your code goes in Fraction.swift and Functions.swift. main.swift holds the supplied input/output code and cannot be edited.
Try it yourself
// Supplied input/output code: keep it as it is
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
let p = line.split(separator: "/").map { Int($0)! }
print(Fraction(numerator: p[0], denominator: p[1]))
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesMethods and selfInitializersClasses Are ReferencesRecap - Library Card4Encapsulation
Access ControlRead-Only From OutsideGuarding StateFailable InitializersRecap - Bank Account7Polymorphism and Generics
PolymorphismType CastingGeneric FunctionsGeneric TypesRecap - Shape Calculator5Inheritance
SubclassesOverriding MethodsInitializers and superfinal and HierarchiesRecap - Employee Hierarchy11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Swift playground