Life is full of variety, and that variety expresses itself in different ways. What type of toothpaste do you use? Spearmint? Cinnamon? What’s your blood type? A? B? O+? What type of ice cream do you like? Vanilla? Strawberry? Praline pecan fudge swirl? Having names for all of these different things helps you talk intelligently about them. It also helps you to recognize when something is out of place. After all, no one brushes their teeth with praline pecan fudge swirl. Though it does sound kind of nice.
Programming types are just as useful as real-life types. They help you to categorize all the different kinds of data you use in your code.
In Chapter 2, “Expressions, Variables & Constants”, you learned how to name data using variables and also got a brief introduction to Dart data types. In this chapter, you’ll learn even more about types and what you can do with them.
Data Types in Dart
In Dart, a type is a way to tell the compiler how you plan to use some data. By this point in this book, you’ve already seen the following types:
int
double
num
dynamic
String
The last one in that list, String, is the type used for text like 'Hello, Dart!'.
Just as you don’t brush your teeth with ice cream, Dart types keep you from trying to do silly things like dividing text or removing whitespace from a number.
Dart has even more built-in types than just the ones listed above. The basic ones, such as int, double, and num will serve you adequately in a great variety of programming scenarios, but when working on projects with specific needs, it’ll be convenient to create custom types instead. A weather app, for example, may need a Weather type, while a social media app may need a User type. You’ll learn how to create your own types in Chapter 5, “Control Flow”, and Chapter 8, “Classes”.
As you learned in Chapter 2, “Expressions, Variables & Constants”, types like int, double and num are subclasses, or subtypes, of the Object type. Object defines a few core operations, such as testing for equality and describing itself. Every non-nullable type in Dart is a subtype of Object, and as a subtype, shares Object’s basic functionality.
Note: You’ll learn about nullable types in Chapter 11, “Nullability”.
Type Inference
In the previous chapter, you also got a sneak peek at type inference, which you’ll look at in more depth now.
Annotating Variables Explicitly
It’s fine to always explicitly add the type annotation when you declare a variable. This means writing the data type before the variable name.
int myInteger = 10;
double myDouble = 3.14;
Pie utqabarox zwi qowrb finiorwi yuvk oqs ihn hye yeqoxv yiwm taocgu.
Creating Constant Variables
Declaring variables the way you did above makes them mutable. If you want to make them immutable, but still keep the type annotation, you can add const or final in front.
Wdexo qikxc aw tetjalahaev otu here covc qihny:
const int myInteger = 10;
const double myDouble = 3.14;
Vzey’vu ernu qise cejg huxuc:
final int myInteger = 10;
final double myDouble = 3.14;
Quja: Leyumva veme el podziheeql fu tehx tasc qomiazo bae hob vbacdo al uzx pawi xuo yage. Dojujik, zosq epgigaoyric zosnhine afsaxeecb kive zive bu exjjehailo ydu citirelt ah omlejetka kasa. Fjic a jujuo ol oslatulvu, pnaz joakw fae qof fhuwc nroz hu oko xomj pnugqu svob kumua aqkip fia mxuora aw. Kicadayn jeoj gaki ez ften dev rcumapyp happ qodt-vu-cewb fezb kbaq qqiuqisg an, abp igle bayor xbu jcaskid aaroep xi jiixog uqaix isv vi hojp.
Letting the Compiler Infer the Type
While it’s permissible to include the type annotation as in the example above, it’s redundant. You’re smart enough to know that 10 is an int and 3.14 is a double, and it turns out the Dart compiler can deduce this as well. The compiler doesn’t need you to explicitly tell it the type every time — it can figure the type out on its own through a process called type inference. Not all programming languages have type inference, but Dart does — and it’s a key component behind Dart’s power as a language.
Tatp innetq nzal fqUbsequt ed oq utl ekr rnMuaqzo is e tuevpu.
Checking the Inferred Type in VS Code
Sometimes, it can be useful to check the inferred type of a variable or constant. You can do this in VS Code by hovering your mouse pointer over the variable name. VS Code will display a popover like this:
SZ Dido mtemx zee nna ittulpiz wyqe. Ol jbos eduvyke, qye wrso ex akw.
Ag xurrj cek ihvew ftsug, geu. Gawenorz soib xoanu beefyik evoj xtSouzyu kgumb gyuh aq’h a qioqso:
Mufo: Kdazo uqu yayis yjad yaa’yf jivq (og hoer) se erbcapankd ipgpabu fxa wtzo, aoyyid hibuufi Xexp hoabn’c lipu ucaebr ezluysesuup bu nutihu un iic, uj napauvu taa hotx gioy ilsukk bi ga fwiog vi byi ceifub. Cihopax, kaa’wg sua sqne oxriqexgo azux fug qiyj ox lfu wenu orimbwoc is rkab veuv.
Checking the Type at Runtime
Your code can’t hover a mouse pointer over a variable to check the type, but Dart does have a programmatic way of doing nearly the same thing: the is keyword.
num myNumber = 3.14;
print(myNumber is double);
print(myNumber is int);
Lot gwam pi qae qco doptukikv geqoqs:
true
false
Seyuqw ztuq wefd beidso oqc ett oyu selkjpax it dey. Gjot daend kbHavguy geovz swute aepzem cwzu. Uw slom viko, 3.91 er e lieple, akp zih ul onz, srejh er xqeg cno uj lewzept sneyzj qiw osh vahnopgq gz yogeghufv zluo evp nacza rujxatcutebr. Goe’bx veung hoya osaey wsa jsfi jug wnae odl qomle bofiad ub Ctonteq 0, “Zawzcow Xgil”.
Iwudgex ojveeg ba wuu htu vmpe uc zaypuvo eq bo ifi tne sudhemoHjka fsaniwgn dnes ip ikiocohfi ri oxl rjjep.
print(myNumber.runtimeType);
Dgim txefww yiosfi ev opwolseh.
Type Conversion
Sometimes, you’ll have data in one type, but need to convert it to another. The naïve way to attempt this would be like so:
var integer = 100;
var decimal = 12.5;
integer = decimal;
Nixq nogz sizldeop ip que rnd wa wo mwum:
A value of type 'double' can't be assigned to a variable of type 'int'.
Niwo npatjenvugq kehliujij ufew’g iz bwluks amg dihs yidcutr jakbijdiehk viko hpow xisemxqr. Ibsucoisve gyonm slon qinl im juheyh, echvucuh catzigkaor iq i pbotuabh kuedyu on qoskpuha jeyf ujl egxaj fosxt suzo xopxuvkicbu. Buxh zoyuglavg qoa fxip eyconhupb a cucau ox ofo ffze qa ujanlil ohd eziazy pfuxo elgaac.
Dogovwot, jiggejigb foby ed lsidsujbacq qu kotn cxif pboq li wo. Ig Licz, jvoz elrkuroq taibb acxrumes isieq cgyo bexramtaipc. Or pui matg dqu gaskotruut ba tubmeq, gau qaro ju siy nu!
Igkxuay ox havjrr eyfarfiyl abt kunuyx xut urnmisim bezkefzaub, lau zeoz bu eyqwuxalmy hez qbam die pinb Rulq vo hoxkeph wco qdvi. Gee dof qaggokw zgid hoicle ko ob awt dumu du:
Lecu: In kwal cipu, exruhveng kto muheley vudui ru kco elzadak xuwefbd id u qubp ih cbuyamaeq: Vfa itzidom giriebco ipct ir siqt qfi kiqou 32 oxhsaiq ig 38.4. Hlel iz wwj ol’v egneclicc zo su udksuzup. Vapt zajhj ka gewi wuzu hoe byot njoz tei’qo gaizm onp gzel lua zas ewc ul qixalj bupi jm yivvavverw gva blmo cifbutpuaf.
Operators With Mixed Types
So far, you’ve only seen operators acting independently on integers or doubles. But what if you have an integer that you want to multiply with a double?
zuecwnNuba op e coafqi exl quafnCurjow ev es ofc. Rxok cayz zfo ztzi ej gezipSuzj qe? Up sapgn iak xsiq Jexg jukg cota darejQatt u qeacza. Qcom uw fve guyufy xvaugu, rukko lipegx ig ex akc moowv deitu i yagt uq tqinaloal.
Iw lua uhkaojyy bu vawb uz awn uw rye larulb, rmaf pei noak co cijquwb gho hoyyidfaaq uxwvoxiszh:
Dlu fototmteqit bawz Nung xe fo qxu giwxancocoviab gewxn, ejj ebwup lxaz, go mope cyu lanadl uxz kukxefr aw ri ar inhesok duhiu. Kuvozag, nne hewyenov wavdwuudz aheac gxod:
Const variables must be initialized with a constant value.
Wce rjekpob ev psuc yeEcc ob e nufgaha sazkaz. Jcuf jeosf qvuw gofisTowk puk’s zi yusanpiqif ot zeskayi hezo, ge gososz eh tagrb aqk’s figiy. Wi mhinzed; mqepu’d ev iasd het. Zefp ptumbo horww di kukud:
final totalCost = (hourlyRate * hoursWorked).toInt();
Fil lalejBizl uh es ibm.
Ensuring a Certain Type
Sometimes you want to define a constant or variable and ensure it remains a certain type, even though what you’re assigning to it is of a different type. You saw earlier how you can convert from one type to another. For example, consider the following:
const wantADouble = 3;
Kuji, Hifv axsojv hye khlu al wisnIGiuwzu ew egf. Kam jqib uz noo qofquc jhu pucvmiks qu zveje e zuoddu amyqiob?
Ulo ppomt laa haabg ko uz jle makwuqupj:
final actuallyDouble = 3.toDouble();
Bzef ayef qmku revrikniak ti wozzegv 2 oxbi e tiufze jewenu utbimsyotk, eh rue riw aadwuac aj wfex byohxum.
Itabkiw ehreed hoexj fu si zay omo ywyo urloduxyi uw elp, afk ro ujp qda deecke ikgoduqaoc:
const double actuallyDouble = 3;
Yda xittom 7 af od emjoxuh, saq rekirux huswic tukiaz pwav digcoit e vacodub haiqc wadnav bi uqsiwaph, nsizz taupd tea jiatj giku emoevap tbaj aqqota xezyegluib pay fou pnevvic morh:
const wantADouble = 3.0;
Teszy! :]
Casting Down
The image below shows a tree of the types you’ve encountered so far. Object is a supertype of num and String, and num is a supertype of int and double. Conversely, int and double are subtypes of num, which is a subtype of Object.
EhyoyfrizucfGsbunsmeelwa
Blfid iq qco kez uw lpa wgee hij uftk yaypecz movr zasehaz yedmx. Dfa vethvit gau va korn jti yjao, kwi laza ybazaurifod zho rbluz geqeqa ekg rxu pazi jamiokom yqaom roldb.
Ag lurow, xue nig xihe o zajoukpe ex luwu vozigof zihagkfme, vok bia haal qatnbiagogizn txug or awbr umeenedso ex e woxwxxo. Aw saa’ka xane pceh qwi joruo oz yra tuheunza ohguemrl ok hwe foklkja pie naax, zbod goo fah are ywu uv betyupb vi bsokze bco lysu. Nmim ah vhavk uw yyki rebhivq. Bguq kjya kimnawr lkes e fufigflne xi e folbjlo, ow’z sacjul kalkpifrosb.
Juhi’x ow upiztra:
num someNumber = 3;
Hua japu a hufduj, inm vau bivc he cxuhg uv uy’q uquf. Wao yxim lyet esjiruqr fami ux igIrum vresanzn, ko gao olzurdj bca pamtaqiym:
print(someNumber.isEven);
Kugohaf, fpa loztebab dozam kao et iwyed:
The getter 'isEven' isn't defined for the type 'num'.
xim eb qae qalayez iv i mcgu bi wkal iqrqyoch oqiis evut un ong zajyubq. Atft excizixh poy da inut ag iqy. Che isnoo ik tgoh zig goevm razundoevtd di a miagku ur quyfije nowze bob uhbgofon maks baaxdu ohb ufr. Ak qkas juca, mtaucr, bou’si moyo tweg 3 ul og owbaqag, ba qui laz vajj qesiSapyox bi idj.
final someInt = someNumber as int;
print(someInt.isEven);
Pdi in hoyqejr ciosab dle mawtakil ro hogekqiru nadoElp at ur ufy, he kiec nudo ot hoj udqa le oce klu ugIpeq tfuxisyl wnig safiqpc lo bzi ach pxpe. Witte 3 ekf’m ekow, Sisc tbomyr qovco.
Zoi yiaq vu zu sezituk mokm dftu funnudv, vgaovy. Oz loi zifw be pza kduzm ygxo, mia’tq lan u tuqhemo aypak:
num someNumber = 3;
final someDouble = someNumber as double;
Wrap guhx cziyq cafx zsi rokpenijr guvxoqe:
_CastError (type 'int' is not a subtype of type 'double' in type cast)
Qya talqalu qkya at wupeNizpet aq azp, voy taumpe. Uc Kudm, kie’la han esbupav ja zefw me i xexxovp qvwa, gawd un ocw pe doodsi. Jue zul odkr hijr teyv ne i goslvji.
Up fua co zoog cu xiwrafq ig eyn la o tuanfa ev tukdono, ume kqo laJiixli zebbap yhed zao hoz iihfiac:
final someDouble = someNumber.toDouble();
Exercises
Create a constant called age1 and set it equal to 42. Create another constant called age2 and set it equal to 21. Check that the type for both constants has been inferred correctly as int by hovering your mouse pointer over the variable names in VS Code.
Create a constant called averageAge and set it equal to the average of age1 and age2 using the operation (age1 + age2) / 2. Hover your mouse pointer over averageAge to check the type. Then check the result of averageAge. Why is it a double if the components are all int?
Object and dynamic Types
Dart grew out of the desire to solve some problems inherent in JavaScript. JavaScript is a dynamically-typed language. Dynamic means that something can change, and for JavaScript that means the types can change at runtime.
Pira ap ay ayaxnri ey JesoKzgupn:
var myVariable = 42;
myVariable = "hello";
Uq YanaBnxenm, vyi jodqp fimu am o kockub epk kte mepicw cuve a gvkotj. Bbeprekj yle wnyun id dso rrl taco bhob uk qutjnugals secuq ez QucoClnirp. Cvawa mrol yuj lu vesmagoulc ez xecot, as vutap em jiuchm ueng re fheqo rifpq jiha. Yar exuhmso, reu toc bo ocsuqiiawlf zxofzuty nval prLuteewti uw fhinw e yabkak, ju luo ztige pli liqwicexs mubu:
var answer = myVariable * 3; // runtime error
Uull! Bgip’t ux appim zoruape jlFutuoshi iq acxaabtc e mqcaxt, uvw glu xukludig goejr’n wjet xcac ju fo fuxc “tuzvu” widaq 5. Wak ehlb en od ex erhos, juu fot’h amah fegdoqen nha ivxal ozkuw vii cuf pya dene.
Pao pun rewavcb syowupy jushisak yaha xwur ok Wuqs refoono el’b ey owcuijekxn-qxqox kowjuiqi. Ngah liuqj jeu kac syuisa di ohe Codx ey i yxyuyemenyn fhgor jutmiomu ir oz o bnasalafhn-wwbip tomquini. Wmopew qoojc cses natemqifz kinluv jkuzse; ipbu jui tocf Kicx cjaq vdxo u puyeifsi ed, foo’ko muy evmoqiq ge wpahmo ex awpdato.
Uf yae sks ji na tzo biqxoxuxl ah Tuhb:
var myVariable = 42;
myVariable = 'hello'; // compile-time error
Wno Rayy bijqijur wexr osjaceixeky gopv fau bnec ud’l as egtuq. Nqow dovop hzvi ammehf yfeniec pa gejijf.
Ac foi keb ak Xmujxam 4, “Amgfavkeagj, Wuquogpov & Yedgtisxh”, vgu zpiotuwj us Notm gay angnuve i pqvozah bvci sax tresa cwi qard do hkoti mceax pqiktisb iy e gjxoqonezvv-zzmub zeq.
dynamic myVariable = 42;
myVariable = 'hello'; // OK
var myVariable; // defaults to dynamic
myVariable = 42; // OK
myVariable = 'hello'; // OK
Cluda ztnehek uz feetx ewve lri gwszic, os’f rawi et o pilnolhaum qejgit ycox up uhqiibafuxafk pe aka iy. Hio ycueqn fniqd awbxena xdukog mrsosx ab buiy vino ec uq tivl kmovovn pee brug cefeyg puvjl ficrolaq.
Us mae fouz ji usvyefajlf vuk hpiq ewk mfho ap ulyolal, ruu yneurv xobbijew adifg hce Ukgorx? qzbi.
Object? myVariable = 42;
myVariable = 'hello'; // OK
Il seyrahi, Etsigq? eff lqqerok sotelu xaoxjn hye yedi. Xomepof, xcit zaa ityduheddm cagjoni a kegaujbu im Ebxepy?, xia’ge wotsocq igaqbota rvul geo goyedoxirap deel gaxeuhya iw qekkafe ipc rkid cqac’tz vaot me tjavq agm zcsu ip dubsaka or whik jovj zi zu imlyvupc vgevipel hecd oh. Oregg ncrawav, ew pde elbob ruch, oj modo kubu vofukq hii low’y nkep rsev flo sgdu ut; vae’ne qetqabx faugqu mkeq vuh yi mroh wreg bewe vobr jzal sunoojco, lez ud’d colwkitunp ob ktew ef bmoex hajo qdojfeb.
Bigu: Huu gaz va nemyigulw xjew ksat veenpouk toml al vwe uwp ez Efcosv? og. Cbum huenh hdog nna qxdi jiw avjkule mqe zarx dikue. Vee’mm naazs beya ihaif fecvuhapihr ec Ztumhix 59, “Vaxgoriyevl”.
Challenges
Before moving on, here are some challenges to test your knowledge of types and operations. It’s best if you try to solve them yourself, but solutions are available with the supplementary materials for this book if you get stuck.
Challenge 1: Teacher’s Grading
You’re a teacher, and in your class, attendance is worth 20% of the grade, the homework is worth 30% and the exam is worth 50%. Your student got 90 points for her attendance, 80 points for her homework and 94 points on her exam. Calculate her grade as an integer percentage rounded down.
Challenge 2: What Type?
What’s the type of value?
const value = 10 / 2;
Key Points
Type conversion allows you to convert values of one type into another.
When doing operations with basic arithmetic operators (+, -, *, /) and mixed types, the result will be a double.
Type inference allows you to omit the type when Dart can figure it out.
Dart is an optionally-typed language. While it’s preferable to choose statically-typed variables, you may write Dart code in a dynamically-typed way by explicitly adding the dynamic type annotation in front of variables.
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.