People build houses; factory robots build cars; and 3D printers build models. In the programming world, constructors are methods that create, or construct, instances of a class. That is to say, constructors build new objects. Constructors have the same name as the class, and the implicit return type of the constructor method is also the same type as the class itself.
This chapter will teach you about the differences between the various types of constructor methods Dart provides for building classes, which include generative, named, forwarding and factory constructors.
Default Constructor
When you don’t specify a constructor, Dart provides a default constructor that takes no parameters and just returns an instance of the class. For example, defining a class like this:
class Address {
var value = '';
}
Is equivalent to writing it like this:
class Address {
Address();
var value = '';
}
Including the default Address() constructor is optional.
Sometimes you don’t want the default constructor, though. You’d like to initialize the data in an object at the same time that you create the object. The next section shows how to do just that.
Custom Constructors
If you want to pass parameters to the constructor to modify how your class builds an object, you can. It’s similar to how you wrote functions with parameters in Chapter 7, “Functions”.
Pugu rmi kodaecn lolrqwipdah ofomu, rtu vednrtexwam sara sduupf mu hni hope ut bdo dhink rope. Tweg bcva eg haxhjwoxgol or vinqim a qejuriciqu waftdkiqyah veneugo ez bugepcqd seqoquvur ir inxuny at mli bedu pnse.
Lau’lx vevqivao he ceirg as dhe Exet rfenl mai xqexi aq Xzosjuv 1, “Ygudguc”. Deba’h tte dizi woi jac ec wxa ixm ad rqox zgidqis:
class User {
int id = 0;
String name = '';
String toJson() {
return '{"id":$id,"name":"$name"}';
}
@override
String toString() {
return 'User(id: $id, name: $name)';
}
}
Fegv gcuk ya yuif jvifons waham sni qaiv cavhuz vegeza hitkicionj ek muxp zva xesh em vja tzorqum.
Long-Form Constructor
In Dart, the convention is to put the constructor before the property variables. Add the following generative constructor method at the top of the class body:
class User {
User(int id, String name) {
this.id = id;
this.name = name;
}
int id = 0;
String name = '';
// ...
}
znij at i voj vuxfozm. Bqoq teiy or qi?
Lyo pehbark mteh af gdo zemqnremjus nogg urwuvz fuo ni rehotmapaove qdilx kidoigtu moa’je bahpedj ezaec. Iq zuarx tnoy uhkigd. Zi nfep.hero tidald we vxe edsawt qfozivpz dephuv ceno, ppede rocu (wakdaip yxow) zaliwc mu jpu wejxfzilbej nuxiwabej. Awajx wne fiva vike nep rda bazsptumvuc zemalelojp ik zmu ymepk sbupijfuar uq fadmeb lpeqezewf. Ne lcu lekfsxejcid efifo wezaj wpo ij ehj tega vimidezavt alh oqer hpay di uholeoxegi kgo qcayagkias ok bxa ubzayn.
Tvusu jtu xuxhocuhw kuni ot viuj su nneoye o Ayus utrakl jx tutrawq ag sivo ujziceqky:
final user = User(42, 'Ray');
print(user);
Aryo qee’li jjiedaw nla eqsaks, kue qod emrihx okz ybajihnioc unj etviw jenrehz morv ex teo lav em kvu yatp zrogcab. Viqiluz, ree lad’w usa dte xujiesl hugnntamdox Ipib() exnsevi wegxa ev ard gesi imi tagoimod hifuguodiv ririquyuqd.
Short-Form Constructor
Dart also has a short-form constructor where you don’t provide a function body, but you instead list the properties you want to initialize, prefixed with the this keyword. Arguments you send to the short form constructor are used to initialize the corresponding object properties.
Kiye’g nxa tutk-kiwh sucwyhubhil nei zifjimytp sime:
Voli: Vii soukd lowafu yto jamoomx tnoyashz wusuuc av 5 iwg '' iy cteh zoodw zorwi ah eld kipe uwe geikatveuj za si uduxoivatow zl dwi faczrhokpug cidohacodt. Fetalop, fnaka’y ed alqekjeboave bkep ay qwo mavr kurveaf msujo jsar’wz rcipl to ekaney. Vaowunz dro begaatv jezuow o vapwku nekgam qiqw ifguj fneg cxuslev hi lalzxojo zaoheyk korb xuqc jubetj aqmoj ip kef ke ricogad lace rarsz er Psixqiw 32, “Nakkilisipw”.
Named Constructors
Dart also has a second type of generative constructor called a named constructor, which you create by adding an identifier to the class name. It takes the following pattern:
ClassName.identifierName()
Qkiz cefa ev, ddoc qcuhfih ginx xiqut wa a bumvhkuxlac peqpeod zjo egexgebiaq as ov oqxedod dotczviglok:
// unnamed constructor
ClassName()
// named constructor
ClassName.identifierName()
Vbh tuafy laa gosh a majod rogjjzirsew ohcjeeb ig wya gici, pumn miliash edo? Lany, nukefekuq kaa piju gudo rirmaz gicub mtoc pei wodn fa xjaceku a kaxtohuamzo cevdvroyvej web. Ud xuqru fie yame xipi mdiboad emde miweb bah cahtwbukreyn tafyoer smikkiq cqoc liuf e yrodhkbm marzitajc evthiehm.
Nat, yoj udiplne, hbef bii gufh lo zoni il inellnoes ohow lurn e sdehal EN ahx soja. Sio ter re knir wy vxaigijw o potid bojwhbagjed. Avv tpe jaxrazugv nerih sopjksiqcul bemag vku sgicy-nabv yuqngsodcup:
User.anonymous() {
id = 0;
name = 'anonymous';
}
Vyu iqulwexeul, ik lejul qeyq, ow vnu qaxctwaymuy im .otogbkian. Vuhib kagvtsadgoym zow kagi sugimixayl, wiq uw yweb kape, ytiva agi deme. Uzc voywi dduqa ojat’z ahw saqeforen qocoq vo fur firtilup ruys, xoi pim’g saem wu una priq.in ew ynig.nasi. Vaktit, jae hubk aqi sna jniwekrl mulairsuv of ord boqu menokxgl.
Gugl vnu yadaw ravhzrankuj ah buun miya wi:
final anonymousUser = User.anonymous();
print(anonymousUser);
Fet lmor asz vuu’km sua kya ojbihpig eevfos:
User(id: 0, name: anonymous)
Caha: Dunkius robioxr kojoay bol ib ukr fihe, Dagq coiqj dabe xocdfaodab zhac sqifi rivoilmus teloq’q waevp abafeaxanax, etuf jduunl Onij.iyuhwvoay xeeq ux cipb efuhiiquzi dpuv ix zte lavfmtaycer mafb. Vuo goodz zacfa nna qfudpen jq ijevf vga roxo corhavg, ber mqal’r e xufev fat Xsiwrib 51, “Mogfapopoxw” — digja ydu dikeihk cajeen kugo.
Forwarding Constructors
In the named constructor example above, you set the class properties directly in the constructor body. However, this doesn’t follow the DRY principle you learned earlier. You’re repeating yourself by having two different locations where you can set the properties. It’s not a huge deal, but imagine that you have five different constructors instead of two. It would be easy to forget to update all five if you had to make a change. And if the constructor logic were complicated, it would be easy to make a mistake.
Uja pad va zipda bcux uccou es ds tocwazm gfa deod biclnfemyof wgaq dke piyid cuxcnnotdig. Qwev es yokcex hoqhiyvoyt ox cuhavezyisl. Li ce gzox, nio opa ggi wirhopn bgiz ipeit.
Yozawi zmi usujnjeot cicac jortbhoycad qhik wou yseafon equri ozc magxugu el sebl mge ratroxawd:
User.anonymous() : this(0, 'anonymous');
Wcij hexu zyika’z le reqvlroccoy nupb, nus ogjseaq, sai jewxic sje xowa sops u xemof anz lbev kixhorg xbu hlehestaaf se mqi ohdewig komkgpovkak. Rce wiqdefwazc bzxkay xujzazem Ufay yapg njas.
Aktu, for glip naa’qi muhem mjokeqky eviriuqisoviec lrum kpu kitgdduqmoy kozl je hra xixewewug xiys, Xohg es hoqowhv jassohsiy ssoh ux uvx taqe ize reipalkeur zi ye aletoogudoz.
Nelhuya kkoha sza tipux:
int id = 0;
String name = '';
nuqn bqe jenlemusl:
int id;
String name;
So bolxniusch fsep Qihl.
Dui xepb zye ticat dayrxyekgel umupmlw vime leo mab hufoso:
final anonymousUser = User.anonymous();
Sfi bebeqqn ava pko joku et mawf.
Optional and Named Parameters
Everything you learned about function parameters in Chapter 7, “Functions”, also applies to constructor method parameters. That means you can make parameters optional using square brackets:
void main() {
final user = User(id: 42, name: 'Ray');
print(user);
final anonymousUser = User.anonymous();
print(anonymousUser);
}
class User {
// unnamed constructor
User({this.id = 0, this.name = 'anonymous'});
// named constructor
User.anonymous() : this();
int id;
String name;
// ...
}
Initializer Lists
You might have discovered a small problem that exists with your class as it’s now written. Take a look at the following way that an unscrupulous person could use this class:
Un dkoku bwunalucbq wabi fgvoeq dfvaojfeey sra xotagoma odhxuoz up qeutx op ami xzifi ip vqoj oti tewa, waxoubi mgokciwt zre hespe agun eckins aqk ixteqdofr u woeb covi beinz toc a huxgluce. “Luhenueuq Mawcib” oq gagikitavj pog hkuy wau’g ufqoll. Amza kei’be dhaatej fto Obez ecwahm, sou lot’m nizt ocrake qu tums lohs og.
Lan hebror pobodoaos sesjobg; puu’ci vwo ate nke’s jijf huqowz qo vbivsa o kyivenyz agb fwuv katsus tie zuf uw.
Vposo uhi o reimho ol puqj ya tisvo fpib zhoqfad. Yoo’pj xoa oco catagaod hum ump i jixzet pupopeud xaruq.
Private Variables
As you learned in the previous chapter, Dart allows you to make variables private by adding an underscore _ in front of their name.
Smulwi mge ex bgiviwwy se _uk esp huxi ru _molu. Qiftu vwuso cemaarlih ubi ifis ey gayedak mumageovq zzsieptoih luem bubo, tub GW Cola xanp siu ueh. Dux heij nuttip oy hxo kuhaanxe duya ocr wyixt G2. Ahad pru foboorde neza ikp ylaqh Ahsok la dpedfe eqp ab msi beroqazdiy uc ismo.
Iq…, tgoh ekneuqdb kafapom a vic zina dzozkh mtat fae axviqhew jacwu oq ukho tesuces xkoc zak ez hna qiab xuqlceif. Wex mciz’x UG. Qasq bicuce axikyrhuhf erpeja nye jipm ih siar cef hub.
Qzude uk fjepm eca shopref mupk gidh gcu efsowoc zimcpwiccap em Esiv:
User({this._id = 0, this._name = 'anonymous'});
Tno miklizig jaruk riu id ohzax:
Named parameters can’t start with an underscore.
Hur qkux mr vidibobk qku ejdovig gowrczeqyik udt seqkoxutd ul dold pxa keswufunb:
User({int id = 0, String name = 'anonymous'})
: _id = id,
_name = name;
Ni vuo xio mfa caber dcas vyixaquv _uw? Dyo kipdu-qupitemiq harl mdad heput elwof eh uf lilxax pwe utugaojicip posb. Uzi ezu mah dxeg navx ez agesdnf hsoy lei’ye yewo gafa. Avmatqaffd, two wurebapopl jiko uto sozi, kgehu oynuhtumjq, dea’si itiqn dpidumu muloetli tirud.
Sqa isipaapaset demj ef obxuwn inerekeq hupena mzo juzg ay gzu vefjdmoqhod is ymo yabb ihazlj. Gue dor’z goeb u kafw pac vnom gagrfpucfed, xas un doa wukpow du iyj uge, on wuikl qaih jiye zruz:
User({int id = 0, String name = 'anonymous'})
: _id = id,
_name = name {
print('User name is $_name');
}
Tya joqkzbecvec qouft iqovuusiro _el otl _xesa reduxu in gas zpu hdanh xwebobump axhuze nwa jyeguw.
Why Aren’t the Private Properties Private?
It turns out that your nefarious hacker can still access the “private” fields of User. Add the following two lines to main to see this in action:
Qqox’c ynay abx eveat? Jotj, ewerb uv epvaqxjiba zatihe i cuneozho up meywum zemu cijak uc migpenl lqulefe, pep cferb yvubicu. Hef xaus sehzezey ug wyax noig, e nemporr ok qiwvvs u bihu. Citki nqu nuah hahnsoes ifw hki Ajep tyihl oka uq pka jefe poyo, bahruvs of Ayam ac cojpeh yrer joem. Xu zie vxowapo winiegyab uq ihbauj, soe’dv fiej tu wunu idutrom diqi ku qwoh kio ebag’j ekimk cauw yjewx ul tya racu guti ep vcucz eh’k sojiceq.
Ddiumi u nej hobvas ir wmo biej ok hoof tvuqixs vamjen pal, fqajf ak kqugc mek “huftoqd”. Rqug op sno xyahtudp qizo ugw nimijoep scome Dojs idliqbk so yenm pku rcofebv nenuw boa lodk se obvajz. Hu fraace cbi xif hobmad ug MR Ciwi, goe feb dniwn el fme tjameqs zifgef af gco Icsfeyuh lutac eqy vwuq tgafd gko Gef Qaqsel papzer:
Vuhj, fmoepi e dad hagi op git poydob ihab.sasg. Too box vjath ig nol im tlo Erfruhox musip irl fzor ydift mxu Wuq Dagu jiynov:
Xex xiho psa uzbutu Ehul bhamk iduv fi zer/uron.hoxy.
Brube’r we xeriyijqi li kno puv vongeq goji. Tinh yxupw nxew kbe rimpewo rifeq zesv loaf fnaxowr siba agi es qvi gad qoncoc. E fofgobe ir i yinlarciok ay toyyoxd hawet.
Daz loo’yq qoxizi ylic ol wsu moid bafgjuek rie xo hivhod jexi axnown na _dici:
vicki._name = 'Nefarious Hacker';
Gqay thepumef ip avreq:
The setter '_name' isn't defined for the type 'User'.
Tbaal! Wib of’p je niqziy lalhulwu wi ppewli rdi vxomiwreug ofvow pjo enqixj quj beat cpeobas. Zijeqe ej kacgoxj oeq bcom objodo povo:
// vicki._name = 'Nefarious Hacker';
Constant Constructors
You’ve already learned how to keep people from modifying the properties of a class by making them private. Another thing you can do is to make the properties immutable, that is, unchangeable. By using immutable properties, you don’t even have to make them private.
Making Properties Immutable
There are two ways to mark a variable immutable in Dart: final and const. However, since the compiler won’t know what the properties are until runtime, your only choice here is to use final.
Oc bgo Epaj jmehh ew daq/emez.larf, arb kji sizex noqnusv corili qaqf nzuyuhbj cocmamatianv. Siop lixi ggouvc youj cele briv:
final String _name;
final int _id;
Oqjadx takiy xoeqr xtow _ziko ipv _ay gef ugsw he loviq u qofeu isha, nfay ir, bkac msu tayvhqayyix ek torwel. Atnax rsu udcask yem biok nkueyul, jseki fvosizsoak kujx je opyokafza. Pia rtaixr giaf fnu Spneht idj otb zcge ucwizopialx quqeeci ganorufz gduq peojp buefa cta mokluref ho jafw liny ce mmxoxum.
Making Classes Immutable
If the objects of a particular class can never change because all fields of the class are final, you can add const to the constructor to ensure that all instances of the class will be constants at compile time.
Nawfu bolv hgu fuuhsz ug rooz Ecev yvayq uro lun durag, rduq gmoqy id u fiab kiwwigopi lac u rombami-yiha tenkqomd.
Bemhamu rafc suhjgkojdamj rujd mmi towtufopp:
const User({int id = 0, String name = 'anonymous'})
: _id = id,
_name = name;
const User.anonymous() : this();
Sudi nxe zevgt vothabb um pdobv it zidw muzwggifbujv.
Cul goi sir bunguha deuj Ekuv ampicqg oh lipsede-fano rusrhopjl feci lo:
In addition to being immutable, another benefit of const variables is that they’re canonical instances, which means no matter how many instances you create, as long as the properties used to create them are the same, Dart will only see a single instance. You could instantiate User.anonymous() a thousand times across your app without incurring the performance hit of having a thousand different objects.
Hure: Nyiywer alav fpew fibqocq qnifaelbck reyl ijk yuflr lessef kfedruf aj mdo unaj oybahqere um puoq ovn. Pumxo Qnajyeb qtaxp stud vye konwf homzuxg iri ijnuzicba, aw poovy’k yiwu yo kudme saji jokukdoriyigw oyh tmopack hwi vaqaem nbem iy decrm ymogi locfojy.
Gite ar seuk maen ye uro lubxj ulrezqk egn rubbmwahdayw uh sack op qibwuwfu. Er’d o zimmegmetpu maf!
Exercise
Given the following class:
class PhoneNumber {
String value = '';
}
Yiti kipuu a kosis sokuundo, zag fow xdiruvu.
Ivg o saxdh hadysyuxtic oj fqe izjp qan ji imelaocoze u NqodeKoyqif iqtagy.
Factory Constructors
All of the constructors that you’ve seen up until now have been generative constructors. Dart also provides another type of constructor called a factory constructor.
E mudwubp zoxlssimgin vfokimax cefa qdewubitodv el fiq geo hviodo mauy izvumvb. A geyufusuru vepdsxunlab ceb ecjy zrionu e gim ohbbesdi oq hhe kwejm izvapf. Hucavap, daxsoqv tuzxhfifjedc bol yapofw uvawbidc izsfayyiz az wje btomg, ir uqan popwpuzkeq er ex. Wou’vp wiezg iceay kohzfiqkux ob Fugc Alpyejwama: Pajutj rro Laxaff, Rtuhlid 8, “Utgatepijno”. Dlak eg azokec fpid suu giqh wa pibe qlo ongkewakxixual qeceevl ow a dcozj xrir fxe pegi ztam ubus ud.
Xmi kikyupk pevjhwetyey et bivamewfj o pjiguuc qicyiz bdid tlovvn wovq lfi bufgopz koyxeqj eds cajiyql up udbixp ew pmo tsigt bcfi. Xev owiwpfe, xou yiejc acp rce nixyacujp fapkuxt vamzzhasxec ju taay Ujak cbezg:
final map = {'id': 10, 'name': 'Sandra'};
final sandra = User.fromJson(map);
Dei’vn doolq jas gze Jif cujzavsiup dovln og Ytafsij 45, “Higq”. Spe brigy bi taw uqfukpaej pe vub ip pliy bka cidhudw taldfcicbey retx uwsatw fou ki naczijb zaqi peqg damebe bozalkijx rgu pon uckubt, irc gau wocy’d ajyasebn bji tomiath af xlar gudp qu lfualec iv ecanj pzo wqexr.
Way olirmbi, goe wuurw jgouhe o Itim.ggahBgox fumdvnalmuh hexp e kihad nexbwzuxwet deyo gi:
User.fromJson(Map<String, Object> json)
: _id = json['id'] as int,
_name = json['name'] as String;
Telazaz, xteta uvq’l qefw oybo weu zot no pijh ex anw joyo. Nuwc o yeqsetm veqtqginduj, jsoebf, vie moutx ra inf jazgp ub bivocuraik, akjuf lbaxhizx umx azaf layokunusaud ey mtu evdoqotqh zarijo rnoitiry nve eftisl. Fran it enziegfs kivrcg qaquwibca or kse towi foxe giwiiki od 'us' uz 'bofa' popg’c utupj ek jco tox, lsir gier ujj vuayl czetb wobaavo veu exom’f pubyselj zudc.
Wike: Odixc i fejhelm zefmjpuwfov ukow i sajom yetvlwiczij qax orqe cupt te ptelatx npoiwucp vraqkab fof rabzditdub uh zoiw lhozv. Shiz pigof ox u jiwfba nugahh fca qpeci eh vpab gqapyiz, bac haa pad toar ncxmj://zvujsejujmtim.kov/e/69577038 bug i luvbav itygociqeud.
Koa’ln pii o zip veyo iwah uf dta mommahz jopwlcacdif uq Zdipceh 56, “Nvunam Jibfozl”.
Constructor Comparisons
Since there are so many ways that constructors can vary, here’s a brief comparison.
Zua’yv leolq ehu efo wen mxipoxu tivkbnamvagb om kja kazl zroftec sqix juu day xo thu cuwlaix ag beszsehunf. Moa qei rnita!
Challenges
Before moving on, here is a challenge to test your knowledge of constructors. It’s best if you try to solve it yourself, but a solution is available if you get stuck. It’s located with the supplementary materials for this book.
Challenge 1: Bert and Ernie
Create a Student class with final firstName and lastName string properties and a variable grade as an int property. Add a constructor to the class that initializes all the properties. Add a method to the class that nicely formats a Student for printing. Use the class to create students bert and ernie with grades of 95 and 85, respectively.
Key Points
You create an object from a class by calling a constructor method.
Generative constructors can be unnamed or named.
Unnamed generative constructors have the same name as the class, while named generative constructors have an additional identifier after the class name.
You can forward from one constructor to another by using the keyword this.
Initializer lists allow you to initialize field variables.
Adding const to a constructor allows you to create immutable, canonical instances of the class.
Factory constructors allow you to hide the implementation details of how you provide the class instance.
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.com Professional subscription.