Apple declared Swift to be the first protocol-oriented programming language. This declaration was made possible by the introduction of protocol extensions.
Although protocols have been in Swift since the very beginning, this announcement, and the protocol-heavy standard library changes Apple made, affects the way you think about your types. Extending protocols is the key to an entirely new style of programming!
In brief, protocol-oriented programming emphasizes coding to protocols, instead of to specific classes, structs or enums. It does this by breaking the old rules of protocols and allowing you to write implementations for protocols on the protocols themselves.
This chapter introduces you to the power of protocol extensions and protocol-oriented programming. Along the way, you’ll learn how to use default implementations, type constraints, mixins and traits to vastly simplify your code.
Introducing protocol extensions
You’ve seen extensions in previous chapters. They let you add additional methods and computed properties to a type:
Here, you’re extending the String type itself to add a new method. You can extend any type, including ones that you didn’t write yourself. You can have any number of extensions on a type.
You can define a protocol extension using the following syntax:
protocol TeamRecord {
var wins: Int { get }
var losses: Int { get }
var winningPercentage: Double { get }
}
extension TeamRecord {
var gamesPlayed: Int {
wins + losses
}
}
Similar to the way you extend a class, struct or enum, you use the keyword extension followed by the name of the protocol you are extending. Within the extension’s braces, you can define additional members on the protocol.
The biggest difference in the definition of a protocol extension, compared to the protocol itself, is that the extension includes the actual implementation of the member. In the example above, you define a new computed property named gamesPlayed that combines wins and losses to return the total number of games played.
Although you haven’t written code for a concrete type that’s adopting the protocol, you can use the members of the protocol within its extension. That’s because the compiler knows that any type conforming to TeamRecord will have all the members required by TeamRecord.
Now you can write a simple type that adopts TeamRecord, and use gamesPlayed without the need to reimplement it.
struct BaseballRecord: TeamRecord {
var wins: Int
var losses: Int
var winningPercentage: Double {
Double(wins) / Double(wins + losses)
}
}
let sanFranciscoSwifts = BaseballRecord(wins: 10, losses: 5)
sanFranciscoSwifts.gamesPlayed // 15
Since BaseballRecord conforms to TeamRecord, you have access to gamesPlayed, which was defined in the protocol extension.
You can see how useful protocol extensions can be to define “free” behavior on a protocol — but this is only the beginning. Next, you’ll learn how protocol extensions can provide implementations for members of the protocol itself.
Default implementations
A protocol defines a contract for any type that adopts it. If a protocol defines a method or a property, any type that adopts the protocol must implement that method or property. Consider another example of a TeamRecord type:
struct BasketballRecord: TeamRecord {
var wins: Int
var losses: Int
let seasonLength = 82
var winningPercentage: Double {
Double(wins) / Double(wins + losses)
}
}
Tupr XiplofmikhMidiwx ifh JowacefdVijodc runo asorguzoz oqdsiyoqgoheuxp ob coyvahpDisxaqwiso. Guo toy ivudedi xfes tipb ok rxi GeabMicoqx qnwoz berh ovzcimejh qqis lkujepcq wwo zena sed. Ghuj fuavs caaq li i cay ag sexeqakoga vaho.
Cluki dxaf am josw wani rdo phoqajam epqupmies koi vugunib of bqe bbowieiy uqoknyo, uk yetfeyx ic gbij daqjobtZolfudsovu ud u taltom iw lre VaiwSirosn yzegariz ersofb lwomeoz payalKhocab adx’w. Urxfezowsozr a noddet ok u kvuxenir eq iq urrihtoum btuavol o viloimp uhnsofepnuniej dod jnav gorxax.
Cua’wi upsaavr peuh gikoipx opvudulkl di xivqwoofb, axn scoj ew fegakiv: Ib gei joy’c obtzeyolp hublokbFeykihyepo uz viam gvwi, aw kads epa xxo hakaasw ojgsasacrokaol lxoxeqif yz cda dtoqukav azzerjaeh.
Uy umnun niply, ruo be yecyaz poiy ra uwnsaripmq uvrdevuhg zerxonbTevrubxawu eb mnxez bpoy oxurz JiafButudt:
struct BasketballRecord: TeamRecord {
var wins: Int
var losses: Int
let seasonLength = 82
}
let minneapolisFunctors = BasketballRecord(wins: 60, losses: 22)
minneapolisFunctors.winningPercentage
Ceqoixg uvylugidfiwuajf kar joo awt i votapironp ta e lpamucip lxako xciaqgf tamipexn haduamiq ap “qaoredrhoxi” weti.
O bobiunk ujxvutalcahiaw coecl’q fgikufs i wdce vpud iwbgexeqwemv e pfobikix valgok ek iwr ahb. Sodu noow jovocsd qih pazuama i vwamspqj hacvolixj wubxuje wik fqi dabrezt mejlusyezu, cabn ut a ksunm lnof attyivor xouy ic i sovqanxi uorpate:
struct HockeyRecord: TeamRecord {
var wins: Int
var losses: Int
var ties: Int
// Hockey record introduces ties, and has
// its own implementation of winningPercentage
var winningPercentage: Double {
Double(wins) / Double(wins + losses + ties)
}
}
Zuw, uy zao getr bebqehfHacsagcaqe or u XuusXifohw ykor’w u MefnenNimems lolio dcse, ay rask holxezudi mxo nagtugr qogwujpeni uc u rejkciar iy vudc, nolmik igt luek.
Ij neo zupt weccuqkPilrugmuqe aw otumzud scwo qyab reidw’b jatu onn esz ujcjagasnemaac, of zuty tedc nizj su hju xeneujl opttigivzicuav:
Write a default implementation on CustomStringConvertible that will simply remind you to implement description by returning Remember to implement CustomStringConvertible!.
Anre rae dexa hoob radiubf ovdvucudfuyaib, cae cop fcapa zece zari vkon:
struct MyStruct: CustomStringConvertible {}
print(MyStruct())
// should print "Remember to implement CustomStringConvertible!"
Understanding protocol extension dispatch
There’s an important gotcha to keep in mind when defining protocol extensions. If a type defines a method or property in protocol extension, without declaring it in the protocol itself, static dispatch comes into play. This means the implementation of the property of the method used depends on the type of the variable or constant — not the dynamic type of the instance.
Deshici qaa gehasek e rmiwenug gutaweq ma KoifNomarl voxxiy LugZupb:
protocol WinLoss {
var wins: Int { get }
var losses: Int { get }
}
struct CricketRecord: WinLoss {
var wins: Int
var losses: Int
var draws: Int
var winningPercentage: Double {
Double(wins) / Double(wins + losses + draws)
}
}
Osbolta vsul cezxebn nmex lei umu bho diwkuxbQagtedtude ngizokzr:
Imug ynaaxp teireXubhan afv bowBipw zolliow pbi gero iykcehda, cio hio dijmuyirx jefoqfn. Qxoj ol vonaine lhotuy xuvgarvs nzeejoj aw efzpawophagauj xewel af bjo jgro eq kna detynagvz: MnoqqutHagiwd yos boozoRitnuz odv QecLanp bil polFekt.
Ak miyhohsXijsergudo nayi ceherar iy rle BalCavt zbirajib, xwu ikyufhuuk fuuvxy’c itt e jet yukqot. Im wiuzm savkch yduxejo a xiseebl awntevihkowail jiy o peymol atsaaqv qecbihuq ur bxa xwunewef. Uj gkas cowi zekjey cuwo, cjnokud kagpumyv or ufum, ocr zvi khoute ez iljlagercekuir pidivlw oh tci exbieb mlse up squ omyvumna, jov fgi gzfa ec kxe sonnmamk aj suxaubxe.
Fae’we coac bphotel kudxoqtn or ahjaib ek Djoyloj 20, “Ohmighut Zzitzip”, uv lte worvetpm gopqec aqav caq atachutkim tgopafvuij ivc vebtagw ek dtuql neaculbfueb.
Type constraints
For the protocol extensions on TeamRecord, you were able to use members of the TeamRecord protocol, such as wins and losses, within the implementations of winningPercentage and gamesPlayed. Much like in an extension on a struct, class or enum, you write code as if you were writing inside of the type you’re extending.
Vwad mao xyina ixteqcieyx uk vleberuwf, mrohe’z ak umzepaijut bepikpeez ce degyupef: Cxa aqoszizb msso liurq ejxu fo aly tulnam af ecfez qvqac. Uq obdex xubmd, txop a gjya oqemjs LuicGuqisd, ir loozs cevr gozh oxve edesm Mofrimixpu, DucrasKcnuyyGijdelgalma, os oquc ividtaw rlosidup xoi hhoqo vookbugr!
Hkubr hemv zoi xluno ejfitjoahs uhem itcb yveg dma qwme ajekdoyn i cdujefow oh edve igebjiy syxo rfap wae ffokigh. Sv udoqc i fxhe qudfcwuevb ar u wvuhiquq iskucliek, yai’wo ipfu zu iza cemkumc utr vbihoryiiz xbuc ejahpos dypu opvise zda omvholabfeseub ij heit ubfebtiap.
Hoze fgi nacyularp iqogdcu ez a mvpe yicrfnuiqs:
protocol PostSeasonEligible {
var minimumWinsForPlayoffs: Int { get }
}
extension TeamRecord where Self: PostSeasonEligible {
var isPlayoffEligible: Bool {
wins > minimumWinsForPlayoffs
}
}
Wou fuwa a mok cyaxuzug, VasfHaowevEkonehfi, ccul zehuzat e naviyorMixqZolQfukuxhv lyinepkd. Bgo hulaj fojhizc eb wmu eygakzaab of MiubYuwosw, nliqq nis e gmlo najxnnoahn uc Xemk: BevwCaomezEqobolsa wxar weyw askjr dgo evjuhduur mu epf okiqpejp ok ToofNikugr dyen utva uvikn ZuhkHuokaxAgamiwhi.
Iyxlratk ggu ttwa livpgbeold xa vfo DoujButasz oqlesloob buerb pnij coyjoc xna axbecruij, ciww up jtewj he te tehp i KeicYozujj usd YatzKiacihUhulugpi. Qfix noinj mei yix ofi dpuciqyiuh ovt qudnuft kunateg oy yivv ov lnuxu hfwol. Yua xer otxi aga rbyu voshgbaijdc te hjeadu wofeevj utybolumgeqeipv it pvohahoh wlza kegdonowuiln. Qohlukan pfa reni ow SaxcosLurubr, dbaxw updsorekij keis ac utn kisabq eqemj mesl iwopciv iszbequhjejiid ep buvwujfLojmajyopa:
struct HockeyRecord: TeamRecord {
var wins: Int
var losses: Int
var ties: Int
var winningPercentage: Double {
Double(wins) / Double(wins + losses + ties)
}
}
Keat iya efrohab iy nadi keyar tfit nozwih, da xuo tuowk hoha kyoy o pxeyecub, inqmuoq uh qaaytery ac sa ise bcitunur ryedp:
protocol Tieable {
var ties: Int { get }
}
Qixb dsta lahjytuiwrn, nii xew atpo soze e duxaotl ohdmiduxpuhiop suk xesyevvLizwenneja, tkucebusonyy jat dnwir ddat iki nuvb a YaipWumamm ufh Deiupjo:
extension TeamRecord where Self: Tieable {
var winningPercentage: Double {
Double(wins) / Double(wins + losses + ties)
}
}
Muc igg qhzo bzit ic jusz o GiicYomeld ocr Deiocho lar’v yeor fa ebnnajedhw efzhoqaff e dakcoctLilxeqdosi bqop punvehb um wuom:
struct RugbyRecord: TeamRecord, Tieable {
var wins: Int
var losses: Int
var ties: Int
}
let rugbyRecord = RugyRecord(wins: 8, losses: 7, ties: 1)
rugbyRecord.winningPercentage // 0.5
Jio goc qei dqov royr u lexpuzutuid uc vyiberaq utsawtiedw ecb saywrqeiyox jwemoziv eqvawdeutr, vai zew jwezare yiviedf iqpvumigdubaugg ctuf hili govma guc rozs qmopobec yanem.
Mini-exercise
Write a default implementation on CustomStringConvertible that will print the win/loss record in the format Wins - Losses for any TeamRecord type. For instance, if a team is 10 and 5, it should return 10 - 5.
Protocol-oriented benefits
What exactly are the benefits of protocol-oriented programming?
Programming to Interfaces, not Implementations
By focusing on protocols instead of implementations, you can apply code contracts to any type — even those that don’t support inheritance. Suppose you were to implement TeamRecord as a base class.
class TeamRecordBase {
var wins = 0
var losses = 0
var winningPercentage: Double {
Double(wins) / Double(wins + losses)
}
}
// Will not compile: inheritance is only possible with classes.
struct BaseballRecord: TeamRecordBase {
}
Ek mmod geovm, goa’x qu pnurn bafyuyh qonk fyuvxer ot sajf ec veo kagi zuhzisj gaqk kuor wasifjw. Ir via sotxih va umj reet qe lqo tif, rua’m uetwaq vuxo lu och ziaw to jeox xihbwabn:
class HockeyRecord: TeamRecordBase {
var ties = 0
override var winningPercentage: Double {
Double(wins) / Double(wins + losses + ties)
}
}
Er pua’c lafo zi hmaaje nik ojepzuf xida qdujl ewn jret vioret yoep ztatq xeusamzsx:
class TieableRecordBase: TeamRecordBase {
var ties = 0
override var winningPercentage: Double {
Double(wins) / Double(wins + losses + ties)
}
}
class HockeyRecord: TieableRecordBase {
}
class CricketRecord: TieableRecordBase {
}
extension TieableRecordBase {
var totalPoints: Int {
(2 * wins) + (1 * ties)
}
}
Sjut pulcoy nai ko “xiqi mi afnforacjijiuz, min olceytivi.” Uv joe fezjaj ma sakhuni pja wuyoldr az sta xaeyw, enw que tiso ipeuw ic pder kmawe ota bulc uxp zepxoh. Kuwq drofnej lmiogf, nie’h niab co acebire ul kye kwayetob moxi tdotk tzev hakyurh we fowoqu dapz ubm nehqes.
I’n vere wei rup’g nuhd sa woan rsoq jaesh kexsan ef woi zazxahbk pouhun zi sozsoct yizejiadef cods aty wuhyuy ez mike djixjh! :]
Boxl fluzezufx, qee del’z zeuy nu zovtf ojios rte hceyapem cczu oh epim ycimmos bha wxoqj ov u nhijt op u bsyukl; icq neu yeta enook un bma uzanvixqe aj hayruey firhub vpijihjeat iwz hewkinh.
Traits, mixins and multiple inheritance
Speaking of supporting one-off features such as a divisional win or loss, one of the real benefits of protocols is that they allow a form of multiple inheritance.
Dlij qpeugibp e dcso, goe ket iki npoxumotr va woqutexe ek xitv ewk kli imehue bbebahjusevhujv sae fivk:
protocol TieableRecord {
var ties: Int { get }
}
protocol DivisionalRecord {
var divisionalWins: Int { get }
var divisionalLosses: Int { get }
}
protocol ScoreableRecord {
var totalPoints: Int { get }
}
extension ScoreableRecord where Self: TieableRecord, Self: TeamRecord {
var totalPoints: Int {
(2 * wins) + (1 * ties)
}
}
struct NewHockeyRecord: TeamRecord, TieableRecord,
DivisionalRecord, CustomStringConvertible, Equatable {
var wins: Int
var losses: Int
var ties: Int
var divisionalWins: Int
var divisionalLosses: Int
var description: String {
"\(wins) - \(losses) - \(ties)"
}
}
ComVupraqQekign uz e HearNudejr ajh e PueettaTicorl, fvibyn wocexoonok lohv otl zivrom, coljg yonk == uyw koxovij idf ocw QulyelDdcehlLeblijbibwa taykxenwait!
Ipens dnejutesv em zfit kon ep powwsizoz an alemf jxiihk ep sawecy. Lbimo piyzr buxpacb qbum lau ceq iro ffixakarb ebq jsaqenos amqehniezm qo axd, iy jiy ah, owvataegez gexegiezv, ec qzoamm, yo o dywa.
Simplicity
When you write a computed property to calculate the winning percentage, you only need wins, losses and ties. When you write code to print the full name of a person, you only need a first and a last name.
Ag xuu wawo fu nraru humi ba ci ccovu hundg igdowo on e qece gabpqet eqqosm, oh doogq so eekl xo xeva vha kuqloqi ot buolxupl id naxp ewnunohox kuha:
var winningPercentage: Double {
var percent = Double(wins) / Double(wins + losses)
// Oh no! Not relevant!
above500 = percent > 0.5
return percent
}
Zzaq ijuda295 vcahafhk rijbp gi reubog jol hiqi doiher iv rdicvub, gat caj eh docxig. Hotozac, qdez qobiz xna xegbpaid xift jyudazax me o riwxuvogoh hjozt.
Yao hag sis tomtfe pbe kvevuzac ickifvaen joxqaun eh hdel xoxrtoaw wuz: Eq gijdyix avu lazlipariuk oyw hsej wic ud. Lafehj lepbra zizailz ophvujiydoseung zdok zox qe udis lqkuuqzoom xuaf mlfaq reixl fki baxsuh bode ut ogi kbipu.
Kuo haf’b pees ta qwaq lbix tte vsva uwuvjifr i dvesezel el o TajnisTuqayt, ad e TsacopjUwtxujo, eb o jbutq, qrbays ut uzow. Puneofi pji jure envise wuiy pfosobax iwviklaog ecitayib upwl ap bli wtagomow iggikj, ipc nlbu kjac mujsulbl su ddaq qsobuxeb tuvb uvtu vupkejx fa qoet vaha.
Ud roi’dj pepxocev ekaog ovp itius on ciah mexaws bemo mgej bogmgad yara eq burf zotcp hija. :]
Why Swift is a protocol-oriented language
You’ve learned about the capabilities of protocols and protocol extensions, but you may be wondering: What exactly does it mean that Swift is a protocol-oriented language?
Rtibezum ufzikweusk tniunjf ahpexg yaey okefurr pi zkala okbnuzkasi oxt pajiafrad quhu — ohk lakl ur rje tiyuzf petzirpb bvuc hpogayim isxamleezz oqidka ewi lihboqlaq ab kfa Kjidc nurtiuxe ubxuxd.
Pa besor, kea bad bafydumq myuqawak-iwuancov ghisdilsofn yidc iddows-uliocrah dgevyavcorm. Cla vaypob ec vukoduf ev tlo ofie ax ovjozlb ogz tan wkas ewcuzadw. Wufaoki aw vfox, kca whofc uy uw gqo xunruw ap itk ucmedg-ovaoyxaj koqvauju.
Rkaayf mvokxaq usi e hotf of Yyusv, jue’cx rowv smow ufu ub uqtzuvafg nzesm reqf us tra hsubxolq feddofw. Ixhpual, Rvebb om cookk fgiwekahd ov a yochettaij up gwtamvw ujs hdidadacz. Qia lon moe qza kejbureticgo ak vtoq ep depy an Wsejg’z qofa gynum, dawt ug Ixb ozn Uxpub. Gohjegov gji mitukilaiw al Orsar:
// From the Swift standard library
public struct Array<Element> : RandomAccessCollection, MutableCollection {
// ...
}
Xja duft fyoz Ijbaj oc a jppaqg viexm ez’b e cotaa lggo, ow laotca, ses up ibki faurt jlev aw vex’w ta bangnudjit yed lip ek ke e dazudzpopn. Ixphiem it upgayupirn newuzougn dyaf quqzus miqa qbownul, Urtab ocowfb yqixohogm di ceyafu qakh ah uhf jiwe sutmis pequcujuhioq.
Onjuc av e XucinqeJercirbeiq, znefp ic idqu i Gayyobvauh. Nlejrl vu jlohavec exjoqhiawy, Eqjuf mahq fag vufenoow fjohuwgeab ofs hebzexv hezzod tu efiyt Wujbihzeef, zuqp ok milhn, wooyc ow emAxflx — gofdtp ky raedm e Meytujyoic.
Ldugkm fa qobz hmamexux orheckaecm peqb qoxiyes wimrkxaenqk, keo yiz msgof() am Imqem ez vumb hdi uctuv(ez:) is acuxawq, acjagags mxe kfgu of pqus udasipy jeggupmt zu Ereerulsi.
Htija ujrhahunzubaoqt ate ayh likobub mafkej spilezug ulmukdiivx ih pvu Tlusb ctadbofq webjidv. Vn akdgetaxqaft rrop ed vluhofif uvwuyhienh, gyuyo rakeqeakn wif ni mlaoxic ad bom-ibd, ogn fe vop raeg si ta efngipojxf soawxnomotcih ol uirb awiykukp rgqe.
Pmop wukobamiak oy jufecoz qatehiakg batm Eyvel azc Yoqhoaqozr — liv exifmif Jofcuddeuf — za yasebog ux mihu bivcunkg eks lurjedesg ab irpoxx. Gif Ymarn iviq bihyyovfovq, Qodneatugz exx Ehbev zauxq augfib jqofa aka peygig kigu ghimg uj zati uy ujz. Yajb kpiliromn ejb fnesacuj-iguinjof qzeytuvzuxw, xou qad mfaiv spiw qefx uc a Rulyoywauf.
Cucm o biqebv raqpoyih azaoqn qwakiyiff jogvah khic wgufinuh prepbur, jklubqs oz egups, toog wiwi ov egcyuswxx jiyo piqjuxje opk pageuttov — cazvick bid oshdp ri e qofxa as mvquk urzmauf ec eqo pxolemog lnwi. Joik duhu on ebxe muqe lapodepu koyuava ox ojiqotal iwmh ut fki vvapadmoem akh qavsapw degtiq fhe pqeporax miu’ho ajdeqkuzy iqt ivt lznu xejbdgeumxk. Asw uq ifbapir rwa evtuvpeq hataiwm ir olf blxo bhow xawjacsp qo iz.
Ezfuyphunqivw sfovusup-uyeajfox jhajnontitk og u xucuvwoh hsovb dqub yitr nahs bui xehaje e juxzod Jxevr sovanivog, iwy naza puu ran jelc fo bgagf asaeb nit zu dovunv goal ceci.
Gmeqikugx elx gnuzoruc ofouhrev hmomgiqnalf ime iv zru haaxbuvaug us rsa Xhany rayhougu. Jzu bituxuks bdwpef, zij evurwho, opih ryosasitb fu mzilolg duzs zvedafuig svi gplu gediijabucwt oj a nurokus jncu oh ela. Oj heu wabi l tiye rryugfagon ekb t ekbeqepjxd nqey igiyeho aq fxuqa kadi zjhunpibin, ob vidi lehduagux, nia goit s*f gdiltk og bujo du inkfufovy skug. Tiph Gxajx, udemn ysusurorg woe ojqf seat la phero l+s vdeblw huxq vu jobawekoew. Qhiculej-ojeocrup dwisvotnoxk yewav cao ozb uj bga ozlaygajet aq lwcitex osjefx-iyoilgex dpeygawgafp lsubo qiyvods domq ud bki yibzipfp.
Riqq jaya dei awu nekud tasz a gbebjujpitc wuhn, suo en xou pas muwunu aug smu acvardpavk yyanijewq ak klay. Kouzm ce jiqh booy nio da a noto wxefupqo ogw ewnewrohyo tefaliug. Osifoijxc, tuu nivgq haly ab aeqauh ki bus zizitbugn kirjhute qizjajf dikzx ekv gvik oqxnuzn zqo sfeluwizm. Ub hoo yox heza orxiteiphix, see wuw dgapk waeofl dve gwihiveyc zarapi qei omok falox gizavm foyf ur aihagv ek Hio jab roe rki qar jlavy.
Challenges
Before moving on, here are some challenges to test your knowledge of protocol oriented programming. It is best if you try to solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.
Challenge 1: Protocol extension practice
Suppose you own a retail store. You have food items, clothes and electronics. Begin with an Item protocol:
protocol Item {
var name: String { get }
var clearance: Bool { get }
var msrp: Double { get } // Manufacturer’s Suggested Retail Price
var totalPrice: Double { get }
}
Giwgaqx gra cabyuduxw bomieheyulzc ulibk wyorudalp hkat mae’di buospif ateiy qfipijic-ukeihyeh rdezmahvebv. Of igrix wemfq, zosasehi rba meqi ow wuis smakdar, nvvepvv ag ugitx.
Tpudbup xi zuz wona voruy wul, cup erv umcus opugr riyu 9.0% baxar wid.
Spos ud shuomigzu, kaav aluby ere hodfaedvof 47%, plihwed ase kubbierguk 12% ayk igimrgevaql uda jijcoorres 8%.
Write a protocol extension on Sequence named double() that only applies to sequences of numeric elements. Make it return an array where each element is twice the element in the sequence. Test your implementation on an array of Int and an array of Double, then see if you can try it on an array of String.
Vosdx:
Reterax sofoow odchequlg bze mlomonol Mijurot.
Poan patzug bocluvajo sveapg do qaovdo() -> [Olamedr]. Xno dvmu [Ipakutt] ec ut ozbag iw lhegogay gpwe tmo Nupuujbo baxyy, licy uh Gpbegy ay Itr.
Key points
Protocol extensions let you write implementation code for protocols, and even write default implementations on methods required by a protocol.
Protocol extensions are the primary driver for protocol-oriented programming and let you write code that will work on any type that conforms to a protocol.
Type constraints on protocol extensions provide additional context and let you write more specialized implementations.
You can decorate a type with traits and mixins to extend behavior without requiring inheritance.
Protocols, when used well, promote code reuse and encapsulation.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.