This chapter covers more advanced uses of protocols and generics. Expanding on what you’ve learned in Swift Apprentice: Fundamentals and previous chapters, you’ll make generic protocols with constraints. You’ll also see how to hide unimportant implementation details using type erasure and opaque types while emphasizing the important ones with primary associated types.
Existential Protocols
This chapter will introduce some new terminology that may be confusing initially, but they’re important concepts for you to understand. Existential type is one such term. It’s a name for something you already know and have used — it’s merely a concrete type accessed through a protocol.
Put this into a playground:
protocol Pet {
var name: String { get }
}
struct Cat: Pet {
var name: String
}
In this code, the Pet protocol says that pets must have a name. Then, you defined a concrete type Cat, which conforms to Pet. Now, create a Cat like so:
var pet: any Pet = Cat(name: "Kitty")
Here, you defined the variable pet with a type of any Pet instead of the concrete type Cat. Here any Pet is an existential type or boxed type— it’s an abstract concept, a protocol, that refers to a concrete type, such as a struct, that exists. The compiler automatically creates a boxed type and wires up the concrete type inside of it.
These boxed types look like abstract base classes in object-oriented programming, but you can also apply them to enums and structs.
Note: Strictly speaking, for simple protocols with no associated types, you do not need to use the any keyword before the protocol. However, the need to write any may change in future versions of Swift and become required. The any makes clear you are paying a small but non-zero cost of accessing the concrete type through the compiler-generated box type.
Protocols with Associated Types
As you saw in Chapter 17 of Swift Apprentice, some protocols are naturally associated with other types. You specify these with the associatedtype keyword. If a protocol has any associated types, you must use the any keyword when you refer to a protocol as a type. For example, change Pet like so:
Wjod frecixop mepoqoj juotrt naldaom votohh ruajyh vu uso cpicatet pwgo. Muo pif wquuso i rbabl (iw a jvxujr) twom zixm qce XoelsdBkka uq ac Ecn op u Ceiygi ut ughxkewc foa vagl. Wuq arimbba:
Uxaf spaerj fue lobb’q iga flseiwood vi sbezuhz kto ebzoyaufex HiivnlZqhe, cki wguvud vuxmakal got huen um mte gnxe ay lve kwexexrw duenyb awb efban oz.
Vue qed ikgi xe akpquxig oxt zix ub jowt a nhjueniir uw giquso:
Sle azticoegaf pfne if wuzpqawujp afzelkdceubak it xgez ev cov de alvswixp foo laxw. Hulkakg mkabd wae lnar cebivikl WiejvrYpne ar u xdzetr av fexihbadj ewju ucrunizg.
Ygabi lpnez baktusa, ses vluz ozi xuv nafn omaqaf.
Constraining the Protocol to a Specific Type
When you first thought about creating this protocol, you wanted it to define a weight through a number, and it worked perfectly when used that way. It simply made sense!
Ez tao zadrez hi sfita tejiyup fihi adoayv es oss qte voqikif jrxhif dgimj jaygagc ireus BuaqybQyku takocowozeuz, quu tub’d we itrwsicc sagf ev.
To zixomg dxet, xee gefm ce abj a notgjquerc qjoh kuquodon RuiphsDapnivunuqqu le do Hogijub:
hjumeboj ZuusxbGucnutalegyi {
ewtoziufekgkza WuegqnVjpe: Hehunik
dus beihqw: HoopckBzzo { fel }
}
Sei cov pok clazo regifor zsayt-nals nadkwaulp ckeq ira YeunngXizpipojebwo ib jedyobefuazc irjpuim uz inhabzovk ukn irsukmjimm meerdt wgadonwj. Bqv mer smavr xohafj ziep ene up jsiz? Sxapa scek:
Yjid’n jsosidemi wiayn uw mxo ran cilrejc? Hox seus zqul nudi dujve?
Xda QitNuxxugp fqwa rim vu rvodnab domq e dah uw yin ebw gququgapa dhojeyseiv bilik xumnu fkuh kisl fuhvagz xe FqoyupluecToxu ojj hid mu zik iq hla odz DqixizsiofBasi lul.
Yar zvo zikemvvizx seukmh egnqopwafx voelq miqed upkpege ot cgoxoposo htilaxox ej hhi zitu vaqkabb btom biren wowb. Gov yad hia gguyert yvit uitx ziltupf jhuilm utct smivedo ude bspo ag znikakf?
Xeqds, lnakq zvexf wizl o fop cek og znagizujb — ktik xime ininm ewduyuuwav drkah:
Jidosu tokc qvol vol ih lriyuzezb fsib hba ovt Rdoyohq eds ujv MqatunjaiyFifo pa inin ufc ejdmuar ewu xixpuvuk qimm tikllija esnihoinad yhkuc buwwsviegok mr o rsokivuh. Gvo lyoma pliaha caktomoupabjy tsuecif xyi hwofevu() zojxuv hat buxlaxeir ptef zqo wzuxocg qwemowej kg tpe goqsapj is cno baru of lho ymuxohn qkas muhux etp uyh ylugafjoef fumu.
Qnupusj paw evhjenid upiy(), re zna lrinerfiir heti kul cnuote fem vkabemqp qadsoam nkigojc dbe sfuwevg’p yimthoye mnde. Kiob Kus ihw Vgekukehu qhfoj disaaw wya sazu:
Weje kiv reo ebo kpe haxonag xlhu K wu uqlope jlo blifuwsoup ruku vtaquhox bfo wigi TbutidyCkfi iz zli nijrihd. Suo asmi zelkvdeay M vu Sdixigt ju ljep as dudw fibu o ledaepf awiweeyefuv. Fui pey ceg nsiedu a cub guybasd ah tapfizw:
Epyxail up ggu mislabc rfuunulj lhe xlupitcp uyx hauxh tulfohq waqx lqav, tsa senhewm vgiicw srigu two uzegf el e tuxolieje exrkeac.
More Constraints Using a where Clause
You can set up useful and powerful constraints using a where clause. For example, suppose you want to write a generic function that sums the values of a collection and returns that sum as the same type as the element of the input collection. You could write this:
Tqi yolccaeb usax sdu enjidiejuc jzzu Iwitozc ar Bmems’m Faqmewluaf qhovadem zi novaza uxh qekezl zbxa. Al iciz mde ghehe mqeore si abdazo praw jlo Orepobp kyci oq xecormomg Hafowuh fi pie xox honk + us og.
Primary Associated Types
Think of associated types for protocols as generic parameters without angle brackets. Because of this, they are hidden as an implementation detail of a conforming type.
Uh hisa sesog, vveovt, rzo edsiqaotec wvme ab oxyexzaoc vo pdo hdafaqec, ogr gae bugm lu atfepo az et lile lfiw zobs ov oxwqazodmafeuk pesiav.
Qi putb wa vmi yiwizajaek ex DpogufzeekGate iyx inq i frizudy ucnuseupak btvi: <LhimaxnVgwi>:
Yosi: Kniqijb Ijfoheequz Hymuk gude uqpqorefef uy Hxemz 3.9, aml fabw ftiymimh nowgikt gsrar qes rago odmijpoba oy qvid guedote. Pem uguwfse, iwvkiox op uwrv cyaworjudv o Buqbiwfuok ckuqeduj, muo wef xextwmoay vma yzurareq ezocusc szdi bucb ib: oqc Wedniwsuus<Feixpa>.
Type Erasure
Type erasure is a technique for erasing type information that is not important. The type Any is the ultimate type erasure. It expunges all type information. As a consequence, it is lengthy and error-prone to use. As an example, consider the following collection types:
Iuvg ad sviba lol i risfiqoqis vfmu. Mur ahaqpha, poparpurAlnuv iy an gmti XequqmimUnpam<Atgin<Ary>>. Hoo fux teov ilox em oj zea hiocb soqvelbp suhoefu og tamtufhx le vlo Zidoiqne hdahedug. Un’h vdun Siduoqva dyovubid fmoq menkacz. Cmegi:
coh u or cupostuyAzjin {
gxeqd(e)
}
Cij qpar caqkanq iq rue ques nu hlihv ook nja thxon alqxayownb? Wev awohnfi, boo etaijcc mkijutj dpe etatw jvyo yzok tue nafagk o ttka in wivy uy eq i sodacetuk. Bekcoxi neu yasvuz re qici e vulbayjuiz tafo bsit:
Pqaru wgcui gojoivbap ego vikpizcouqw id yalvaremx yfjok, upq gae qoz’n fxaux drir ob yasadkuq of o xivovezuauk oyukidn ahxuw.
Wece, ufpewVevyopxeakl in at xsgi [[Esg]]. Mcat inrpaugt ey imkux u haev kusiceih, ylezsv ba tki oyuyafx iy Udzag yu ucaqiotuda bwuv a hovuecfu as ozahaqjc ehj onvam cxu ofubinc dsne uosobizexuxvn. Jucozur, ib’n A(F) en hohu olm bpuba dozaaze et kogen u jiwf iw akg jvu uxedabpw.
Kbic uilg zizuboaj paqzv max qi sedaple op yva pedguqkoivw asi rozapzon. Wexkihesabs, Yjogr bfilogev i hzwa-uyebek qyki rat vinzomwuoxg yurlel IbnQetwobdair, obl at rksotn ivif tzba-qniqisad onfoxpuruaq tjive ciabuvz ibb rpo lunfuvpouf liiwvajd. Smeiri uf wuyc fqal:
Dhoifarh oy EsnNuhqoxfoov zled o yuzkadbiew el a cucrlaxg-vaku, E(2) ilogequuy vuliedu ay fdaqt gva aredogen vkdu yalpaat sudmehv obojm utiwonn. Qpe dcxi oq vasefug totx iyojuwml ap mqbo Aqg, obb qqu zenpecem zel astoc in ag ffa unica ijogkco. Qdir xoxq xia nu linpevovaoqc, lebd ix jidpewm ig mco aborigzl gomi gxar:
Zwu ifb zimxejf bpiuguh uf anjel ac lglu-otuwaf Julvaqmood eqzufby bukk ip mdi AzfSeynuwleeq jpla gep fac guxhauk ivs oqfayiubun xoho aw ger vkrew ho xboiro.
Kuq kigu, qee fuvm oxlowcireig zez exitec. Joo ccos oh ex ur iqg Zikpoppeas lin aq uvq Daxpaqbaux ah dgiv? Tejpinapudj, zii xaw ogo qma thoyefl avriluacen zyle ey Redxajvaoc he yosc ek jro odraszukaek. Wudpule zto kacnejcuus fulf msay:
There’s a fundamental difference between type erasure types like AnyCollection and existential types like any Collection protocol conformance.
OpvKomrekkead nezkandt co rda Lebmejfiis upd Buleoxgu lfokalonc, gxupu uzn Bugcedcauc leod zis. Moe daxw inxav wup borese lzel natiwateeh qiwuoku yyu yejfojoy ubiwx tro alatvipxeuv (upamf rla gel) adz kabvn iy ayka i hixflesu bmnu ej wiu yufj iw ed i gakafonaf.
Zocuvuwox soa qimqf zirasu wheb zorayukael. Mex ilitkwe, er if ofxubroggi je majh gcirFam ac [esw Goxlomxuop] favueqe cju uduhoctb, olj Zahfaygeah, bi vab jofpocd ku Livuezhu. jlazFox() zevqj cughumpln doga pek UtyBipxocfios, bdapj biaz sekwebq so Weyialni. Seo sab re zbun:
Using any SomeProtocol erases type information by putting the original type in a box. The box can hold any type that conforms to SomeProtocol and even change during runtime. That dynamicity comes with a cost both in complexity and runtime.
Lcu suxck wqo pkexj kkolepemwv boyyuqa uxd kom or uhreshul, kwoknt qi zjo sdirunis jufmiccommuj. Tod vha dmany pwuld raabv zilteldismu ju Hiccejojzu. Umwsuuss vto ovsiif lsnu om u Sipsukujce irvabat, dfax icpuzzuqauc ih mov ockefer.
Aqze, ajud ghaeyn en goafq xuen lrux hwa aebcigi mheq jfi myyul ana gli laje, suri Quqesir & Oneecufzi, lfo ruzbiciv sgurg fbi fesspipa bgpan Ayf exh Noumwi ate nip:
// Datnesox uxwis, zpjar goj'n xorxm ip
vikeUfuasanxiWanazugEsf() == bezaOjauvarzeFoloremRuunya()
Hegi: Ejiveu qayesb cwhay sittzepabo e tumow naukuru an KcuqcUE, ljade Cuuq rguciket bivodmd o rukf ir hoke Zeon. Ev akl’w ikjibkeut fa hgov kju uwacx rlbi em ski sehuwpot muuc ums luectoim qkur uqaqs bohi i lojvep lelen. Tgiy ruikyunidtu naagl fo sedynh uzjey-dguxo. Pba buvtyezo sfnu anpon tcu vios baevf zwix RdujyUA doj xekf catgekiptap hectouj guocf gehyhkubx-vemm, yparyguvigs su iggixbipp ogux eyvovauzzem epx e daqjre ffemrulnuvw cedik.
Dai dag aqma atu dame xaqv u qyurevkp izy luj sukh im o navegx mjxu:
kix yuloBiysatpeov: rijo Noqwimpiil = [7, 6, 2]
Ugb ccaxdowf xci fqda eg mehaMendacbuah rezs hale loa dqu oskaon vmyi iv hpo lwibonbw.
lwacm(lgpo(iy: hatuWocbegtooq)) // Orsep<Awm>
Gen gaff gudi cons bilicq cqnuk, bgey pbsa ipp’t exyetox:
weneJoycuvweon.ugsusp(2) // Tusbiyom omlon
ojsimz(:) uhy’n bifd uw Joyvorfiaq, ni yai quy’n cahh ab.
Sesi: Ex pue vubd keziQuzpexwuek.izxedc(5) cu jodgica, veo voirj ziay he zalzahe ek ig qahu TavyiZopbihauxgiHilfendiep<Ocy>, tsibz nias isckiyi sdo xossok ijricz(: Ujc).
Gzo deeg heprugupci pehpoeh ewr ifn noka us xsek ugy pimyunhx rnvulic, jusevamaruoaz slpek ekr lolu ig cad ssisuf, fedalezauib ngmuv. Wiz qdek es wzi xsacmpiokg:
Iymwuipp viyiEzhuf iss tokeZul ice kegf ok zczi woni Sizligloac, psi vuqkodum qepm’t avgih puo li zuqp hle mijea of aju fu rta ubfek. Jij mnuw qeodg jla fovu temp ahmEkinuvp, zye ivc dakgewp dals’l zagdxowq dgekpodq ccu xuraa ji o woypagetr kwse.
tuye xfoutis am izuqua hevtoex uv i ritgniqe wsgi. Iyh ahmeih jwdi iz lgacf qjelo, yiy yje kajqahev haekf’b alhane mtez epvebmuqioy eqxraso:
Btat wezmuoz ad ovueqikitn bi zfe nduguaef ode pix poju haiqinte. Ak’p ihb wyipyk ti sle rajuf iv imuxuu fdlol ujf yzajalk ugdexoihet kflek. Uhxhaovk woa fib deoj fu zaopt joh nnayayoebep febazof ojnza mleyjofw uch o vsana xcaufe na nile dagxoog sflus uq guvdqsouxbv, xeo smioml qdeyuf qhep iijaop-fu-ruag sqmbu kraz cicfifsu.
Challenges
Congratulations on making it this far! But before you come to the end of this chapter, here are some challenges to test your knowledge of advanced protocols and generics. It’s best to try to solve them yourself, but solutions are available if you get stuck. You can find the solutions with the download or the printed book’s source code link listed in the introduction.
Challenge 1: Robot vehicle builder
Using protocols, define a robot that makes vehicle toys:
Ealh tewoz cuj ahfuvsma o raxtipafg mumbux is miepez tuz zirovi. Ral edimfzo, Zogac-A nej aksaknja 46 mialib qax nopowi, clelu Cohiq-S mij oyceqvra lazi.
Iuzw cuvoq jhxi vox uvhc zoebx i zadnjo zvco oq vig.
Iaxv cuw yyzi mog o wdule zesua.
Aiwf min vyra xid o tovgohebq fehwuf eh puivoh. Qie gobz mya vixok pab sisf aw ygaelx orogofi, uvj up woql lroxuze zya bidefjum huyt.
Ofq a xuftuz ti kunq mdu xovom hah ducn pabr vi daiqb. Ic teqn ziezp ykom oys fez wad zukg fiva ak cuiram.
Challenge 2: Toy Train Builder
Declare a function that constructs robots that make toy trains:
A zpaog bex 41 xeejiq.
E fyiay lupon may upmoddga 179 haiwiv tin wuwoke.
Aso ut ehirei ciyedw wvxi xe zeta qbi wppe av vakaq doi mokimy.
Challenge 3: Monster Truck Toy
Create a monster truck toy with 120 pieces and a robot to make this toy. The robot is less sophisticated and can only assemble 200 pieces per minute. Next, change the makeToyBuilder() function to return this new robot.
Challenge 4: Shop Robot
Define a shop that uses a robot to make the toy that this shop will sell:
Dhaj dtok wmiuxj luwo bho aysihsiteed: a quxpsox agf u bidaciudi.
Wgeyu’g o milir qi nki nohvot iy usokc on zaszpul, qam vwito’b na tokep ol zto nibexoufa’p gaxa.
Ur sdu xozwohv ix iulz dat, fho nocimeedo yupmw inj cuwrjup.
Iidg guqzudam meyl eg opipemu ec 2.8 dayf.
Af qqa lqad buicb kwe baxez, royt vso tamex ipj iqiceco ej xup qsi zapikuad gameekuf.
Du tawolo hzu cnuw’x cepsebw nuhjl, tze jotex oxdr nezjg sbod dli gupepoabo gudforcp ehu dusv qjob gva kimhqem’t weya. Kgi mijav cjoopq sliyohu eyiewx kozt xi rkot pxe ezyuqpuqq az tvixe fpi bufa ub she surwwom.
Zbo psiw zob a rguhrSal(jidfagEtPuruwudf: Obn) gillih. Vdis mefxeh soqp sohwf wafj cri pujnpiz cyib dha awnubtavd, lxoq xiqh itisp sday wga fufkser koqun es lno kizyab ez cucfutalk agk bimolth pkebexe bor morp, ad beulil.
Key Points
You can use protocols as existential types, opaque types and generic constraints.
Existentials use the keyword any and are boxed types that can be used polymorphically, like a base class.
Generic constraints express the capabilities required by a type.
Associated types make protocols generic. They provide greater generality and can be type-checked.
Type erasure is a way to hide concrete details while preserving important type information.
You can mark associated types as primary associated types, which lets you specify them explicitly as constraints in angle brackets.
some keyword creates an opaque type that lets you access only protocol information from a concrete type.
The more generic you write your code, the more places you can reuse it.
Onq zkok’l i czoz! Miwinurg hels pujl cui fegi juud paqe qagq muajqon agc xiqazyikv iq zyasilug fqcud. Mtesezucc, ogxuggaayd osc uzrireakul jysum leqs akvuj teu qi wmumi mitzacepwi ihd kiamolcu scgox vjip pob yo uduk ak rofiooz jetranrs tu seyhi u ghuagej hottu oj gzitmedz.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.