1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900 |
- ==========
- Nim Manual
- ==========
- :Authors: Andreas Rumpf, Zahary Karadjov
- :Version: |nimversion|
- .. default-role:: code
- .. include:: rstcommon.rst
- .. contents::
- "Complexity" seems to be a lot like "energy": you can transfer it from the
- end-user to one/some of the other players, but the total amount seems to remain
- pretty much constant for a given task. -- Ran
- About this document
- ===================
- **Note**: This document is a draft! Several of Nim's features may need more
- precise wording. This manual is constantly evolving into a proper specification.
- **Note**: The experimental features of Nim are
- covered `here <manual_experimental.html>`_.
- **Note**: Assignments, moves, and destruction are specified in
- the `destructors <destructors.html>`_ document.
- This document describes the lexis, the syntax, and the semantics of the Nim language.
- To learn how to compile Nim programs and generate documentation see
- `Compiler User Guide <nimc.html>`_ and `DocGen Tools Guide <docgen.html>`_.
- The language constructs are explained using an extended BNF, in which `(a)*`
- means 0 or more `a`'s, `a+` means 1 or more `a`'s, and `(a)?` means an
- optional *a*. Parentheses may be used to group elements.
- `&` is the lookahead operator; `&a` means that an `a` is expected but
- not consumed. It will be consumed in the following rule.
- The `|`, `/` symbols are used to mark alternatives and have the lowest
- precedence. `/` is the ordered choice that requires the parser to try the
- alternatives in the given order. `/` is often used to ensure the grammar
- is not ambiguous.
- Non-terminals start with a lowercase letter, abstract terminal symbols are in
- UPPERCASE. Verbatim terminal symbols (including keywords) are quoted
- with `'`. An example::
- ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
- The binary `^*` operator is used as a shorthand for 0 or more occurrences
- separated by its second argument; likewise `^+` means 1 or more
- occurrences: `a ^+ b` is short for `a (b a)*`
- and `a ^* b` is short for `(a (b a)*)?`. Example::
- arrayConstructor = '[' expr ^* ',' ']'
- Other parts of Nim, like scoping rules or runtime semantics, are
- described informally.
- Definitions
- ===========
- Nim code specifies a computation that acts on a memory consisting of
- components called `locations`:idx:. A variable is basically a name for a
- location. Each variable and location is of a certain `type`:idx:. The
- variable's type is called `static type`:idx:, the location's type is called
- `dynamic type`:idx:. If the static type is not the same as the dynamic type,
- it is a super-type or subtype of the dynamic type.
- An `identifier`:idx: is a symbol declared as a name for a variable, type,
- procedure, etc. The region of the program over which a declaration applies is
- called the `scope`:idx: of the declaration. Scopes can be nested. The meaning
- of an identifier is determined by the smallest enclosing scope in which the
- identifier is declared unless overloading resolution rules suggest otherwise.
- An expression specifies a computation that produces a value or location.
- Expressions that produce locations are called `l-values`:idx:. An l-value
- can denote either a location or the value the location contains, depending on
- the context.
- A Nim `program`:idx: consists of one or more text `source files`:idx: containing
- Nim code. It is processed by a Nim `compiler`:idx: into an `executable`:idx:.
- The nature of this executable depends on the compiler implementation; it may,
- for example, be a native binary or JavaScript source code.
- In a typical Nim program, most of the code is compiled into the executable.
- However, some of the code may be executed at
- `compile-time`:idx:. This can include constant expressions, macro definitions,
- and Nim procedures used by macro definitions. Most of the Nim language is
- supported at compile-time, but there are some restrictions -- see `Restrictions
- on Compile-Time Execution <#restrictions-on-compileminustime-execution>`_ for
- details. We use the term `runtime`:idx: to cover both compile-time execution
- and code execution in the executable.
- The compiler parses Nim source code into an internal data structure called the
- `abstract syntax tree`:idx: (`AST`:idx:). Then, before executing the code or
- compiling it into the executable, it transforms the AST through
- `semantic analysis`:idx:. This adds semantic information such as expression types,
- identifier meanings, and in some cases expression values. An error detected
- during semantic analysis is called a `static error`:idx:. Errors described in
- this manual are static errors when not otherwise specified.
- A `panic`:idx: is an error that the implementation detects
- and reports at runtime. The method for reporting such errors is via
- *raising exceptions* or *dying with a fatal error*. However, the implementation
- provides a means to disable these `runtime checks`:idx:. See the section
- pragmas_ for details.
- Whether a panic results in an exception or in a fatal error is
- implementation specific. Thus the following program is invalid; even though the
- code purports to catch the `IndexDefect` from an out-of-bounds array access, the
- compiler may instead choose to allow the program to die with a fatal error.
- .. code-block:: nim
- var a: array[0..1, char]
- let i = 5
- try:
- a[i] = 'N'
- except IndexDefect:
- echo "invalid index"
- The current implementation allows to switch between these different behaviors
- via ``--panics:on|off``. When panics are turned on, the program dies with a
- panic, if they are turned off the runtime errors are turned into
- exceptions. The benefit of ``--panics:on`` is that it produces smaller binary
- code and the compiler has more freedom to optimize the code.
- An `unchecked runtime error`:idx: is an error that is not guaranteed to be
- detected and can cause the subsequent behavior of the computation to
- be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx:
- language features are used and if no runtime checks are disabled.
- A `constant expression`:idx: is an expression whose value can be computed during
- a semantic analysis of the code in which it appears. It is never an l-value and
- never has side effects. Constant expressions are not limited to the capabilities
- of semantic analysis, such as constant folding; they can use all Nim language
- features that are supported for compile-time execution. Since constant
- expressions can be used as an input to semantic analysis (such as for defining
- array bounds), this flexibility requires the compiler to interleave semantic
- analysis and compile-time code execution.
- It is mostly accurate to picture semantic analysis proceeding top to bottom and
- left to right in the source code, with compile-time code execution interleaved
- when necessary to compute values that are required for subsequent semantic
- analysis. We will see much later in this document that macro invocation not only
- requires this interleaving, but also creates a situation where semantic analysis
- does not entirely proceed top to bottom and left to right.
- Lexical Analysis
- ================
- Encoding
- --------
- All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other
- encodings are not supported. Any of the standard platform line termination
- sequences can be used - the Unix form using ASCII LF (linefeed), the Windows
- form using the ASCII sequence CR LF (return followed by linefeed), or the old
- Macintosh form using the ASCII CR (return) character. All of these forms can be
- used equally, regardless of the platform.
- Indentation
- -----------
- Nim's standard grammar describes an `indentation sensitive`:idx: language.
- This means that all the control structures are recognized by indentation.
- Indentation consists only of spaces; tabulators are not allowed.
- The indentation handling is implemented as follows: The lexer annotates the
- following token with the preceding number of spaces; indentation is not
- a separate token. This trick allows parsing of Nim with only 1 token of
- lookahead.
- The parser uses a stack of indentation levels: the stack consists of integers
- counting the spaces. The indentation information is queried at strategic
- places in the parser but ignored otherwise: The pseudo-terminal `IND{>}`
- denotes an indentation that consists of more spaces than the entry at the top
- of the stack; `IND{=}` an indentation that has the same number of spaces. `DED`
- is another pseudo terminal that describes the *action* of popping a value
- from the stack, `IND{>}` then implies to push onto the stack.
- With this notation we can now easily define the core of the grammar: A block of
- statements (simplified example)::
- ifStmt = 'if' expr ':' stmt
- (IND{=} 'elif' expr ':' stmt)*
- (IND{=} 'else' ':' stmt)?
- simpleStmt = ifStmt / ...
- stmt = IND{>} stmt ^+ IND{=} DED # list of statements
- / simpleStmt # or a simple statement
- Comments
- --------
- Comments start anywhere outside a string or character literal with the
- hash character `#`.
- Comments consist of a concatenation of `comment pieces`:idx:. A comment piece
- starts with `#` and runs until the end of the line. The end of line characters
- belong to the piece. If the next line only consists of a comment piece with
- no other tokens between it and the preceding one, it does not start a new
- comment:
- .. code-block:: nim
- i = 0 # This is a single comment over multiple lines.
- # The scanner merges these two pieces.
- # The comment continues here.
- `Documentation comments`:idx: are comments that start with two `##`.
- Documentation comments are tokens; they are only allowed at certain places in
- the input file as they belong to the syntax tree.
- Multiline comments
- ------------------
- Starting with version 0.13.0 of the language Nim supports multiline comments.
- They look like:
- .. code-block:: nim
- #[Comment here.
- Multiple lines
- are not a problem.]#
- Multiline comments support nesting:
- .. code-block:: nim
- #[ #[ Multiline comment in already
- commented out code. ]#
- proc p[T](x: T) = discard
- ]#
- Multiline documentation comments also exist and support nesting too:
- .. code-block:: nim
- proc foo =
- ##[Long documentation comment
- here.
- ]##
- Identifiers & Keywords
- ----------------------
- Identifiers in Nim can be any string of letters, digits
- and underscores, with the following restrictions:
- * begins with a letter
- * does not end with an underscore `_`
- * two immediate following underscores `__` are not allowed::
- letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
- digit ::= '0'..'9'
- IDENTIFIER ::= letter ( ['_'] (letter | digit) )*
- Currently, any Unicode character with an ordinal value > 127 (non-ASCII) is
- classified as a `letter` and may thus be part of an identifier but later
- versions of the language may assign some Unicode characters to belong to the
- operator characters instead.
- The following keywords are reserved and cannot be used as identifiers:
- .. code-block:: nim
- :file: keywords.txt
- Some keywords are unused; they are reserved for future developments of the
- language.
- Identifier equality
- -------------------
- Two identifiers are considered equal if the following algorithm returns true:
- .. code-block:: nim
- proc sameIdentifier(a, b: string): bool =
- a[0] == b[0] and
- a.replace("_", "").toLowerAscii == b.replace("_", "").toLowerAscii
- That means only the first letters are compared in a case-sensitive manner. Other
- letters are compared case-insensitively within the ASCII range and underscores are ignored.
- This rather unorthodox way to do identifier comparisons is called
- `partial case-insensitivity`:idx: and has some advantages over the conventional
- case sensitivity:
- It allows programmers to mostly use their own preferred
- spelling style, be it humpStyle or snake_style, and libraries written
- by different programmers cannot use incompatible conventions.
- A Nim-aware editor or IDE can show the identifiers as preferred.
- Another advantage is that it frees the programmer from remembering
- the exact spelling of an identifier. The exception with respect to the first
- letter allows common code like `var foo: Foo` to be parsed unambiguously.
- Note that this rule also applies to keywords, meaning that `notin` is
- the same as `notIn` and `not_in` (all-lowercase version (`notin`, `isnot`)
- is the preferred way of writing keywords).
- Historically, Nim was a fully `style-insensitive`:idx: language. This meant that
- it was not case-sensitive and underscores were ignored and there was not even a
- distinction between `foo` and `Foo`.
- Keywords as identifiers
- -----------------------
- If a keyword is enclosed in backticks it loses its keyword property and becomes an ordinary identifier.
- Examples
- .. code-block:: nim
- var `var` = "Hello Stropping"
- .. code-block:: nim
- type Obj = object
- `type`: int
- let `object` = Obj(`type`: 9)
- assert `object` is Obj
- assert `object`.`type` == 9
- var `var` = 42
- let `let` = 8
- assert `var` + `let` == 50
- const `assert` = true
- assert `assert`
- String literals
- ---------------
- Terminal symbol in the grammar: `STR_LIT`.
- String literals can be delimited by matching double quotes, and can
- contain the following `escape sequences`:idx:\ :
- ================== ===================================================
- Escape sequence Meaning
- ================== ===================================================
- ``\p`` platform specific newline: CRLF on Windows,
- LF on Unix
- ``\r``, ``\c`` `carriage return`:idx:
- ``\n``, ``\l`` `line feed`:idx: (often called `newline`:idx:)
- ``\f`` `form feed`:idx:
- ``\t`` `tabulator`:idx:
- ``\v`` `vertical tabulator`:idx:
- ``\\`` `backslash`:idx:
- ``\"`` `quotation mark`:idx:
- ``\'`` `apostrophe`:idx:
- ``\\`` '0'..'9'+ `character with decimal value d`:idx:;
- all decimal digits directly
- following are used for the character
- ``\a`` `alert`:idx:
- ``\b`` `backspace`:idx:
- ``\e`` `escape`:idx: `[ESC]`:idx:
- ``\x`` HH `character with hex value HH`:idx:;
- exactly two hex digits are allowed
- ``\u`` HHHH `unicode codepoint with hex value HHHH`:idx:;
- exactly four hex digits are allowed
- ``\u`` {H+} `unicode codepoint`:idx:;
- all hex digits enclosed in `{}` are used for
- the codepoint
- ================== ===================================================
- Strings in Nim may contain any 8-bit value, even embedded zeros. However
- some operations may interpret the first binary zero as a terminator.
- Triple quoted string literals
- -----------------------------
- Terminal symbol in the grammar: `TRIPLESTR_LIT`.
- String literals can also be delimited by three double quotes `"""` ... `"""`.
- Literals in this form may run for several lines, may contain `"` and do not
- interpret any escape sequences.
- For convenience, when the opening `"""` is followed by a newline (there may
- be whitespace between the opening `"""` and the newline),
- the newline (and the preceding whitespace) is not included in the string. The
- ending of the string literal is defined by the pattern `"""[^"]`, so this:
- .. code-block:: nim
- """"long string within quotes""""
- Produces::
- "long string within quotes"
- Raw string literals
- -------------------
- Terminal symbol in the grammar: `RSTR_LIT`.
- There are also raw string literals that are preceded with the
- letter `r` (or `R`) and are delimited by matching double quotes (just
- like ordinary string literals) and do not interpret the escape sequences.
- This is especially convenient for regular expressions or Windows paths:
- .. code-block:: nim
- var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab
- To produce a single `"` within a raw string literal, it has to be doubled:
- .. code-block:: nim
- r"a""b"
- Produces::
- a"b
- `r""""` is not possible with this notation, because the three leading
- quotes introduce a triple quoted string literal. `r"""` is the same
- as `"""` since triple quoted string literals do not interpret escape
- sequences either.
- Generalized raw string literals
- -------------------------------
- Terminal symbols in the grammar: `GENERALIZED_STR_LIT`,
- `GENERALIZED_TRIPLESTR_LIT`.
- The construct `identifier"string literal"` (without whitespace between the
- identifier and the opening quotation mark) is a
- generalized raw string literal. It is a shortcut for the construct
- `identifier(r"string literal")`, so it denotes a routine call with a
- raw string literal as its only argument. Generalized raw string literals
- are especially convenient for embedding mini languages directly into Nim
- (for example regular expressions).
- The construct `identifier"""string literal"""` exists too. It is a shortcut
- for `identifier("""string literal""")`.
- Character literals
- ------------------
- Character literals are enclosed in single quotes `''` and can contain the
- same escape sequences as strings - with one exception: the platform
- dependent `newline`:idx: (``\p``)
- is not allowed as it may be wider than one character (it can be the pair
- CR/LF). Here are the valid `escape sequences`:idx: for character
- literals:
- ================== ===================================================
- Escape sequence Meaning
- ================== ===================================================
- ``\r``, ``\c`` `carriage return`:idx:
- ``\n``, ``\l`` `line feed`:idx:
- ``\f`` `form feed`:idx:
- ``\t`` `tabulator`:idx:
- ``\v`` `vertical tabulator`:idx:
- ``\\`` `backslash`:idx:
- ``\"`` `quotation mark`:idx:
- ``\'`` `apostrophe`:idx:
- ``\\`` '0'..'9'+ `character with decimal value d`:idx:;
- all decimal digits directly
- following are used for the character
- ``\a`` `alert`:idx:
- ``\b`` `backspace`:idx:
- ``\e`` `escape`:idx: `[ESC]`:idx:
- ``\x`` HH `character with hex value HH`:idx:;
- exactly two hex digits are allowed
- ================== ===================================================
- A character is not a Unicode character but a single byte.
- Rationale: It enables the efficient support of `array[char, int]` or
- `set[char]`.
- The `Rune` type can represent any Unicode character.
- `Rune` is declared in the `unicode module <unicode.html>`_.
- A character literal that does not end in `'` is interpreted as `'` if there
- is a preceeding backtick token. There must be no whitespace between the preceeding
- backtick token and the character literal. This special case ensures that a declaration
- like ``proc `'customLiteral`(s: string)`` is valid. ``proc `'customLiteral`(s: string)``
- is the same as ``proc `'\''customLiteral`(s: string)``.
- See also `Custom Numeric Literals <#custom-numeric-literals>`_.
- Numeric Literals
- ----------------
- Numeric literals have the form::
- hexdigit = digit | 'A'..'F' | 'a'..'f'
- octdigit = '0'..'7'
- bindigit = '0'..'1'
- unary_minus = '-' # See the section about unary minus
- HEX_LIT = unary_minus? '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
- DEC_LIT = unary_minus? digit ( ['_'] digit )*
- OCT_LIT = unary_minus? '0' 'o' octdigit ( ['_'] octdigit )*
- BIN_LIT = unary_minus? '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
- INT_LIT = HEX_LIT
- | DEC_LIT
- | OCT_LIT
- | BIN_LIT
- INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8'
- INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16'
- INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
- INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
- UINT_LIT = INT_LIT ['\''] ('u' | 'U')
- UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
- UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
- UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
- UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64'
- exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
- FLOAT_LIT = unary_minus? digit (['_'] digit)* (('.' digit (['_'] digit)* [exponent]) |exponent)
- FLOAT32_SUFFIX = ('f' | 'F') ['32']
- FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX
- | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX
- FLOAT64_SUFFIX = ( ('f' | 'F') '64' ) | 'd' | 'D'
- FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX
- | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX
- CUSTOM_NUMERIC_LIT = (FLOAT_LIT | INT_LIT) '\'' CUSTOM_NUMERIC_SUFFIX
- # CUSTOM_NUMERIC_SUFFIX is any Nim identifier that is not
- # a pre-defined type suffix.
- As can be seen in the productions, numeric literals can contain underscores
- for readability. Integer and floating-point literals may be given in decimal (no
- prefix), binary (prefix `0b`), octal (prefix `0o`), and hexadecimal
- (prefix `0x`) notation.
- The fact that the unary minus `-` in a number literal like `-1` is considered
- to be part of the literal is a late addition to the language. The rationale is that
- an expression `-128'i8` should be valid and without this special case, this would
- be impossible -- `128` is not a valid `int8` value, only `-128` is.
- For the `unary_minus` rule there are further restrictions that are not covered
- in the formal grammar. For `-` to be part of the number literal its immediately
- preceeding character has to be in the
- set `{' ', '\t', '\n', '\r', ',', ';', '(', '[', '{'}`. This set was designed to
- cover most cases in a natural manner.
- In the following examples, `-1` is a single token:
- .. code-block:: nim
- echo -1
- echo(-1)
- echo [-1]
- echo 3,-1
- "abc";-1
- In the following examples, `-1` is parsed as two separate tokens (as `- 1`):
- .. code-block:: nim
- echo x-1
- echo (int)-1
- echo [a]-1
- "abc"-1
- There exists a literal for each numerical type that is
- defined. The suffix starting with an apostrophe ('\'') is called a
- `type suffix`:idx:. Literals without a type suffix are of an integer type
- unless the literal contains a dot or `E|e` in which case it is of
- type `float`. This integer type is `int` if the literal is in the range
- `low(i32)..high(i32)`, otherwise it is `int64`.
- For notational convenience, the apostrophe of a type suffix
- is optional if it is not ambiguous (only hexadecimal floating-point literals
- with a type suffix can be ambiguous).
- The pre-defined type suffixes are:
- ================= =========================
- Type Suffix Resulting type of literal
- ================= =========================
- `'i8` int8
- `'i16` int16
- `'i32` int32
- `'i64` int64
- `'u` uint
- `'u8` uint8
- `'u16` uint16
- `'u32` uint32
- `'u64` uint64
- `'f` float32
- `'d` float64
- `'f32` float32
- `'f64` float64
- ================= =========================
- Floating-point literals may also be in binary, octal or hexadecimal
- notation:
- `0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`
- is approximately 1.72826e35 according to the IEEE floating-point standard.
- Literals are bounds checked so that they fit the datatype. Non-base-10
- literals are used mainly for flags and bit pattern representations, therefore
- bounds checking is done on bit width, not value range. If the literal fits in
- the bit width of the datatype, it is accepted.
- Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1
- instead of causing an overflow error.
- Custom Numeric Literals
- ~~~~~~~~~~~~~~~~~~~~~~~
- If the suffix is not predefined, then the suffix is assumed to be a call
- to a proc, template, macro or other callable identifier that is passed the
- string containing the literal. The callable identifier needs to be declared
- with a special ``'`` prefix:
- .. code-block:: nim
- import strutils
- type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble"
- proc `'u4`(n: string): u4 =
- # The leading ' is required.
- result = (parseInt(n) and 0x0F).u4
- var x = 5'u4
- More formally, a custom numeric literal `123'custom` is transformed
- to r"123".`'custom` in the parsing step. There is no AST node kind that
- corresponds to this transformation. The transformation naturally handles
- the case that additional parameters are passed to the callee:
- .. code-block:: nim
- import strutils
- type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble"
- proc `'u4`(n: string; moreData: int): u4 =
- result = (parseInt(n) and 0x0F).u4
- var x = 5'u4(123)
- Custom numeric literals are covered by the grammar rule named `CUSTOM_NUMERIC_LIT`.
- A custom numeric literal is a single token.
- Operators
- ---------
- Nim allows user defined operators. An operator is any combination of the
- following characters::
- = + - * / < >
- @ $ ~ & % |
- ! ? ^ . : \
- (The grammar uses the terminal OPR to refer to operator symbols as
- defined here.)
- These keywords are also operators:
- `and or not xor shl shr div mod in notin is isnot of as from`.
- `.`:tok: `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they
- are used for other notational purposes.
- `*:` is as a special case treated as the two tokens `*`:tok: and `:`:tok:
- (to support `var v*: T`).
- The `not` keyword is always a unary operator, `a not b` is parsed
- as `a(not b)`, not as `(a) not (b)`.
- Other tokens
- ------------
- The following strings denote other tokens::
- ` ( ) { } [ ] , ; [. .] {. .} (. .) [:
- The `slice`:idx: operator `..`:tok: takes precedence over other tokens that
- contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok:
- and not the two tokens `{.`:tok:, `.}`:tok:.
- Syntax
- ======
- This section lists Nim's standard syntax. How the parser handles
- the indentation is already described in the `Lexical Analysis`_ section.
- Nim allows user-definable operators.
- Binary operators have 11 different levels of precedence.
- Associativity
- -------------
- Binary operators whose first character is `^` are right-associative, all
- other binary operators are left-associative.
- .. code-block:: nim
- proc `^/`(x, y: float): float =
- # a right-associative division operator
- result = x / y
- echo 12 ^/ 4 ^/ 8 # 24.0 (4 / 8 = 0.5, then 12 / 0.5 = 24.0)
- echo 12 / 4 / 8 # 0.375 (12 / 4 = 3.0, then 3 / 8 = 0.375)
- Precedence
- ----------
- Unary operators always bind stronger than any binary
- operator: `$a + b` is `($a) + b` and not `$(a + b)`.
- If a unary operator's first character is `@` it is a `sigil-like`:idx:
- operator which binds stronger than a `primarySuffix`: `@x.abc` is parsed
- as `(@x).abc` whereas `$x.abc` is parsed as `$(x.abc)`.
- For binary operators that are not keywords, the precedence is determined by the
- following rules:
- Operators ending in either `->`, `~>` or `=>` are called
- `arrow like`:idx:, and have the lowest precedence of all operators.
- If the operator ends with `=` and its first character is none of
- `<`, `>`, `!`, `=`, `~`, `?`, it is an *assignment operator* which
- has the second-lowest precedence.
- Otherwise, precedence is determined by the first character.
- ================ ======================================================= ================== ===============
- Precedence level Operators First character Terminal symbol
- ================ ======================================================= ================== ===============
- 10 (highest) `$ ^` OP10
- 9 `* / div mod shl shr %` `* % \ /` OP9
- 8 `+ -` `+ - ~ |` OP8
- 7 `&` `&` OP7
- 6 `..` `.` OP6
- 5 `== <= < >= > != in notin is isnot not of as from` `= < > !` OP5
- 4 `and` OP4
- 3 `or xor` OP3
- 2 `@ : ?` OP2
- 1 *assignment operator* (like `+=`, `*=`) OP1
- 0 (lowest) *arrow like operator* (like `->`, `=>`) OP0
- ================ ======================================================= ================== ===============
- Whether an operator is used as a prefix operator is also affected by preceding
- whitespace (this parsing change was introduced with version 0.13.0):
- .. code-block:: nim
- echo $foo
- # is parsed as
- echo($foo)
- Spacing also determines whether `(a, b)` is parsed as an argument list
- of a call or whether it is parsed as a tuple constructor:
- .. code-block:: nim
- echo(1, 2) # pass 1 and 2 to echo
- .. code-block:: nim
- echo (1, 2) # pass the tuple (1, 2) to echo
- Grammar
- -------
- The grammar's start symbol is `module`.
- .. include:: grammar.txt
- :literal:
- Order of evaluation
- ===================
- Order of evaluation is strictly left-to-right, inside-out as it is typical for most others
- imperative programming languages:
- .. code-block:: nim
- :test: "nim c $1"
- var s = ""
- proc p(arg: int): int =
- s.add $arg
- result = arg
- discard p(p(1) + p(2))
- doAssert s == "123"
- Assignments are not special, the left-hand-side expression is evaluated before the
- right-hand side:
- .. code-block:: nim
- :test: "nim c $1"
- var v = 0
- proc getI(): int =
- result = v
- inc v
- var a, b: array[0..2, int]
- proc someCopy(a: var int; b: int) = a = b
- a[getI()] = getI()
- doAssert a == [1, 0, 0]
- v = 0
- someCopy(b[getI()], getI())
- doAssert b == [1, 0, 0]
- Rationale: Consistency with overloaded assignment or assignment-like operations,
- `a = b` can be read as `performSomeCopy(a, b)`.
- However, the concept of "order of evaluation" is only applicable after the code
- was normalized: The normalization involves template expansions and argument
- reorderings that have been passed to named parameters:
- .. code-block:: nim
- :test: "nim c $1"
- var s = ""
- proc p(): int =
- s.add "p"
- result = 5
- proc q(): int =
- s.add "q"
- result = 3
- # Evaluation order is 'b' before 'a' due to template
- # expansion's semantics.
- template swapArgs(a, b): untyped =
- b + a
- doAssert swapArgs(p() + q(), q() - p()) == 6
- doAssert s == "qppq"
- # Evaluation order is not influenced by named parameters:
- proc construct(first, second: int) =
- discard
- # 'p' is evaluated before 'q'!
- construct(second = q(), first = p())
- doAssert s == "qppqpq"
- Rationale: This is far easier to implement than hypothetical alternatives.
- Constants and Constant Expressions
- ==================================
- A `constant`:idx: is a symbol that is bound to the value of a constant
- expression. Constant expressions are restricted to depend only on the following
- categories of values and operations, because these are either built into the
- language or declared and evaluated before semantic analysis of the constant
- expression:
- * literals
- * built-in operators
- * previously declared constants and compile-time variables
- * previously declared macros and templates
- * previously declared procedures that have no side effects beyond
- possibly modifying compile-time variables
- A constant expression can contain code blocks that may internally use all Nim
- features supported at compile time (as detailed in the next section below).
- Within such a code block, it is possible to declare variables and then later
- read and update them, or declare variables and pass them to procedures that
- modify them. However, the code in such a block must still adhere to the
- restrictions listed above for referencing values and operations outside the
- block.
- The ability to access and modify compile-time variables adds flexibility to
- constant expressions that may be surprising to those coming from other
- statically typed languages. For example, the following code echoes the beginning
- of the Fibonacci series **at compile-time**. (This is a demonstration of
- flexibility in defining constants, not a recommended style for solving this
- problem.)
- .. code-block:: nim
- :test: "nim c $1"
- import std/strformat
- var fibN {.compileTime.}: int
- var fibPrev {.compileTime.}: int
- var fibPrevPrev {.compileTime.}: int
- proc nextFib(): int =
- result = if fibN < 2:
- fibN
- else:
- fibPrevPrev + fibPrev
- inc(fibN)
- fibPrevPrev = fibPrev
- fibPrev = result
- const f0 = nextFib()
- const f1 = nextFib()
- const displayFib = block:
- const f2 = nextFib()
- var result = fmt"Fibonacci sequence: {f0}, {f1}, {f2}"
- for i in 3..12:
- add(result, fmt", {nextFib()}")
- result
- static:
- echo displayFib
- Restrictions on Compile-Time Execution
- ======================================
- Nim code that will be executed at compile time cannot use the following
- language features:
- * methods
- * closure iterators
- * the `cast` operator
- * reference (pointer) types
- * FFI
- The use of wrappers that use FFI and/or `cast` is also disallowed. Note that
- these wrappers include the ones in the standard libraries.
- Some or all of these restrictions are likely to be lifted over time.
- Types
- =====
- All expressions have a type that is known during semantic analysis. Nim
- is statically typed. One can declare new types, which is in essence defining
- an identifier that can be used to denote this custom type.
- These are the major type classes:
- * ordinal types (consist of integer, bool, character, enumeration
- (and subranges thereof) types)
- * floating-point types
- * string type
- * structured types
- * reference (pointer) type
- * procedural type
- * generic type
- Ordinal types
- -------------
- Ordinal types have the following characteristics:
- - Ordinal types are countable and ordered. This property allows the operation
- of functions such as `inc`, `ord`, and `dec` on ordinal types to
- be defined.
- - Ordinal values have the smallest possible value. Trying to count further
- down than the smallest value produces a panic or a static error.
- - Ordinal values have the largest possible value. Trying to count further
- than the largest value produces a panic or a static error.
- Integers, bool, characters, and enumeration types (and subranges of these
- types) belong to ordinal types.
- A distinct type is an ordinal type if its base type is an ordinal type.
- Pre-defined integer types
- -------------------------
- These integer types are pre-defined:
- `int`
- the generic signed integer type; its size is platform-dependent and has the
- same size as a pointer. This type should be used in general. An integer
- literal that has no type suffix is of this type if it is in the range
- `low(int32)..high(int32)` otherwise the literal's type is `int64`.
- `int`\ XX
- additional signed integer types of XX bits use this naming scheme
- (example: int16 is a 16-bit wide integer).
- The current implementation supports `int8`, `int16`, `int32`, `int64`.
- Literals of these types have the suffix 'iXX.
- `uint`
- the generic `unsigned integer`:idx: type; its size is platform-dependent and
- has the same size as a pointer. An integer literal with the type
- suffix `'u` is of this type.
- `uint`\ XX
- additional unsigned integer types of XX bits use this naming scheme
- (example: uint16 is a 16-bit wide unsigned integer).
- The current implementation supports `uint8`, `uint16`, `uint32`,
- `uint64`. Literals of these types have the suffix 'uXX.
- Unsigned operations all wrap around; they cannot lead to over- or
- underflow errors.
- In addition to the usual arithmetic operators for signed and unsigned integers
- (`+ - *` etc.) there are also operators that formally work on *signed*
- integers but treat their arguments as *unsigned*: They are mostly provided
- for backwards compatibility with older versions of the language that lacked
- unsigned integer types. These unsigned operations for signed integers use
- the `%` suffix as convention:
- ====================== ======================================================
- operation meaning
- ====================== ======================================================
- `a +% b` unsigned integer addition
- `a -% b` unsigned integer subtraction
- `a *% b` unsigned integer multiplication
- `a /% b` unsigned integer division
- `a %% b` unsigned integer modulo operation
- `a <% b` treat `a` and `b` as unsigned and compare
- `a <=% b` treat `a` and `b` as unsigned and compare
- `ze(a)` extends the bits of `a` with zeros until it has the
- width of the `int` type
- `toU8(a)` treats `a` as unsigned and converts it to an
- unsigned integer of 8 bits (but still the
- `int8` type)
- `toU16(a)` treats `a` as unsigned and converts it to an
- unsigned integer of 16 bits (but still the
- `int16` type)
- `toU32(a)` treats `a` as unsigned and converts it to an
- unsigned integer of 32 bits (but still the
- `int32` type)
- ====================== ======================================================
- `Automatic type conversion`:idx: is performed in expressions where different
- kinds of integer types are used: the smaller type is converted to the larger.
- A `narrowing type conversion`:idx: converts a larger to a smaller type (for
- example `int32 -> int16`). A `widening type conversion`:idx: converts a
- smaller type to a larger type (for example `int16 -> int32`). In Nim only
- widening type conversions are *implicit*:
- .. code-block:: nim
- var myInt16 = 5i16
- var myInt: int
- myInt16 + 34 # of type `int16`
- myInt16 + myInt # of type `int`
- myInt16 + 2i32 # of type `int32`
- However, `int` literals are implicitly convertible to a smaller integer type
- if the literal's value fits this smaller type and such a conversion is less
- expensive than other implicit conversions, so `myInt16 + 34` produces
- an `int16` result.
- For further details, see `Convertible relation
- <#type-relations-convertible-relation>`_.
- Subrange types
- --------------
- A subrange type is a range of values from an ordinal or floating-point type (the base
- type). To define a subrange type, one must specify its limiting values -- the
- lowest and highest value of the type. For example:
- .. code-block:: nim
- type
- Subrange = range[0..5]
- PositiveFloat = range[0.0..Inf]
- `Subrange` is a subrange of an integer which can only hold the values 0
- to 5. `PositiveFloat` defines a subrange of all positive floating-point values.
- NaN does not belong to any subrange of floating-point types.
- Assigning any other value to a variable of type `Subrange` is a
- panic (or a static error if it can be determined during
- semantic analysis). Assignments from the base type to one of its subrange types
- (and vice versa) are allowed.
- A subrange type has the same size as its base type (`int` in the
- Subrange example).
- Pre-defined floating-point types
- --------------------------------
- The following floating-point types are pre-defined:
- `float`
- the generic floating-point type; its size used to be platform-dependent,
- but now it is always mapped to `float64`.
- This type should be used in general.
- `float`\ XX
- an implementation may define additional floating-point types of XX bits using
- this naming scheme (example: `float64` is a 64-bit wide float). The current
- implementation supports `float32` and `float64`. Literals of these types
- have the suffix 'fXX.
- Automatic type conversion in expressions with different kinds
- of floating-point types is performed: See `Convertible relation`_ for further
- details. Arithmetic performed on floating-point types follows the IEEE
- standard. Integer types are not converted to floating-point types automatically
- and vice versa.
- The IEEE standard defines five types of floating-point exceptions:
- * Invalid: operations with mathematically invalid operands,
- for example 0.0/0.0, sqrt(-1.0), and log(-37.8).
- * Division by zero: divisor is zero and dividend is a finite nonzero number,
- for example 1.0/0.0.
- * Overflow: operation produces a result that exceeds the range of the exponent,
- for example MAXDOUBLE+0.0000000000001e308.
- * Underflow: operation produces a result that is too small to be represented
- as a normal number, for example, MINDOUBLE * MINDOUBLE.
- * Inexact: operation produces a result that cannot be represented with infinite
- precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
- The IEEE exceptions are either ignored during execution or mapped to the
- Nim exceptions: `FloatInvalidOpDefect`:idx:, `FloatDivByZeroDefect`:idx:,
- `FloatOverflowDefect`:idx:, `FloatUnderflowDefect`:idx:,
- and `FloatInexactDefect`:idx:.
- These exceptions inherit from the `FloatingPointDefect`:idx: base class.
- Nim provides the pragmas `nanChecks`:idx: and `infChecks`:idx: to control
- whether the IEEE exceptions are ignored or trap a Nim exception:
- .. code-block:: nim
- {.nanChecks: on, infChecks: on.}
- var a = 1.0
- var b = 0.0
- echo b / b # raises FloatInvalidOpDefect
- echo a / b # raises FloatOverflowDefect
- In the current implementation `FloatDivByZeroDefect` and `FloatInexactDefect`
- are never raised. `FloatOverflowDefect` is raised instead of
- `FloatDivByZeroDefect`.
- There is also a `floatChecks`:idx: pragma that is a short-cut for the
- combination of `nanChecks` and `infChecks` pragmas. `floatChecks` are
- turned off as default.
- The only operations that are affected by the `floatChecks` pragma are
- the `+`, `-`, `*`, `/` operators for floating-point types.
- An implementation should always use the maximum precision available to evaluate
- floating pointer values during semantic analysis; this means expressions like
- `0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64` that are evaluating during
- constant folding are true.
- Boolean type
- ------------
- The boolean type is named `bool`:idx: in Nim and can be one of the two
- pre-defined values `true` and `false`. Conditions in `while`,
- `if`, `elif`, `when`-statements need to be of type `bool`.
- This condition holds::
- ord(false) == 0 and ord(true) == 1
- The operators `not, and, or, xor, <, <=, >, >=, !=, ==` are defined
- for the bool type. The `and` and `or` operators perform short-cut
- evaluation. Example:
- .. code-block:: nim
- while p != nil and p.name != "xyz":
- # p.name is not evaluated if p == nil
- p = p.next
- The size of the bool type is one byte.
- Character type
- --------------
- The character type is named `char` in Nim. Its size is one byte.
- Thus it cannot represent a UTF-8 character, but a part of it.
- The `Rune` type is used for Unicode characters, it can represent any Unicode
- character. `Rune` is declared in the `unicode module <unicode.html>`_.
- Enumeration types
- -----------------
- Enumeration types define a new type whose values consist of the ones
- specified. The values are ordered. Example:
- .. code-block:: nim
- type
- Direction = enum
- north, east, south, west
- Now the following holds::
- ord(north) == 0
- ord(east) == 1
- ord(south) == 2
- ord(west) == 3
- # Also allowed:
- ord(Direction.west) == 3
- The implied order is: north < east < south < west. The comparison operators can be used
- with enumeration types. Instead of `north` etc, the enum value can also
- be qualified with the enum type that it resides in, `Direction.north`.
- For better interfacing to other programming languages, the fields of enum
- types can be assigned an explicit ordinal value. However, the ordinal values
- have to be in ascending order. A field whose ordinal value is not
- explicitly given is assigned the value of the previous field + 1.
- An explicit ordered enum can have *holes*:
- .. code-block:: nim
- type
- TokenType = enum
- a = 2, b = 4, c = 89 # holes are valid
- However, it is then not ordinal anymore, so it is impossible to use these
- enums as an index type for arrays. The procedures `inc`, `dec`, `succ`
- and `pred` are not available for them either.
- The compiler supports the built-in stringify operator `$` for enumerations.
- The stringify's result can be controlled by explicitly giving the string
- values to use:
- .. code-block:: nim
- type
- MyEnum = enum
- valueA = (0, "my value A"),
- valueB = "value B",
- valueC = 2,
- valueD = (3, "abc")
- As can be seen from the example, it is possible to both specify a field's
- ordinal value and its string value by using a tuple. It is also
- possible to only specify one of them.
- An enum can be marked with the `pure` pragma so that its fields are
- added to a special module-specific hidden scope that is only queried
- as the last attempt. Only non-ambiguous symbols are added to this scope.
- But one can always access these via type qualification written
- as `MyEnum.value`:
- .. code-block:: nim
- type
- MyEnum {.pure.} = enum
- valueA, valueB, valueC, valueD, amb
- OtherEnum {.pure.} = enum
- valueX, valueY, valueZ, amb
- echo valueA # MyEnum.valueA
- echo amb # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb
- echo MyEnum.amb # OK.
- To implement bit fields with enums see `Bit fields <#set-type-bit-fields>`_
- String type
- -----------
- All string literals are of the type `string`. A string in Nim is very
- similar to a sequence of characters. However, strings in Nim are both
- zero-terminated and have a length field. One can retrieve the length with the
- builtin `len` procedure; the length never counts the terminating zero.
- The terminating zero cannot be accessed unless the string is converted
- to the `cstring` type first. The terminating zero assures that this
- conversion can be done in O(1) and without any allocations.
- The assignment operator for strings always copies the string.
- The `&` operator concatenates strings.
- Most native Nim types support conversion to strings with the special `$` proc.
- When calling the `echo` proc, for example, the built-in stringify operation
- for the parameter is called:
- .. code-block:: nim
- echo 3 # calls `$` for `int`
- Whenever a user creates a specialized object, implementation of this procedure
- provides for `string` representation.
- .. code-block:: nim
- type
- Person = object
- name: string
- age: int
- proc `$`(p: Person): string = # `$` always returns a string
- result = p.name & " is " &
- $p.age & # we *need* the `$` in front of p.age which
- # is natively an integer to convert it to
- # a string
- " years old."
- While `$p.name` can also be used, the `$` operation on a string does
- nothing. Note that we cannot rely on automatic conversion from an `int` to
- a `string` like we can for the `echo` proc.
- Strings are compared by their lexicographical order. All comparison operators
- are available. Strings can be indexed like arrays (lower bound is 0). Unlike
- arrays, they can be used in case statements:
- .. code-block:: nim
- case paramStr(i)
- of "-v": incl(options, optVerbose)
- of "-h", "-?": incl(options, optHelp)
- else: write(stdout, "invalid command line option!\n")
- Per convention, all strings are UTF-8 strings, but this is not enforced. For
- example, when reading strings from binary files, they are merely a sequence of
- bytes. The index operation `s[i]` means the i-th *char* of `s`, not the
- i-th *unichar*. The iterator `runes` from the `unicode module
- <unicode.html>`_ can be used for iteration over all Unicode characters.
- cstring type
- ------------
- The `cstring` type meaning `compatible string` is the native representation
- of a string for the compilation backend. For the C backend the `cstring` type
- represents a pointer to a zero-terminated char array
- compatible with the type `char*` in Ansi C. Its primary purpose lies in easy
- interfacing with C. The index operation `s[i]` means the i-th *char* of
- `s`; however no bounds checking for `cstring` is performed making the
- index operation unsafe.
- A Nim `string` is implicitly convertible
- to `cstring` for convenience. If a Nim string is passed to a C-style
- variadic proc, it is implicitly converted to `cstring` too:
- .. code-block:: nim
- proc printf(formatstr: cstring) {.importc: "printf", varargs,
- header: "<stdio.h>".}
- printf("This works %s", "as expected")
- Even though the conversion is implicit, it is not *safe*: The garbage collector
- does not consider a `cstring` to be a root and may collect the underlying
- memory. However, in practice, this almost never happens as the GC considers
- stack roots conservatively. One can use the builtin procs `GC_ref` and
- `GC_unref` to keep the string data alive for the rare cases where it does
- not work.
- A `$` proc is defined for cstrings that returns a string. Thus to get a nim
- string from a cstring:
- .. code-block:: nim
- var str: string = "Hello!"
- var cstr: cstring = str
- var newstr: string = $cstr
- `cstring` literals shouldn't be modified.
- .. code-block:: nim
- var x = cstring"literals"
- x[1] = 'A' # This is wrong!!!
- If the `cstring` originates from a regular memory (not read-only memory),
- it can be modified:
- .. code-block:: nim
- var x = "123456"
- var s: cstring = x
- s[0] = 'u' # This is ok
- Structured types
- ----------------
- A variable of a structured type can hold multiple values at the same
- time. Structured types can be nested to unlimited levels. Arrays, sequences,
- tuples, objects, and sets belong to the structured types.
- Array and sequence types
- ------------------------
- Arrays are a homogeneous type, meaning that each element in the array has the
- same type. Arrays always have a fixed length specified as a constant expression
- (except for open arrays). They can be indexed by any ordinal type.
- A parameter `A` may be an *open array*, in which case it is indexed by
- integers from 0 to `len(A)-1`. An array expression may be constructed by the
- array constructor `[]`. The element type of this array expression is
- inferred from the type of the first element. All other elements need to be
- implicitly convertible to this type.
- An array type can be defined using the `array[size, T]` syntax, or using
- `array[lo..hi, T]` for arrays that start at an index other than zero.
- Sequences are similar to arrays but of dynamic length which may change
- during runtime (like strings). Sequences are implemented as growable arrays,
- allocating pieces of memory as items are added. A sequence `S` is always
- indexed by integers from 0 to `len(S)-1` and its bounds are checked.
- Sequences can be constructed by the array constructor `[]` in conjunction
- with the array to sequence operator `@`. Another way to allocate space for a
- sequence is to call the built-in `newSeq` procedure.
- A sequence may be passed to a parameter that is of type *open array*.
- Example:
- .. code-block:: nim
- type
- IntArray = array[0..5, int] # an array that is indexed with 0..5
- IntSeq = seq[int] # a sequence of integers
- var
- x: IntArray
- y: IntSeq
- x = [1, 2, 3, 4, 5, 6] # [] is the array constructor
- y = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence
- let z = [1.0, 2, 3, 4] # the type of z is array[0..3, float]
- The lower bound of an array or sequence may be received by the built-in proc
- `low()`, the higher bound by `high()`. The length may be
- received by `len()`. `low()` for a sequence or an open array always returns
- 0, as this is the first valid index.
- One can append elements to a sequence with the `add()` proc or the `&`
- operator, and remove (and get) the last element of a sequence with the
- `pop()` proc.
- The notation `x[i]` can be used to access the i-th element of `x`.
- Arrays are always bounds checked (statically or at runtime). These
- checks can be disabled via pragmas or invoking the compiler with the
- ``--boundChecks:off`` command-line switch.
- An array constructor can have explicit indexes for readability:
- .. code-block:: nim
- type
- Values = enum
- valA, valB, valC
- const
- lookupTable = [
- valA: "A",
- valB: "B",
- valC: "C"
- ]
- If an index is left out, `succ(lastIndex)` is used as the index
- value:
- .. code-block:: nim
- type
- Values = enum
- valA, valB, valC, valD, valE
- const
- lookupTable = [
- valA: "A",
- "B",
- valC: "C",
- "D", "e"
- ]
- Open arrays
- -----------
- Often fixed size arrays turn out to be too inflexible; procedures should
- be able to deal with arrays of different sizes. The `openarray`:idx: type
- allows this; it can only be used for parameters. Openarrays are always
- indexed with an `int` starting at position 0. The `len`, `low`
- and `high` operations are available for open arrays too. Any array with
- a compatible base type can be passed to an openarray parameter, the index
- type does not matter. In addition to arrays, sequences can also be passed
- to an open array parameter.
- The openarray type cannot be nested: multidimensional openarrays are not
- supported because this is seldom needed and cannot be done efficiently.
- .. code-block:: nim
- proc testOpenArray(x: openArray[int]) = echo repr(x)
- testOpenArray([1,2,3]) # array[]
- testOpenArray(@[1,2,3]) # seq[]
- Varargs
- -------
- A `varargs` parameter is an openarray parameter that additionally
- allows to pass a variable number of arguments to a procedure. The compiler
- converts the list of arguments to an array implicitly:
- .. code-block:: nim
- proc myWriteln(f: File, a: varargs[string]) =
- for s in items(a):
- write(f, s)
- write(f, "\n")
- myWriteln(stdout, "abc", "def", "xyz")
- # is transformed to:
- myWriteln(stdout, ["abc", "def", "xyz"])
- This transformation is only done if the varargs parameter is the
- last parameter in the procedure header. It is also possible to perform
- type conversions in this context:
- .. code-block:: nim
- proc myWriteln(f: File, a: varargs[string, `$`]) =
- for s in items(a):
- write(f, s)
- write(f, "\n")
- myWriteln(stdout, 123, "abc", 4.0)
- # is transformed to:
- myWriteln(stdout, [$123, $"def", $4.0])
- In this example `$` is applied to any argument that is passed to the
- parameter `a`. (Note that `$` applied to strings is a nop.)
- Note that an explicit array constructor passed to a `varargs` parameter is
- not wrapped in another implicit array construction:
- .. code-block:: nim
- proc takeV[T](a: varargs[T]) = discard
- takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
- `varargs[typed]` is treated specially: It matches a variable list of arguments
- of arbitrary type but *always* constructs an implicit array. This is required
- so that the builtin `echo` proc does what is expected:
- .. code-block:: nim
- proc echo*(x: varargs[typed, `$`]) {...}
- echo @[1, 2, 3]
- # prints "@[1, 2, 3]" and not "123"
- Unchecked arrays
- ----------------
- The `UncheckedArray[T]` type is a special kind of `array` where its bounds
- are not checked. This is often useful to implement customized flexibly sized
- arrays. Additionally, an unchecked array is translated into a C array of
- undetermined size:
- .. code-block:: nim
- type
- MySeq = object
- len, cap: int
- data: UncheckedArray[int]
- Produces roughly this C code:
- .. code-block:: C
- typedef struct {
- NI len;
- NI cap;
- NI data[];
- } MySeq;
- The base type of the unchecked array may not contain any GC'ed memory but this
- is currently not checked.
- **Future directions**: GC'ed memory should be allowed in unchecked arrays and
- there should be an explicit annotation of how the GC is to determine the
- runtime size of the array.
- Tuples and object types
- -----------------------
- A variable of a tuple or object type is a heterogeneous storage
- container.
- A tuple or object defines various named *fields* of a type. A tuple also
- defines a lexicographic *order* of the fields. Tuples are meant to be
- heterogeneous storage types with few abstractions. The `()` syntax
- can be used to construct tuples. The order of the fields in the constructor
- must match the order of the tuple's definition. Different tuple-types are
- *equivalent* if they specify the same fields of the same type in the same
- order. The *names* of the fields also have to be identical.
- The assignment operator for tuples copies each component.
- The default assignment operator for objects copies each component. Overloading
- of the assignment operator is described `here
- <manual_experimental.html#type-bound-operations>`_.
- .. code-block:: nim
- type
- Person = tuple[name: string, age: int] # type representing a person:
- # a person consists of a name
- # and an age
- var
- person: Person
- person = (name: "Peter", age: 30)
- echo person.name
- # the same, but less readable:
- person = ("Peter", 30)
- echo person[0]
- A tuple with one unnamed field can be constructed with the parentheses and a
- trailing comma:
- .. code-block:: nim
- proc echoUnaryTuple(a: (int,)) =
- echo a[0]
- echoUnaryTuple (1,)
- In fact, a trailing comma is allowed for every tuple construction.
- The implementation aligns the fields for the best access performance. The alignment
- is compatible with the way the C compiler does it.
- For consistency with `object` declarations, tuples in a `type` section
- can also be defined with indentation instead of `[]`:
- .. code-block:: nim
- type
- Person = tuple # type representing a person
- name: string # a person consists of a name
- age: Natural # and an age
- Objects provide many features that tuples do not. Objects provide inheritance
- and the ability to hide fields from other modules. Objects with inheritance
- enabled have information about their type at runtime so that the `of` operator
- can be used to determine the object's type. The `of` operator is similar to
- the `instanceof` operator in Java.
- .. code-block:: nim
- type
- Person = object of RootObj
- name*: string # the * means that `name` is accessible from other modules
- age: int # no * means that the field is hidden
- Student = ref object of Person # a student is a person
- id: int # with an id field
- var
- student: Student
- person: Person
- assert(student of Student) # is true
- assert(student of Person) # also true
- Object fields that should be visible from outside the defining module have to
- be marked by `*`. In contrast to tuples, different object types are
- never *equivalent*, they are nominal types whereas tuples are structural.
- Objects that have no ancestor are implicitly `final` and thus have no hidden
- type information. One can use the `inheritable` pragma to
- introduce new object roots apart from `system.RootObj`.
- .. code-block:: nim
- type
- Person = object # example of a final object
- name*: string
- age: int
- Student = ref object of Person # Error: inheritance only works with non-final objects
- id: int
- Object construction
- -------------------
- Objects can also be created with an `object construction expression`:idx: that
- has the syntax `T(fieldA: valueA, fieldB: valueB, ...)` where `T` is
- an `object` type or a `ref object` type:
- .. code-block:: nim
- var student = Student(name: "Anton", age: 5, id: 3)
- Note that, unlike tuples, objects require the field names along with their values.
- For a `ref object` type `system.new` is invoked implicitly.
- Object variants
- ---------------
- Often an object hierarchy is an overkill in certain situations where simple variant
- types are needed. Object variants are tagged unions discriminated via an
- enumerated type used for runtime type flexibility, mirroring the concepts of
- *sum types* and *algebraic data types (ADTs)* as found in other languages.
- An example:
- .. code-block:: nim
- # This is an example of how an abstract syntax tree could be modelled in Nim
- type
- NodeKind = enum # the different node types
- nkInt, # a leaf with an integer value
- nkFloat, # a leaf with a float value
- nkString, # a leaf with a string value
- nkAdd, # an addition
- nkSub, # a subtraction
- nkIf # an if statement
- Node = ref NodeObj
- NodeObj = object
- case kind: NodeKind # the `kind` field is the discriminator
- of nkInt: intVal: int
- of nkFloat: floatVal: float
- of nkString: strVal: string
- of nkAdd, nkSub:
- leftOp, rightOp: Node
- of nkIf:
- condition, thenPart, elsePart: Node
- # create a new case object:
- var n = Node(kind: nkIf, condition: nil)
- # accessing n.thenPart is valid because the `nkIf` branch is active:
- n.thenPart = Node(kind: nkFloat, floatVal: 2.0)
- # the following statement raises an `FieldDefect` exception, because
- # n.kind's value does not fit and the `nkString` branch is not active:
- n.strVal = ""
- # invalid: would change the active object branch:
- n.kind = nkInt
- var x = Node(kind: nkAdd, leftOp: Node(kind: nkInt, intVal: 4),
- rightOp: Node(kind: nkInt, intVal: 2))
- # valid: does not change the active object branch:
- x.kind = nkSub
- As can be seen from the example, an advantage to an object hierarchy is that
- no casting between different object types is needed. Yet, access to invalid
- object fields raises an exception.
- The syntax of `case` in an object declaration follows closely the syntax of
- the `case` statement: The branches in a `case` section may be indented too.
- In the example, the `kind` field is called the `discriminator`:idx:\: For
- safety, its address cannot be taken and assignments to it are restricted: The
- new value must not lead to a change of the active object branch. Also, when the
- fields of a particular branch are specified during object construction, the
- corresponding discriminator value must be specified as a constant expression.
- Instead of changing the active object branch, replace the old object in memory
- with a new one completely:
- .. code-block:: nim
- var x = Node(kind: nkAdd, leftOp: Node(kind: nkInt, intVal: 4),
- rightOp: Node(kind: nkInt, intVal: 2))
- # change the node's contents:
- x[] = NodeObj(kind: nkString, strVal: "abc")
- Starting with version 0.20 `system.reset` cannot be used anymore to support
- object branch changes as this never was completely memory safe.
- As a special rule, the discriminator kind can also be bounded using a `case`
- statement. If possible values of the discriminator variable in a
- `case` statement branch are a subset of discriminator values for the selected
- object branch, the initialization is considered valid. This analysis only works
- for immutable discriminators of an ordinal type and disregards `elif`
- branches. For discriminator values with a `range` type, the compiler
- checks if the entire range of possible values for the discriminator value is
- valid for the chosen object branch.
- A small example:
- .. code-block:: nim
- let unknownKind = nkSub
- # invalid: unsafe initialization because the kind field is not statically known:
- var y = Node(kind: unknownKind, strVal: "y")
- var z = Node()
- case unknownKind
- of nkAdd, nkSub:
- # valid: possible values of this branch are a subset of nkAdd/nkSub object branch:
- z = Node(kind: unknownKind, leftOp: Node(), rightOp: Node())
- else:
- echo "ignoring: ", unknownKind
- # also valid, since unknownKindBounded can only contain the values nkAdd or nkSub
- let unknownKindBounded = range[nkAdd..nkSub](unknownKind)
- z = Node(kind: unknownKindBounded, leftOp: Node(), rightOp: Node())
- Set type
- --------
- .. include:: sets_fragment.txt
- Reference and pointer types
- ---------------------------
- References (similar to pointers in other programming languages) are a
- way to introduce many-to-one relationships. This means different references can
- point to and modify the same location in memory (also called `aliasing`:idx:).
- Nim distinguishes between `traced`:idx: and `untraced`:idx: references.
- Untraced references are also called *pointers*. Traced references point to
- objects of a garbage-collected heap, untraced references point to
- manually allocated objects or objects somewhere else in memory. Thus
- untraced references are *unsafe*. However, for certain low-level operations
- (accessing the hardware) untraced references are unavoidable.
- Traced references are declared with the **ref** keyword, untraced references
- are declared with the **ptr** keyword. In general, a `ptr T` is implicitly
- convertible to the `pointer` type.
- An empty subscript `[]` notation can be used to de-refer a reference,
- the `addr` procedure returns the address of an item. An address is always
- an untraced reference.
- Thus the usage of `addr` is an *unsafe* feature.
- The `.` (access a tuple/object field operator)
- and `[]` (array/string/sequence index operator) operators perform implicit
- dereferencing operations for reference types:
- .. code-block:: nim
- type
- Node = ref NodeObj
- NodeObj = object
- le, ri: Node
- data: int
- var
- n: Node
- new(n)
- n.data = 9
- # no need to write n[].data; in fact n[].data is highly discouraged!
- Automatic dereferencing can be performed for the first argument of a routine
- call, but this is an experimental feature and is described `here
- <manual_experimental.html#automatic-dereferencing>`_.
- In order to simplify structural type checking, recursive tuples are not valid:
- .. code-block:: nim
- # invalid recursion
- type MyTuple = tuple[a: ref MyTuple]
- Likewise `T = ref T` is an invalid type.
- As a syntactical extension, `object` types can be anonymous if
- declared in a type section via the `ref object` or `ptr object` notations.
- This feature is useful if an object should only gain reference semantics:
- .. code-block:: nim
- type
- Node = ref object
- le, ri: Node
- data: int
- To allocate a new traced object, the built-in procedure `new` has to be used.
- To deal with untraced memory, the procedures `alloc`, `dealloc` and
- `realloc` can be used. The documentation of the `system <system.html>`_ module
- contains further information.
- Nil
- ---
- If a reference points to *nothing*, it has the value `nil`. `nil` is the
- default value for all `ref` and `ptr` types. The `nil` value can also be
- used like any other literal value. For example, it can be used in an assignment
- like `myRef = nil`.
- Dereferencing `nil` is an unrecoverable fatal runtime error (and not a panic).
- A successful dereferencing operation `p[]` implies that `p` is not nil. This
- can be exploited by the implementation to optimize code like:
- .. code-block:: nim
- p[].field = 3
- if p != nil:
- # if p were nil, `p[]` would have caused a crash already,
- # so we know `p` is always not nil here.
- action()
- Into:
- .. code-block:: nim
- p[].field = 3
- action()
- *Note*: This is not comparable to C's "undefined behavior" for
- dereferencing NULL pointers.
- Mixing GC'ed memory with `ptr`
- --------------------------------
- Special care has to be taken if an untraced object contains traced objects like
- traced references, strings, or sequences: in order to free everything properly,
- the built-in procedure `reset` has to be called before freeing the untraced
- memory manually:
- .. code-block:: nim
- type
- Data = tuple[x, y: int, s: string]
- # allocate memory for Data on the heap:
- var d = cast[ptr Data](alloc0(sizeof(Data)))
- # create a new string on the garbage collected heap:
- d.s = "abc"
- # tell the GC that the string is not needed anymore:
- reset(d.s)
- # free the memory:
- dealloc(d)
- Without the `reset` call the memory allocated for the `d.s` string would
- never be freed. The example also demonstrates two important features for
- low-level programming: the `sizeof` proc returns the size of a type or value
- in bytes. The `cast` operator can circumvent the type system: the compiler
- is forced to treat the result of the `alloc0` call (which returns an untyped
- pointer) as if it would have the type `ptr Data`. Casting should only be
- done if it is unavoidable: it breaks type safety and bugs can lead to
- mysterious crashes.
- **Note**: The example only works because the memory is initialized to zero
- (`alloc0` instead of `alloc` does this): `d.s` is thus initialized to
- binary zero which the string assignment can handle. One needs to know low-level
- details like this when mixing garbage-collected data with unmanaged memory.
- .. XXX finalizers for traced objects
- Procedural type
- ---------------
- A procedural type is internally a pointer to a procedure. `nil` is
- an allowed value for variables of a procedural type. Nim uses procedural
- types to achieve `functional`:idx: programming techniques.
- Examples:
- .. code-block:: nim
- proc printItem(x: int) = ...
- proc forEach(c: proc (x: int) {.cdecl.}) =
- ...
- forEach(printItem) # this will NOT compile because calling conventions differ
- .. code-block:: nim
- type
- OnMouseMove = proc (x, y: int) {.closure.}
- proc onMouseMove(mouseX, mouseY: int) =
- # has default calling convention
- echo "x: ", mouseX, " y: ", mouseY
- proc setOnMouseMove(mouseMoveEvent: OnMouseMove) = discard
- # ok, 'onMouseMove' has the default calling convention, which is compatible
- # to 'closure':
- setOnMouseMove(onMouseMove)
- A subtle issue with procedural types is that the calling convention of the
- procedure influences the type compatibility: procedural types are only
- compatible if they have the same calling convention. As a special extension,
- a procedure of the calling convention `nimcall` can be passed to a parameter
- that expects a proc of the calling convention `closure`.
- Nim supports these `calling conventions`:idx:\:
- `nimcall`:idx:
- is the default convention used for a Nim **proc**. It is the
- same as `fastcall`, but only for C compilers that support `fastcall`.
- `closure`:idx:
- is the default calling convention for a **procedural type** that lacks
- any pragma annotations. It indicates that the procedure has a hidden
- implicit parameter (an *environment*). Proc vars that have the calling
- convention `closure` take up two machine words: One for the proc pointer
- and another one for the pointer to implicitly passed environment.
- `stdcall`:idx:
- This is the stdcall convention as specified by Microsoft. The generated C
- procedure is declared with the `__stdcall` keyword.
- `cdecl`:idx:
- The cdecl convention means that a procedure shall use the same convention
- as the C compiler. Under Windows the generated C procedure is declared with
- the `__cdecl` keyword.
- `safecall`:idx:
- This is the safecall convention as specified by Microsoft. The generated C
- procedure is declared with the `__safecall` keyword. The word *safe*
- refers to the fact that all hardware registers shall be pushed to the
- hardware stack.
- `inline`:idx:
- The inline convention means the caller should not call the procedure,
- but inline its code directly. Note that Nim does not inline, but leaves
- this to the C compiler; it generates `__inline` procedures. This is
- only a hint for the compiler: it may completely ignore it and
- it may inline procedures that are not marked as `inline`.
- `fastcall`:idx:
- Fastcall means different things to different C compilers. One gets whatever
- the C `__fastcall` means.
- `thiscall`:idx:
- This is the thiscall calling convention as specified by Microsoft, used on
- C++ class member functions on the x86 architecture.
- `syscall`:idx:
- The syscall convention is the same as `__syscall`:c: in C. It is used for
- interrupts.
- `noconv`:idx:
- The generated C code will not have any explicit calling convention and thus
- use the C compiler's default calling convention. This is needed because
- Nim's default calling convention for procedures is `fastcall` to
- improve speed.
- Most calling conventions exist only for the Windows 32-bit platform.
- The default calling convention is `nimcall`, unless it is an inner proc (a
- proc inside of a proc). For an inner proc an analysis is performed whether it
- accesses its environment. If it does so, it has the calling convention
- `closure`, otherwise it has the calling convention `nimcall`.
- Distinct type
- -------------
- A `distinct` type is a new type derived from a `base type`:idx: that is
- incompatible with its base type. In particular, it is an essential property
- of a distinct type that it **does not** imply a subtype relation between it
- and its base type. Explicit type conversions from a distinct type to its
- base type and vice versa are allowed. See also `distinctBase` to get the
- reverse operation.
- A distinct type is an ordinal type if its base type is an ordinal type.
- Modeling currencies
- ~~~~~~~~~~~~~~~~~~~~
- A distinct type can be used to model different physical `units`:idx: with a
- numerical base type, for example. The following example models currencies.
- Different currencies should not be mixed in monetary calculations. Distinct
- types are a perfect tool to model different currencies:
- .. code-block:: nim
- type
- Dollar = distinct int
- Euro = distinct int
- var
- d: Dollar
- e: Euro
- echo d + 12
- # Error: cannot add a number with no unit and a `Dollar`
- Unfortunately, `d + 12.Dollar` is not allowed either,
- because `+` is defined for `int` (among others), not for `Dollar`. So
- a `+` for dollars needs to be defined:
- .. code-block::
- proc `+` (x, y: Dollar): Dollar =
- result = Dollar(int(x) + int(y))
- It does not make sense to multiply a dollar with a dollar, but with a
- number without unit; and the same holds for division:
- .. code-block::
- proc `*` (x: Dollar, y: int): Dollar =
- result = Dollar(int(x) * y)
- proc `*` (x: int, y: Dollar): Dollar =
- result = Dollar(x * int(y))
- proc `div` ...
- This quickly gets tedious. The implementations are trivial and the compiler
- should not generate all this code only to optimize it away later - after all
- `+` for dollars should produce the same binary code as `+` for ints.
- The pragma `borrow`:idx: has been designed to solve this problem; in principle,
- it generates the above trivial implementations:
- .. code-block:: nim
- proc `*` (x: Dollar, y: int): Dollar {.borrow.}
- proc `*` (x: int, y: Dollar): Dollar {.borrow.}
- proc `div` (x: Dollar, y: int): Dollar {.borrow.}
- The `borrow` pragma makes the compiler use the same implementation as
- the proc that deals with the distinct type's base type, so no code is
- generated.
- But it seems all this boilerplate code needs to be repeated for the `Euro`
- currency. This can be solved with templates_.
- .. code-block:: nim
- :test: "nim c $1"
- template additive(typ: typedesc) =
- proc `+` *(x, y: typ): typ {.borrow.}
- proc `-` *(x, y: typ): typ {.borrow.}
- # unary operators:
- proc `+` *(x: typ): typ {.borrow.}
- proc `-` *(x: typ): typ {.borrow.}
- template multiplicative(typ, base: typedesc) =
- proc `*` *(x: typ, y: base): typ {.borrow.}
- proc `*` *(x: base, y: typ): typ {.borrow.}
- proc `div` *(x: typ, y: base): typ {.borrow.}
- proc `mod` *(x: typ, y: base): typ {.borrow.}
- template comparable(typ: typedesc) =
- proc `<` * (x, y: typ): bool {.borrow.}
- proc `<=` * (x, y: typ): bool {.borrow.}
- proc `==` * (x, y: typ): bool {.borrow.}
- template defineCurrency(typ, base: untyped) =
- type
- typ* = distinct base
- additive(typ)
- multiplicative(typ, base)
- comparable(typ)
- defineCurrency(Dollar, int)
- defineCurrency(Euro, int)
- The borrow pragma can also be used to annotate the distinct type to allow
- certain builtin operations to be lifted:
- .. code-block:: nim
- type
- Foo = object
- a, b: int
- s: string
- Bar {.borrow: `.`.} = distinct Foo
- var bb: ref Bar
- new bb
- # field access now valid
- bb.a = 90
- bb.s = "abc"
- Currently, only the dot accessor can be borrowed in this way.
- Avoiding SQL injection attacks
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- An SQL statement that is passed from Nim to an SQL database might be
- modeled as a string. However, using string templates and filling in the
- values is vulnerable to the famous `SQL injection attack`:idx:\:
- .. code-block:: nim
- import std/strutils
- proc query(db: DbHandle, statement: string) = ...
- var
- username: string
- db.query("SELECT FROM users WHERE name = '$1'" % username)
- # Horrible security hole, but the compiler does not mind!
- This can be avoided by distinguishing strings that contain SQL from strings
- that don't. Distinct types provide a means to introduce a new string type
- `SQL` that is incompatible with `string`:
- .. code-block:: nim
- type
- SQL = distinct string
- proc query(db: DbHandle, statement: SQL) = ...
- var
- username: string
- db.query("SELECT FROM users WHERE name = '$1'" % username)
- # Static error: `query` expects an SQL string!
- It is an essential property of abstract types that they **do not** imply a
- subtype relation between the abstract type and its base type. Explicit type
- conversions from `string` to `SQL` are allowed:
- .. code-block:: nim
- import std/[strutils, sequtils]
- proc properQuote(s: string): SQL =
- # quotes a string properly for an SQL statement
- return SQL(s)
- proc `%` (frmt: SQL, values: openarray[string]): SQL =
- # quote each argument:
- let v = values.mapIt(properQuote(it))
- # we need a temporary type for the type conversion :-(
- type StrSeq = seq[string]
- # call strutils.`%`:
- result = SQL(string(frmt) % StrSeq(v))
- db.query("SELECT FROM users WHERE name = '$1'".SQL % [username])
- Now we have compile-time checking against SQL injection attacks. Since
- `"".SQL` is transformed to `SQL("")` no new syntax is needed for nice
- looking `SQL` string literals. The hypothetical `SQL` type actually
- exists in the library as the `SqlQuery type <db_common.html#SqlQuery>`_ of
- modules like `db_sqlite <db_sqlite.html>`_.
- Auto type
- ---------
- The `auto` type can only be used for return types and parameters. For return
- types it causes the compiler to infer the type from the routine body:
- .. code-block:: nim
- proc returnsInt(): auto = 1984
- For parameters it currently creates implicitly generic routines:
- .. code-block:: nim
- proc foo(a, b: auto) = discard
- Is the same as:
- .. code-block:: nim
- proc foo[T1, T2](a: T1, b: T2) = discard
- However, later versions of the language might change this to mean "infer the
- parameters' types from the body". Then the above `foo` would be rejected as
- the parameters' types can not be inferred from an empty `discard` statement.
- Type relations
- ==============
- The following section defines several relations on types that are needed to
- describe the type checking done by the compiler.
- Type equality
- -------------
- Nim uses structural type equivalence for most types. Only for objects,
- enumerations and distinct types name equivalence is used. The following
- algorithm, *in pseudo-code*, determines type equality:
- .. code-block:: nim
- proc typeEqualsAux(a, b: PType,
- s: var HashSet[(PType, PType)]): bool =
- if (a,b) in s: return true
- incl(s, (a,b))
- if a.kind == b.kind:
- case a.kind
- of int, intXX, float, floatXX, char, string, cstring, pointer,
- bool, nil, void:
- # leaf type: kinds identical; nothing more to check
- result = true
- of ref, ptr, var, set, seq, openarray:
- result = typeEqualsAux(a.baseType, b.baseType, s)
- of range:
- result = typeEqualsAux(a.baseType, b.baseType, s) and
- (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB)
- of array:
- result = typeEqualsAux(a.baseType, b.baseType, s) and
- typeEqualsAux(a.indexType, b.indexType, s)
- of tuple:
- if a.tupleLen == b.tupleLen:
- for i in 0..a.tupleLen-1:
- if not typeEqualsAux(a[i], b[i], s): return false
- result = true
- of object, enum, distinct:
- result = a == b
- of proc:
- result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and
- typeEqualsAux(a.resultType, b.resultType, s) and
- a.callingConvention == b.callingConvention
- proc typeEquals(a, b: PType): bool =
- var s: HashSet[(PType, PType)] = {}
- result = typeEqualsAux(a, b, s)
- Since types are graphs which can have cycles, the above algorithm needs an
- auxiliary set `s` to detect this case.
- Type equality modulo type distinction
- -------------------------------------
- The following algorithm (in pseudo-code) determines whether two types
- are equal with no respect to `distinct` types. For brevity the cycle check
- with an auxiliary set `s` is omitted:
- .. code-block:: nim
- proc typeEqualsOrDistinct(a, b: PType): bool =
- if a.kind == b.kind:
- case a.kind
- of int, intXX, float, floatXX, char, string, cstring, pointer,
- bool, nil, void:
- # leaf type: kinds identical; nothing more to check
- result = true
- of ref, ptr, var, set, seq, openarray:
- result = typeEqualsOrDistinct(a.baseType, b.baseType)
- of range:
- result = typeEqualsOrDistinct(a.baseType, b.baseType) and
- (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB)
- of array:
- result = typeEqualsOrDistinct(a.baseType, b.baseType) and
- typeEqualsOrDistinct(a.indexType, b.indexType)
- of tuple:
- if a.tupleLen == b.tupleLen:
- for i in 0..a.tupleLen-1:
- if not typeEqualsOrDistinct(a[i], b[i]): return false
- result = true
- of distinct:
- result = typeEqualsOrDistinct(a.baseType, b.baseType)
- of object, enum:
- result = a == b
- of proc:
- result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and
- typeEqualsOrDistinct(a.resultType, b.resultType) and
- a.callingConvention == b.callingConvention
- elif a.kind == distinct:
- result = typeEqualsOrDistinct(a.baseType, b)
- elif b.kind == distinct:
- result = typeEqualsOrDistinct(a, b.baseType)
- Subtype relation
- ----------------
- If object `a` inherits from `b`, `a` is a subtype of `b`. This subtype
- relation is extended to the types `var`, `ref`, `ptr`:
- .. code-block:: nim
- proc isSubtype(a, b: PType): bool =
- if a.kind == b.kind:
- case a.kind
- of object:
- var aa = a.baseType
- while aa != nil and aa != b: aa = aa.baseType
- result = aa == b
- of var, ref, ptr:
- result = isSubtype(a.baseType, b.baseType)
- .. XXX nil is a special value!
- Convertible relation
- --------------------
- A type `a` is **implicitly** convertible to type `b` iff the following
- algorithm returns true:
- .. code-block:: nim
- proc isImplicitlyConvertible(a, b: PType): bool =
- if isSubtype(a, b) or isCovariant(a, b):
- return true
- if isIntLiteral(a):
- return b in {int8, int16, int32, int64, int, uint, uint8, uint16,
- uint32, uint64, float32, float64}
- case a.kind
- of int: result = b in {int32, int64}
- of int8: result = b in {int16, int32, int64, int}
- of int16: result = b in {int32, int64, int}
- of int32: result = b in {int64, int}
- of uint: result = b in {uint32, uint64}
- of uint8: result = b in {uint16, uint32, uint64}
- of uint16: result = b in {uint32, uint64}
- of uint32: result = b in {uint64}
- of float32: result = b in {float64}
- of float64: result = b in {float32}
- of seq:
- result = b == openArray and typeEquals(a.baseType, b.baseType)
- of array:
- result = b == openArray and typeEquals(a.baseType, b.baseType)
- if a.baseType == char and a.indexType.rangeA == 0:
- result = b == cstring
- of cstring, ptr:
- result = b == pointer
- of string:
- result = b == cstring
- Implicit conversions are also performed for Nim's `range` type
- constructor.
- Let `a0`, `b0` of type `T`.
- Let `A = range[a0..b0]` be the argument's type, `F` the formal
- parameter's type. Then an implicit conversion from `A` to `F`
- exists if `a0 >= low(F) and b0 <= high(F)` and both `T` and `F`
- are signed integers or if both are unsigned integers.
- A type `a` is **explicitly** convertible to type `b` iff the following
- algorithm returns true:
- .. code-block:: nim
- proc isIntegralType(t: PType): bool =
- result = isOrdinal(t) or t.kind in {float, float32, float64}
- proc isExplicitlyConvertible(a, b: PType): bool =
- result = false
- if isImplicitlyConvertible(a, b): return true
- if typeEqualsOrDistinct(a, b): return true
- if isIntegralType(a) and isIntegralType(b): return true
- if isSubtype(a, b) or isSubtype(b, a): return true
- The convertible relation can be relaxed by a user-defined type
- `converter`:idx:.
- .. code-block:: nim
- converter toInt(x: char): int = result = ord(x)
- var
- x: int
- chr: char = 'a'
- # implicit conversion magic happens here
- x = chr
- echo x # => 97
- # one can use the explicit form too
- x = chr.toInt
- echo x # => 97
- The type conversion `T(a)` is an L-value if `a` is an L-value and
- `typeEqualsOrDistinct(T, typeof(a))` holds.
- Assignment compatibility
- ------------------------
- An expression `b` can be assigned to an expression `a` iff `a` is an
- `l-value` and `isImplicitlyConvertible(b.typ, a.typ)` holds.
- Overloading resolution
- ======================
- In a call `p(args)` the routine `p` that matches best is selected. If
- multiple routines match equally well, the ambiguity is reported during
- semantic analysis.
- Every arg in args needs to match. There are multiple different categories how an
- argument can match. Let `f` be the formal parameter's type and `a` the type
- of the argument.
- 1. Exact match: `a` and `f` are of the same type.
- 2. Literal match: `a` is an integer literal of value `v`
- and `f` is a signed or unsigned integer type and `v` is in `f`'s
- range. Or: `a` is a floating-point literal of value `v`
- and `f` is a floating-point type and `v` is in `f`'s
- range.
- 3. Generic match: `f` is a generic type and `a` matches, for
- instance `a` is `int` and `f` is a generic (constrained) parameter
- type (like in `[T]` or `[T: int|char]`.
- 4. Subrange or subtype match: `a` is a `range[T]` and `T`
- matches `f` exactly. Or: `a` is a subtype of `f`.
- 5. Integral conversion match: `a` is convertible to `f` and `f` and `a`
- is some integer or floating-point type.
- 6. Conversion match: `a` is convertible to `f`, possibly via a user
- defined `converter`.
- These matching categories have a priority: An exact match is better than a
- literal match and that is better than a generic match etc. In the following,
- `count(p, m)` counts the number of matches of the matching category `m`
- for the routine `p`.
- A routine `p` matches better than a routine `q` if the following
- algorithm returns true::
- for each matching category m in ["exact match", "literal match",
- "generic match", "subtype match",
- "integral match", "conversion match"]:
- if count(p, m) > count(q, m): return true
- elif count(p, m) == count(q, m):
- discard "continue with next category m"
- else:
- return false
- return "ambiguous"
- Some examples:
- .. code-block:: nim
- proc takesInt(x: int) = echo "int"
- proc takesInt[T](x: T) = echo "T"
- proc takesInt(x: int16) = echo "int16"
- takesInt(4) # "int"
- var x: int32
- takesInt(x) # "T"
- var y: int16
- takesInt(y) # "int16"
- var z: range[0..4] = 0
- takesInt(z) # "T"
- If this algorithm returns "ambiguous" further disambiguation is performed:
- If the argument `a` matches both the parameter type `f` of `p`
- and `g` of `q` via a subtyping relation, the inheritance depth is taken
- into account:
- .. code-block:: nim
- type
- A = object of RootObj
- B = object of A
- C = object of B
- proc p(obj: A) =
- echo "A"
- proc p(obj: B) =
- echo "B"
- var c = C()
- # not ambiguous, calls 'B', not 'A' since B is a subtype of A
- # but not vice versa:
- p(c)
- proc pp(obj: A, obj2: B) = echo "A B"
- proc pp(obj: B, obj2: A) = echo "B A"
- # but this is ambiguous:
- pp(c, c)
- Likewise, for generic matches, the most specialized generic type (that still
- matches) is preferred:
- .. code-block:: nim
- proc gen[T](x: ref ref T) = echo "ref ref T"
- proc gen[T](x: ref T) = echo "ref T"
- proc gen[T](x: T) = echo "T"
- var ri: ref int
- gen(ri) # "ref T"
- Overloading based on 'var T'
- --------------------------------------
- If the formal parameter `f` is of type `var T`
- in addition to the ordinary type checking,
- the argument is checked to be an `l-value`:idx:.
- `var T` matches better than just `T` then.
- .. code-block:: nim
- proc sayHi(x: int): string =
- # matches a non-var int
- result = $x
- proc sayHi(x: var int): string =
- # matches a var int
- result = $(x + 10)
- proc sayHello(x: int) =
- var m = x # a mutable version of x
- echo sayHi(x) # matches the non-var version of sayHi
- echo sayHi(m) # matches the var version of sayHi
- sayHello(3) # 3
- # 13
- Lazy type resolution for untyped
- --------------------------------
- **Note**: An `unresolved`:idx: expression is an expression for which no symbol
- lookups and no type checking have been performed.
- Since templates and macros that are not declared as `immediate` participate
- in overloading resolution, it's essential to have a way to pass unresolved
- expressions to a template or macro. This is what the meta-type `untyped`
- accomplishes:
- .. code-block:: nim
- template rem(x: untyped) = discard
- rem unresolvedExpression(undeclaredIdentifier)
- A parameter of type `untyped` always matches any argument (as long as there is
- any argument passed to it).
- But one has to watch out because other overloads might trigger the
- argument's resolution:
- .. code-block:: nim
- template rem(x: untyped) = discard
- proc rem[T](x: T) = discard
- # undeclared identifier: 'unresolvedExpression'
- rem unresolvedExpression(undeclaredIdentifier)
- `untyped` and `varargs[untyped]` are the only metatype that are lazy in this sense, the other
- metatypes `typed` and `typedesc` are not lazy.
- Varargs matching
- ----------------
- See `Varargs <#types-varargs>`_.
- iterable
- --------
- A called `iterator` yielding type `T` can be passed to a template or macro via
- a parameter typed as `untyped` (for unresolved expressions) or the type class
- `iterable` or `iterable[T]` (after type checking and overload resolution).
- .. code-block:: nim
- iterator iota(n: int): int =
- for i in 0..<n: yield i
- template toSeq2[T](a: iterable[T]): seq[T] =
- var ret: seq[T]
- assert a.typeof is T
- for ai in a: ret.add ai
- ret
- assert iota(3).toSeq2 == @[0, 1, 2]
- assert toSeq2(5..7) == @[5, 6, 7]
- assert not compiles(toSeq2(@[1,2])) # seq[int] is not an iterable
- assert toSeq2(items(@[1,2])) == @[1, 2] # but items(@[1,2]) is
- Statements and expressions
- ==========================
- Nim uses the common statement/expression paradigm: Statements do not
- produce a value in contrast to expressions. However, some expressions are
- statements.
- Statements are separated into `simple statements`:idx: and
- `complex statements`:idx:.
- Simple statements are statements that cannot contain other statements like
- assignments, calls, or the `return` statement; complex statements can
- contain other statements. To avoid the `dangling else problem`:idx:, complex
- statements always have to be indented. The details can be found in the grammar.
- Statement list expression
- -------------------------
- Statements can also occur in an expression context that looks
- like `(stmt1; stmt2; ...; ex)`. This is called
- a statement list expression or `(;)`. The type
- of `(stmt1; stmt2; ...; ex)` is the type of `ex`. All the other statements
- must be of type `void`. (One can use `discard` to produce a `void` type.)
- `(;)` does not introduce a new scope.
- Discard statement
- -----------------
- Example:
- .. code-block:: nim
- proc p(x, y: int): int =
- result = x + y
- discard p(3, 4) # discard the return value of `p`
- The `discard` statement evaluates its expression for side-effects and
- throws the expression's resulting value away, and should only be used
- when ignoring this value is known not to cause problems.
- Ignoring the return value of a procedure without using a discard statement is
- a static error.
- The return value can be ignored implicitly if the called proc/iterator has
- been declared with the `discardable`:idx: pragma:
- .. code-block:: nim
- proc p(x, y: int): int {.discardable.} =
- result = x + y
- p(3, 4) # now valid
- however the discardable pragma does not work on templates as templates substitute the AST in place. For example:
- .. code-block:: nim
- {.push discardable .}
- template example(): string = "https://nim-lang.org"
- {.pop.}
- example()
- This template will resolve into "https://nim-lang.org" which is a string literal and since {.discardable.} doesn't apply to literals, the compiler will error.
- An empty `discard` statement is often used as a null statement:
- .. code-block:: nim
- proc classify(s: string) =
- case s[0]
- of SymChars, '_': echo "an identifier"
- of '0'..'9': echo "a number"
- else: discard
- Void context
- ------------
- In a list of statements, every expression except the last one needs to have the
- type `void`. In addition to this rule an assignment to the builtin `result`
- symbol also triggers a mandatory `void` context for the subsequent expressions:
- .. code-block:: nim
- proc invalid*(): string =
- result = "foo"
- "invalid" # Error: value of type 'string' has to be discarded
- .. code-block:: nim
- proc valid*(): string =
- let x = 317
- "valid"
- Var statement
- -------------
- Var statements declare new local and global variables and
- initialize them. A comma-separated list of variables can be used to specify
- variables of the same type:
- .. code-block:: nim
- var
- a: int = 0
- x, y, z: int
- If an initializer is given, the type can be omitted: the variable is then of the
- same type as the initializing expression. Variables are always initialized
- with a default value if there is no initializing expression. The default
- value depends on the type and is always a zero in binary.
- ============================ ==============================================
- Type default value
- ============================ ==============================================
- any integer type 0
- any float 0.0
- char '\\0'
- bool false
- ref or pointer type nil
- procedural type nil
- sequence `@[]`
- string `""`
- tuple[x: A, y: B, ...] (default(A), default(B), ...)
- (analogous for objects)
- array[0..., T] [default(T), ...]
- range[T] default(T); this may be out of the valid range
- T = enum cast[T]\(0); this may be an invalid value
- ============================ ==============================================
- The implicit initialization can be avoided for optimization reasons with the
- `noinit`:idx: pragma:
- .. code-block:: nim
- var
- a {.noInit.}: array[0..1023, char]
- If a proc is annotated with the `noinit` pragma, this refers to its implicit
- `result` variable:
- .. code-block:: nim
- proc returnUndefinedValue: int {.noinit.} = discard
- The implicit initialization can also be prevented by the `requiresInit`:idx:
- type pragma. The compiler requires an explicit initialization for the object
- and all of its fields. However, it does a `control flow analysis`:idx: to prove
- the variable has been initialized and does not rely on syntactic properties:
- .. code-block:: nim
- type
- MyObject = object {.requiresInit.}
- proc p() =
- # the following is valid:
- var x: MyObject
- if someCondition():
- x = a()
- else:
- x = a()
- # use x
- `requiresInit` pragma can also be applyied to `distinct` types.
- Given the following distinct type definitions:
- .. code-block:: nim
- type
- DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject
- DistinctString {.requiresInit.} = distinct string
- The following code blocks will fail to compile:
- .. code-block:: nim
- var foo: DistinctFoo
- foo.x = "test"
- doAssert foo.x == "test"
- .. code-block:: nim
- var s: DistinctString
- s = "test"
- doAssert s == "test"
- But these ones will compile successfully:
- .. code-block:: nim
- let foo = DistinctFoo(Foo(x: "test"))
- doAssert foo.x == "test"
- .. code-block:: nim
- let s = "test"
- doAssert s == "test"
- Let statement
- -------------
- A `let` statement declares new local and global `single assignment`:idx:
- variables and binds a value to them. The syntax is the same as that of the `var`
- statement, except that the keyword `var` is replaced by the keyword `let`.
- Let variables are not l-values and can thus not be passed to `var` parameters
- nor can their address be taken. They cannot be assigned new values.
- For let variables, the same pragmas are available as for ordinary variables.
- As `let` statements are immutable after creation they need to define a value
- when they are declared. The only exception to this is if the `{.importc.}`
- pragma (or any of the other `importX` pragmas) is applied, in this case the
- value is expected to come from native code, typically a C/C++ `const`.
- Tuple unpacking
- ---------------
- In a `var` or `let` statement tuple unpacking can be performed. The special
- identifier `_` can be used to ignore some parts of the tuple:
- .. code-block:: nim
- proc returnsTuple(): (int, int, int) = (4, 2, 3)
- let (x, _, z) = returnsTuple()
- Const section
- -------------
- A const section declares constants whose values are constant expressions:
- .. code-block::
- import std/[strutils]
- const
- roundPi = 3.1415
- constEval = contains("abc", 'b') # computed at compile time!
- Once declared, a constant's symbol can be used as a constant expression.
- See `Constants and Constant Expressions <#constants-and-constant-expressions>`_
- for details.
- Static statement/expression
- ---------------------------
- A static statement/expression explicitly requires compile-time execution.
- Even some code that has side effects is permitted in a static block:
- .. code-block::
- static:
- echo "echo at compile time"
- There are limitations on what Nim code can be executed at compile time;
- see `Restrictions on Compile-Time Execution
- <#restrictions-on-compileminustime-execution>`_ for details.
- It's a static error if the compiler cannot execute the block at compile
- time.
- If statement
- ------------
- Example:
- .. code-block:: nim
- var name = readLine(stdin)
- if name == "Andreas":
- echo "What a nice name!"
- elif name == "":
- echo "Don't you have a name?"
- else:
- echo "Boring name..."
- The `if` statement is a simple way to make a branch in the control flow:
- The expression after the keyword `if` is evaluated, if it is true
- the corresponding statements after the `:` are executed. Otherwise
- the expression after the `elif` is evaluated (if there is an
- `elif` branch), if it is true the corresponding statements after
- the `:` are executed. This goes on until the last `elif`. If all
- conditions fail, the `else` part is executed. If there is no `else`
- part, execution continues with the next statement.
- In `if` statements, new scopes begin immediately after
- the `if`/`elif`/`else` keywords and ends after the
- corresponding *then* block.
- For visualization purposes the scopes have been enclosed
- in `{| |}` in the following example:
- .. code-block:: nim
- if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch):
- echo "key ", m[0], " value ", m[1] |}
- elif {| (let m = input =~ re""; m.isMatch):
- echo "new m in this scope" |}
- else: {|
- echo "m not declared here" |}
- Case statement
- --------------
- Example:
- .. code-block:: nim
- case readline(stdin)
- of "delete-everything", "restart-computer":
- echo "permission denied"
- of "go-for-a-walk": echo "please yourself"
- else: echo "unknown command"
- # indentation of the branches is also allowed; and so is an optional colon
- # after the selecting expression:
- case readline(stdin):
- of "delete-everything", "restart-computer":
- echo "permission denied"
- of "go-for-a-walk": echo "please yourself"
- else: echo "unknown command"
- The `case` statement is similar to the if statement, but it represents
- a multi-branch selection. The expression after the keyword `case` is
- evaluated and if its value is in a *slicelist* the corresponding statements
- (after the `of` keyword) are executed. If the value is not in any
- given *slicelist* the `else` part is executed. If there is no `else`
- part and not all possible values that `expr` can hold occur in a
- *slicelist*, a static error occurs. This holds only for expressions of
- ordinal types. "All possible values" of `expr` are determined by `expr`'s
- type. To suppress the static error an `else` part with an
- empty `discard` statement should be used.
- For non-ordinal types, it is not possible to list every possible value and so
- these always require an `else` part.
- Because case statements are checked for exhaustiveness during semantic analysis,
- the value in every `of` branch must be a constant expression.
- This restriction also allows the compiler to generate more performant code.
- As a special semantic extension, an expression in an `of` branch of a case
- statement may evaluate to a set or array constructor; the set or array is then
- expanded into a list of its elements:
- .. code-block:: nim
- const
- SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
- proc classify(s: string) =
- case s[0]
- of SymChars, '_': echo "an identifier"
- of '0'..'9': echo "a number"
- else: echo "other"
- # is equivalent to:
- proc classify(s: string) =
- case s[0]
- of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': echo "an identifier"
- of '0'..'9': echo "a number"
- else: echo "other"
- The `case` statement doesn't produce an l-value, so the following example
- won't work:
- .. code-block:: nim
- type
- Foo = ref object
- x: seq[string]
- proc get_x(x: Foo): var seq[string] =
- # doesn't work
- case true
- of true:
- x.x
- else:
- x.x
- var foo = Foo(x: @[])
- foo.get_x().add("asd")
- This can be fixed by explicitly using `return`:
- .. code-block:: nim
- proc get_x(x: Foo): var seq[string] =
- case true
- of true:
- return x.x
- else:
- return x.x
- When statement
- --------------
- Example:
- .. code-block:: nim
- when sizeof(int) == 2:
- echo "running on a 16 bit system!"
- elif sizeof(int) == 4:
- echo "running on a 32 bit system!"
- elif sizeof(int) == 8:
- echo "running on a 64 bit system!"
- else:
- echo "cannot happen!"
- The `when` statement is almost identical to the `if` statement with some
- exceptions:
- * Each condition (`expr`) has to be a constant expression (of type `bool`).
- * The statements do not open a new scope.
- * The statements that belong to the expression that evaluated to true are
- translated by the compiler, the other statements are not checked for
- semantics! However, each condition is checked for semantics.
- The `when` statement enables conditional compilation techniques. As
- a special syntactic extension, the `when` construct is also available
- within `object` definitions.
- When nimvm statement
- --------------------
- `nimvm` is a special symbol that may be used as the expression of a
- `when nimvm` statement to differentiate the execution path between
- compile-time and the executable.
- Example:
- .. code-block:: nim
- proc someProcThatMayRunInCompileTime(): bool =
- when nimvm:
- # This branch is taken at compile time.
- result = true
- else:
- # This branch is taken in the executable.
- result = false
- const ctValue = someProcThatMayRunInCompileTime()
- let rtValue = someProcThatMayRunInCompileTime()
- assert(ctValue == true)
- assert(rtValue == false)
- A `when nimvm` statement must meet the following requirements:
- * Its expression must always be `nimvm`. More complex expressions are not
- allowed.
- * It must not contain `elif` branches.
- * It must contain an `else` branch.
- * Code in branches must not affect semantics of the code that follows the
- `when nimvm` statement. E.g. it must not define symbols that are used in
- the following code.
- Return statement
- ----------------
- Example:
- .. code-block:: nim
- return 40+2
- The `return` statement ends the execution of the current procedure.
- It is only allowed in procedures. If there is an `expr`, this is syntactic
- sugar for:
- .. code-block:: nim
- result = expr
- return result
- `return` without an expression is a short notation for `return result` if
- the proc has a return type. The `result`:idx: variable is always the return
- value of the procedure. It is automatically declared by the compiler. As all
- variables, `result` is initialized to (binary) zero:
- .. code-block:: nim
- proc returnZero(): int =
- # implicitly returns 0
- Yield statement
- ---------------
- Example:
- .. code-block:: nim
- yield (1, 2, 3)
- The `yield` statement is used instead of the `return` statement in
- iterators. It is only valid in iterators. Execution is returned to the body
- of the for loop that called the iterator. Yield does not end the iteration
- process, but the execution is passed back to the iterator if the next iteration
- starts. See the section about iterators (`Iterators and the for statement`_)
- for further information.
- Block statement
- ---------------
- Example:
- .. code-block:: nim
- var found = false
- block myblock:
- for i in 0..3:
- for j in 0..3:
- if a[j][i] == 7:
- found = true
- break myblock # leave the block, in this case both for-loops
- echo found
- The block statement is a means to group statements to a (named) `block`.
- Inside the block, the `break` statement is allowed to leave the block
- immediately. A `break` statement can contain a name of a surrounding
- block to specify which block is to be left.
- Break statement
- ---------------
- Example:
- .. code-block:: nim
- break
- The `break` statement is used to leave a block immediately. If `symbol`
- is given, it is the name of the enclosing block that is to be left. If it is
- absent, the innermost block is left.
- While statement
- ---------------
- Example:
- .. code-block:: nim
- echo "Please tell me your password:"
- var pw = readLine(stdin)
- while pw != "12345":
- echo "Wrong password! Next try:"
- pw = readLine(stdin)
- The `while` statement is executed until the `expr` evaluates to false.
- Endless loops are no error. `while` statements open an `implicit block`
- so that they can be left with a `break` statement.
- Continue statement
- ------------------
- A `continue` statement leads to the immediate next iteration of the
- surrounding loop construct. It is only allowed within a loop. A continue
- statement is syntactic sugar for a nested block:
- .. code-block:: nim
- while expr1:
- stmt1
- continue
- stmt2
- Is equivalent to:
- .. code-block:: nim
- while expr1:
- block myBlockName:
- stmt1
- break myBlockName
- stmt2
- Assembler statement
- -------------------
- The direct embedding of assembler code into Nim code is supported
- by the unsafe `asm` statement. Identifiers in the assembler code that refer to
- Nim identifiers shall be enclosed in a special character which can be
- specified in the statement's pragmas. The default special character is `'\`'`:
- .. code-block:: nim
- {.push stackTrace:off.}
- proc addInt(a, b: int): int =
- # a in eax, and b in edx
- asm """
- mov eax, `a`
- add eax, `b`
- jno theEnd
- call `raiseOverflow`
- theEnd:
- """
- {.pop.}
- If the GNU assembler is used, quotes and newlines are inserted automatically:
- .. code-block:: nim
- proc addInt(a, b: int): int =
- asm """
- addl %%ecx, %%eax
- jno 1
- call `raiseOverflow`
- 1:
- :"=a"(`result`)
- :"a"(`a`), "c"(`b`)
- """
- Instead of:
- .. code-block:: nim
- proc addInt(a, b: int): int =
- asm """
- "addl %%ecx, %%eax\n"
- "jno 1\n"
- "call `raiseOverflow`\n"
- "1: \n"
- :"=a"(`result`)
- :"a"(`a`), "c"(`b`)
- """
- Using statement
- ---------------
- The `using` statement provides syntactic convenience in modules where
- the same parameter names and types are used over and over. Instead of:
- .. code-block:: nim
- proc foo(c: Context; n: Node) = ...
- proc bar(c: Context; n: Node, counter: int) = ...
- proc baz(c: Context; n: Node) = ...
- One can tell the compiler about the convention that a parameter of
- name `c` should default to type `Context`, `n` should default to
- `Node` etc.:
- .. code-block:: nim
- using
- c: Context
- n: Node
- counter: int
- proc foo(c, n) = ...
- proc bar(c, n, counter) = ...
- proc baz(c, n) = ...
- proc mixedMode(c, n; x, y: int) =
- # 'c' is inferred to be of the type 'Context'
- # 'n' is inferred to be of the type 'Node'
- # But 'x' and 'y' are of type 'int'.
- The `using` section uses the same indentation based grouping syntax as
- a `var` or `let` section.
- Note that `using` is not applied for `template` since the untyped template
- parameters default to the type `system.untyped`.
- Mixing parameters that should use the `using` declaration with parameters
- that are explicitly typed is possible and requires a semicolon between them.
- If expression
- -------------
- An `if` expression is almost like an if statement, but it is an expression.
- This feature is similar to *ternary operators* in other languages.
- Example:
- .. code-block:: nim
- var y = if x > 8: 9 else: 10
- An if expression always results in a value, so the `else` part is
- required. `Elif` parts are also allowed.
- When expression
- ---------------
- Just like an `if` expression, but corresponding to the `when` statement.
- Case expression
- ---------------
- The `case` expression is again very similar to the case statement:
- .. code-block:: nim
- var favoriteFood = case animal
- of "dog": "bones"
- of "cat": "mice"
- elif animal.endsWith"whale": "plankton"
- else:
- echo "I'm not sure what to serve, but everybody loves ice cream"
- "ice cream"
- As seen in the above example, the case expression can also introduce side
- effects. When multiple statements are given for a branch, Nim will use
- the last expression as the result value.
- Block expression
- ----------------
- A `block` expression is almost like a block statement, but it is an expression
- that uses the last expression under the block as the value.
- It is similar to the statement list expression, but the statement list expression
- does not open a new block scope.
- .. code-block:: nim
- let a = block:
- var fib = @[0, 1]
- for i in 0..10:
- fib.add fib[^1] + fib[^2]
- fib
- Table constructor
- -----------------
- A table constructor is syntactic sugar for an array constructor:
- .. code-block:: nim
- {"key1": "value1", "key2", "key3": "value2"}
- # is the same as:
- [("key1", "value1"), ("key2", "value2"), ("key3", "value2")]
- The empty table can be written `{:}` (in contrast to the empty set
- which is `{}`) which is thus another way to write the empty array
- constructor `[]`. This slightly unusual way of supporting tables
- has lots of advantages:
- * The order of the (key,value)-pairs is preserved, thus it is easy to
- support ordered dicts with for example `{key: val}.newOrderedTable`.
- * A table literal can be put into a `const` section and the compiler
- can easily put it into the executable's data section just like it can
- for arrays and the generated data section requires a minimal amount
- of memory.
- * Every table implementation is treated equally syntactically.
- * Apart from the minimal syntactic sugar, the language core does not need to
- know about tables.
- Type conversions
- ----------------
- Syntactically a *type conversion* is like a procedure call, but a
- type name replaces the procedure name. A type conversion is always
- safe in the sense that a failure to convert a type to another
- results in an exception (if it cannot be determined statically).
- Ordinary procs are often preferred over type conversions in Nim: For instance,
- `$` is the `toString` operator by convention and `toFloat` and `toInt`
- can be used to convert from floating-point to integer or vice versa.
- Type conversion can also be used to disambiguate overloaded routines:
- .. code-block:: nim
- proc p(x: int) = echo "int"
- proc p(x: string) = echo "string"
- let procVar = (proc(x: string))(p)
- procVar("a")
- Since operations on unsigned numbers wrap around and are unchecked so are
- type conversions to unsigned integers and between unsigned integers. The
- rationale for this is mostly better interoperability with the C Programming
- language when algorithms are ported from C to Nim.
- Exception: Values that are converted to an unsigned type at compile time
- are checked so that code like `byte(-1)` does not compile.
- **Note**: Historically the operations
- were unchecked and the conversions were sometimes checked but starting with
- the revision 1.0.4 of this document and the language implementation the
- conversions too are now *always unchecked*.
- Type casts
- ----------
- *Type casts* are a crude mechanism to interpret the bit pattern of an expression
- as if it would be of another type. Type casts are only needed for low-level
- programming and are inherently unsafe.
- .. code-block:: nim
- cast[int](x)
- The target type of a cast must be a concrete type, for instance, a target type
- that is a type class (which is non-concrete) would be invalid:
- .. code-block:: nim
- type Foo = int or float
- var x = cast[Foo](1) # Error: cannot cast to a non concrete type: 'Foo'
- Type casts should not be confused with *type conversions,* as mentioned in the
- prior section. Unlike type conversions, a type cast cannot change the underlying
- bit pattern of the data being casted (aside from that the size of the target type
- may differ from the source type). Casting resembles *type punning* in other
- languages or C++'s `reinterpret_cast`:cpp: and `bit_cast`:cpp: features.
- The addr operator
- -----------------
- The `addr` operator returns the address of an l-value. If the type of the
- location is `T`, the `addr` operator result is of the type `ptr T`. An
- address is always an untraced reference. Taking the address of an object that
- resides on the stack is **unsafe**, as the pointer may live longer than the
- object on the stack and can thus reference a non-existing object. One can get
- the address of variables, but one can't use it on variables declared through
- `let` statements:
- .. code-block:: nim
- let t1 = "Hello"
- var
- t2 = t1
- t3 : pointer = addr(t2)
- echo repr(addr(t2))
- # --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello"
- echo cast[ptr string](t3)[]
- # --> Hello
- # The following line doesn't compile:
- echo repr(addr(t1))
- # Error: expression has no address
- The unsafeAddr operator
- -----------------------
- For easier interoperability with other compiled languages such as C, retrieving
- the address of a `let` variable, a parameter, or a `for` loop variable can
- be accomplished by using the `unsafeAddr` operation:
- .. code-block:: nim
- let myArray = [1, 2, 3]
- foreignProcThatTakesAnAddr(unsafeAddr myArray)
- Procedures
- ==========
- What most programming languages call `methods`:idx: or `functions`:idx: are
- called `procedures`:idx: in Nim. A procedure
- declaration consists of an identifier, zero or more formal parameters, a return
- value type and a block of code. Formal parameters are declared as a list of
- identifiers separated by either comma or semicolon. A parameter is given a type
- by `: typename`. The type applies to all parameters immediately before it,
- until either the beginning of the parameter list, a semicolon separator, or an
- already typed parameter, is reached. The semicolon can be used to make
- separation of types and subsequent identifiers more distinct.
- .. code-block:: nim
- # Using only commas
- proc foo(a, b: int, c, d: bool): int
- # Using semicolon for visual distinction
- proc foo(a, b: int; c, d: bool): int
- # Will fail: a is untyped since ';' stops type propagation.
- proc foo(a; b: int; c, d: bool): int
- A parameter may be declared with a default value which is used if the caller
- does not provide a value for the argument.
- .. code-block:: nim
- # b is optional with 47 as its default value
- proc foo(a: int, b: int = 47): int
- Parameters can be declared mutable and so allow the proc to modify those
- arguments, by using the type modifier `var`.
- .. code-block:: nim
- # "returning" a value to the caller through the 2nd argument
- # Notice that the function uses no actual return value at all (ie void)
- proc foo(inp: int, outp: var int) =
- outp = inp + 47
- If the proc declaration has no body, it is a `forward`:idx: declaration. If the
- proc returns a value, the procedure body can access an implicitly declared
- variable named `result`:idx: that represents the return value. Procs can be
- overloaded. The overloading resolution algorithm determines which proc is the
- best match for the arguments. Example:
- .. code-block:: nim
- proc toLower(c: char): char = # toLower for characters
- if c in {'A'..'Z'}:
- result = chr(ord(c) + (ord('a') - ord('A')))
- else:
- result = c
- proc toLower(s: string): string = # toLower for strings
- result = newString(len(s))
- for i in 0..len(s) - 1:
- result[i] = toLower(s[i]) # calls toLower for characters; no recursion!
- Calling a procedure can be done in many different ways:
- .. code-block:: nim
- proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ...
- # call with positional arguments # parameter bindings:
- callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true)
- # call with named and positional arguments:
- callme(y=1, x=0, "abd", '\t') # (x=0, y=1, s="abd", c='\t', b=false)
- # call with named arguments (order is not relevant):
- callme(c='\t', y=1, x=0) # (x=0, y=1, s="", c='\t', b=false)
- # call as a command statement: no () needed:
- callme 0, 1, "abc", '\t' # (x=0, y=1, s="abc", c='\t', b=false)
- A procedure may call itself recursively.
- `Operators`:idx: are procedures with a special operator symbol as identifier:
- .. code-block:: nim
- proc `$` (x: int): string =
- # converts an integer to a string; this is a prefix operator.
- result = intToStr(x)
- Operators with one parameter are prefix operators, operators with two
- parameters are infix operators. (However, the parser distinguishes these from
- the operator's position within an expression.) There is no way to declare
- postfix operators: all postfix operators are built-in and handled by the
- grammar explicitly.
- Any operator can be called like an ordinary proc with the \`opr\`
- notation. (Thus an operator can have more than two parameters):
- .. code-block:: nim
- proc `*+` (a, b, c: int): int =
- # Multiply and add
- result = a * b + c
- assert `*+`(3, 4, 6) == `+`(`*`(a, b), c)
- Export marker
- -------------
- If a declared symbol is marked with an `asterisk`:idx: it is exported from the
- current module:
- .. code-block:: nim
- proc exportedEcho*(s: string) = echo s
- proc `*`*(a: string; b: int): string =
- result = newStringOfCap(a.len * b)
- for i in 1..b: result.add a
- var exportedVar*: int
- const exportedConst* = 78
- type
- ExportedType* = object
- exportedField*: int
- Method call syntax
- ------------------
- For object-oriented programming, the syntax `obj.methodName(args)` can be used
- instead of `methodName(obj, args)`. The parentheses can be omitted if
- there are no remaining arguments: `obj.len` (instead of `len(obj)`).
- This method call syntax is not restricted to objects, it can be used
- to supply any type of first argument for procedures:
- .. code-block:: nim
- echo "abc".len # is the same as echo len "abc"
- echo "abc".toUpper()
- echo {'a', 'b', 'c'}.card
- stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
- Another way to look at the method call syntax is that it provides the missing
- postfix notation.
- The method call syntax conflicts with explicit generic instantiations:
- `p[T](x)` cannot be written as `x.p[T]` because `x.p[T]` is always
- parsed as `(x.p)[T]`.
- See also: `Limitations of the method call syntax
- <#templates-limitations-of-the-method-call-syntax>`_.
- The `[: ]` notation has been designed to mitigate this issue: `x.p[:T]`
- is rewritten by the parser to `p[T](x)`, `x.p[:T](y)` is rewritten to
- `p[T](x, y)`. Note that `[: ]` has no AST representation, the rewrite
- is performed directly in the parsing step.
- Properties
- ----------
- Nim has no need for *get-properties*: Ordinary get-procedures that are called
- with the *method call syntax* achieve the same. But setting a value is
- different; for this, a special setter syntax is needed:
- .. code-block:: nim
- # Module asocket
- type
- Socket* = ref object of RootObj
- host: int # cannot be accessed from the outside of the module
- proc `host=`*(s: var Socket, value: int) {.inline.} =
- ## setter of hostAddr.
- ## This accesses the 'host' field and is not a recursive call to
- ## `host=` because the builtin dot access is preferred if it is
- ## available:
- s.host = value
- proc host*(s: Socket): int {.inline.} =
- ## getter of hostAddr
- ## This accesses the 'host' field and is not a recursive call to
- ## `host` because the builtin dot access is preferred if it is
- ## available:
- s.host
- .. code-block:: nim
- # module B
- import asocket
- var s: Socket
- new s
- s.host = 34 # same as `host=`(s, 34)
- A proc defined as `f=` (with the trailing `=`) is called
- a `setter`:idx:. A setter can be called explicitly via the common
- backticks notation:
- .. code-block:: nim
- proc `f=`(x: MyObject; value: string) =
- discard
- `f=`(myObject, "value")
- `f=` can be called implicitly in the pattern
- `x.f = value` if and only if the type of `x` does not have a field
- named `f` or if `f` is not visible in the current module. These rules
- ensure that object fields and accessors can have the same name. Within the
- module `x.f` is then always interpreted as field access and outside the
- module it is interpreted as an accessor proc call.
- Command invocation syntax
- -------------------------
- Routines can be invoked without the `()` if the call is syntactically
- a statement. This command invocation syntax also works for
- expressions, but then only a single argument may follow. This restriction
- means `echo f 1, f 2` is parsed as `echo(f(1), f(2))` and not as
- `echo(f(1, f(2)))`. The method call syntax may be used to provide one
- more argument in this case:
- .. code-block:: nim
- proc optarg(x: int, y: int = 0): int = x + y
- proc singlearg(x: int): int = 20*x
- echo optarg 1, " ", singlearg 2 # prints "1 40"
- let fail = optarg 1, optarg 8 # Wrong. Too many arguments for a command call
- let x = optarg(1, optarg 8) # traditional procedure call with 2 arguments
- let y = 1.optarg optarg 8 # same thing as above, w/o the parenthesis
- assert x == y
- The command invocation syntax also can't have complex expressions as arguments.
- For example: (`anonymous procs <#procedures-anonymous-procs>`_), `if`,
- `case` or `try`. Function calls with no arguments still need () to
- distinguish between a call and the function itself as a first-class value.
- Closures
- --------
- Procedures can appear at the top level in a module as well as inside other
- scopes, in which case they are called nested procs. A nested proc can access
- local variables from its enclosing scope and if it does so it becomes a
- closure. Any captured variables are stored in a hidden additional argument
- to the closure (its environment) and they are accessed by reference by both
- the closure and its enclosing scope (i.e. any modifications made to them are
- visible in both places). The closure environment may be allocated on the heap
- or on the stack if the compiler determines that this would be safe.
- Creating closures in loops
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Since closures capture local variables by reference it is often not wanted
- behavior inside loop bodies. See `closureScope
- <system.html#closureScope.t,untyped>`_ and `capture
- <sugar.html#capture.m,varargs[typed],untyped>`_ for details on how to change this behavior.
- Anonymous Procs
- ---------------
- Unnamed procedures can be used as lambda expressions to pass into other
- procedures:
- .. code-block:: nim
- var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"]
- cities.sort(proc (x,y: string): int =
- cmp(x.len, y.len))
- Procs as expressions can appear both as nested procs and inside top-level
- executable code. The `sugar <sugar.html>`_ module contains the `=>` macro
- which enables a more succinct syntax for anonymous procedures resembling
- lambdas as they are in languages like JavaScript, C#, etc.
- Func
- ----
- The `func` keyword introduces a shortcut for a `noSideEffect`:idx: proc.
- .. code-block:: nim
- func binarySearch[T](a: openArray[T]; elem: T): int
- Is short for:
- .. code-block:: nim
- proc binarySearch[T](a: openArray[T]; elem: T): int {.noSideEffect.}
- Routines
- --------
- A routine is a symbol of kind: `proc`, `func`, `method`, `iterator`, `macro`, `template`, `converter`.
- Type bound operators
- --------------------
- A type bound operator is a `proc` or `func` whose name starts with `=` but isn't an operator
- (i.e. containing only symbols, such as `==`). These are unrelated to setters
- (see `properties <manual.html#procedures-properties>`_), which instead end in `=`.
- A type bound operator declared for a type applies to the type regardless of whether
- the operator is in scope (including if it is private).
- .. code-block:: nim
- # foo.nim:
- var witness* = 0
- type Foo[T] = object
- proc initFoo*(T: typedesc): Foo[T] = discard
- proc `=destroy`[T](x: var Foo[T]) = witness.inc # type bound operator
- # main.nim:
- import foo
- block:
- var a = initFoo(int)
- doAssert witness == 0
- doAssert witness == 1
- block:
- var a = initFoo(int)
- doAssert witness == 1
- `=destroy`(a) # can be called explicitly, even without being in scope
- doAssert witness == 2
- # will still be called upon exiting scope
- doAssert witness == 3
- Type bound operators currently include:
- `=destroy`, `=copy`, `=sink`, `=trace`, `=dispose`, `=deepcopy`
- (some of which are still implementation defined and not yet documented).
- For more details on some of those procs, see
- `lifetimeminustracking-hooks <destructors.html#lifetimeminustracking-hooks>`_.
- Nonoverloadable builtins
- ------------------------
- The following built-in procs cannot be overloaded for reasons of implementation
- simplicity (they require specialized semantic checking)::
- declared, defined, definedInScope, compiles, sizeof,
- is, shallowCopy, getAst, astToStr, spawn, procCall
- Thus they act more like keywords than like ordinary identifiers; unlike a
- keyword however, a redefinition may `shadow`:idx: the definition in
- the system_ module. From this list the following should not be written in dot
- notation `x.f` since `x` cannot be type-checked before it gets passed
- to `f`::
- declared, defined, definedInScope, compiles, getAst, astToStr
- Var parameters
- --------------
- The type of a parameter may be prefixed with the `var` keyword:
- .. code-block:: nim
- proc divmod(a, b: int; res, remainder: var int) =
- res = a div b
- remainder = a mod b
- var
- x, y: int
- divmod(8, 5, x, y) # modifies x and y
- assert x == 1
- assert y == 3
- In the example, `res` and `remainder` are `var parameters`.
- Var parameters can be modified by the procedure and the changes are
- visible to the caller. The argument passed to a var parameter has to be
- an l-value. Var parameters are implemented as hidden pointers. The
- above example is equivalent to:
- .. code-block:: nim
- proc divmod(a, b: int; res, remainder: ptr int) =
- res[] = a div b
- remainder[] = a mod b
- var
- x, y: int
- divmod(8, 5, addr(x), addr(y))
- assert x == 1
- assert y == 3
- In the examples, var parameters or pointers are used to provide two
- return values. This can be done in a cleaner way by returning a tuple:
- .. code-block:: nim
- proc divmod(a, b: int): tuple[res, remainder: int] =
- (a div b, a mod b)
- var t = divmod(8, 5)
- assert t.res == 1
- assert t.remainder == 3
- One can use `tuple unpacking`:idx: to access the tuple's fields:
- .. code-block:: nim
- var (x, y) = divmod(8, 5) # tuple unpacking
- assert x == 1
- assert y == 3
- **Note**: `var` parameters are never necessary for efficient parameter
- passing. Since non-var parameters cannot be modified the compiler is always
- free to pass arguments by reference if it considers it can speed up execution.
- Var return type
- ---------------
- A proc, converter, or iterator may return a `var` type which means that the
- returned value is an l-value and can be modified by the caller:
- .. code-block:: nim
- var g = 0
- proc writeAccessToG(): var int =
- result = g
- writeAccessToG() = 6
- assert g == 6
- It is a static error if the implicitly introduced pointer could be
- used to access a location beyond its lifetime:
- .. code-block:: nim
- proc writeAccessToG(): var int =
- var g = 0
- result = g # Error!
- For iterators, a component of a tuple return type can have a `var` type too:
- .. code-block:: nim
- iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] =
- for i in 0..a.high:
- yield (i, a[i])
- In the standard library every name of a routine that returns a `var` type
- starts with the prefix `m` per convention.
- .. include:: manual/var_t_return.rst
- Future directions
- ~~~~~~~~~~~~~~~~~
- Later versions of Nim can be more precise about the borrowing rule with
- a syntax like:
- .. code-block:: nim
- proc foo(other: Y; container: var X): var T from container
- Here `var T from container` explicitly exposes that the
- location is derived from the second parameter (called
- 'container' in this case). The syntax `var T from p` specifies a type
- `varTy[T, 2]` which is incompatible with `varTy[T, 1]`.
- NRVO
- ----
- **Note**: This section describes the current implementation. This part
- of the language specification will be changed.
- See https://github.com/nim-lang/RFCs/issues/230 for more information.
- The return value is represented inside the body of a routine as the special
- `result`:idx: variable. This allows for a mechanism much like C++'s
- "named return value optimization" (`NRVO`:idx:). NRVO means that the stores
- to `result` inside `p` directly affect the destination `dest`
- in `let/var dest = p(args)` (definition of `dest`) and also in `dest = p(args)`
- (assignment to `dest`). This is achieved by rewriting `dest = p(args)`
- to `p'(args, dest)` where `p'` is a variation of `p` that returns `void` and
- receives a hidden mutable parameter representing `result`.
- Informally:
- .. code-block:: nim
- proc p(): BigT = ...
- var x = p()
- x = p()
- # is roughly turned into:
- proc p(result: var BigT) = ...
- var x; p(x)
- p(x)
- Let `T`'s be `p`'s return type. NRVO applies for `T`
- if `sizeof(T) >= N` (where `N` is implementation dependent),
- in other words, it applies for "big" structures.
- If `p` can raise an exception, NRVO applies regardless. This can produce
- observable differences in behavior:
- .. code-block:: nim
- type
- BigT = array[16, int]
- proc p(raiseAt: int): BigT =
- for i in 0..high(result):
- if i == raiseAt: raise newException(ValueError, "interception")
- result[i] = i
- proc main =
- var x: BigT
- try:
- x = p(8)
- except ValueError:
- doAssert x == [0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0]
- main()
- However, the current implementation produces a warning in these cases.
- There are different ways to deal with this warning:
- 1. Disable the warning via `{.push warning[ObservableStores]: off.}` ... `{.pop.}`.
- Then one may need to ensure that `p` only raises *before* any stores to `result`
- happen.
- 2. One can use a temporary helper variable, for example instead of `x = p(8)`
- use `let tmp = p(8); x = tmp`.
- Overloading of the subscript operator
- -------------------------------------
- The `[]` subscript operator for arrays/openarrays/sequences can be overloaded.
- Methods
- =============
- Procedures always use static dispatch. Methods use dynamic
- dispatch. For dynamic dispatch to work on an object it should be a reference
- type.
- .. code-block:: nim
- type
- Expression = ref object of RootObj ## abstract base class for an expression
- Literal = ref object of Expression
- x: int
- PlusExpr = ref object of Expression
- a, b: Expression
- method eval(e: Expression): int {.base.} =
- # override this base method
- raise newException(CatchableError, "Method without implementation override")
- method eval(e: Literal): int = return e.x
- method eval(e: PlusExpr): int =
- # watch out: relies on dynamic binding
- result = eval(e.a) + eval(e.b)
- proc newLit(x: int): Literal =
- new(result)
- result.x = x
- proc newPlus(a, b: Expression): PlusExpr =
- new(result)
- result.a = a
- result.b = b
- echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
- In the example the constructors `newLit` and `newPlus` are procs
- because they should use static binding, but `eval` is a method because it
- requires dynamic binding.
- As can be seen in the example, base methods have to be annotated with
- the `base`:idx: pragma. The `base` pragma also acts as a reminder for the
- programmer that a base method `m` is used as the foundation to determine all
- the effects that a call to `m` might cause.
- **Note**: Compile-time execution is not (yet) supported for methods.
- **Note**: Starting from Nim 0.20, generic methods are deprecated.
- Multi-methods
- --------------
- **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass
- ``--multimethods:on`` when compiling.
- In a multi-method, all parameters that have an object type are used for the
- dispatching:
- .. code-block:: nim
- :test: "nim c --multiMethods:on $1"
- type
- Thing = ref object of RootObj
- Unit = ref object of Thing
- x: int
- method collide(a, b: Thing) {.inline.} =
- quit "to override!"
- method collide(a: Thing, b: Unit) {.inline.} =
- echo "1"
- method collide(a: Unit, b: Thing) {.inline.} =
- echo "2"
- var a, b: Unit
- new a
- new b
- collide(a, b) # output: 2
- Inhibit dynamic method resolution via procCall
- -----------------------------------------------
- Dynamic method resolution can be inhibited via the builtin `system.procCall`:idx:.
- This is somewhat comparable to the `super`:idx: keyword that traditional OOP
- languages offer.
- .. code-block:: nim
- :test: "nim c $1"
- type
- Thing = ref object of RootObj
- Unit = ref object of Thing
- x: int
- method m(a: Thing) {.base.} =
- echo "base"
- method m(a: Unit) =
- # Call the base method:
- procCall m(Thing(a))
- echo "1"
- Iterators and the for statement
- ===============================
- The `for`:idx: statement is an abstract mechanism to iterate over the elements
- of a container. It relies on an `iterator`:idx: to do so. Like `while`
- statements, `for` statements open an `implicit block`:idx: so that they
- can be left with a `break` statement.
- The `for` loop declares iteration variables - their scope reaches until the
- end of the loop body. The iteration variables' types are inferred by the
- return type of the iterator.
- An iterator is similar to a procedure, except that it can be called in the
- context of a `for` loop. Iterators provide a way to specify the iteration over
- an abstract type. The `yield` statement in the called iterator plays a key
- role in the execution of a `for` loop. Whenever a `yield` statement is
- reached, the data is bound to the `for` loop variables and control continues
- in the body of the `for` loop. The iterator's local variables and execution
- state are automatically saved between calls. Example:
- .. code-block:: nim
- # this definition exists in the system module
- iterator items*(a: string): char {.inline.} =
- var i = 0
- while i < len(a):
- yield a[i]
- inc(i)
- for ch in items("hello world"): # `ch` is an iteration variable
- echo ch
- The compiler generates code as if the programmer would have written this:
- .. code-block:: nim
- var i = 0
- while i < len(a):
- var ch = a[i]
- echo ch
- inc(i)
- If the iterator yields a tuple, there can be as many iteration variables
- as there are components in the tuple. The i'th iteration variable's type is
- the type of the i'th component. In other words, implicit tuple unpacking in a
- for loop context is supported.
- Implicit items/pairs invocations
- --------------------------------
- If the for loop expression `e` does not denote an iterator and the for loop
- has exactly 1 variable, the for loop expression is rewritten to `items(e)`;
- ie. an `items` iterator is implicitly invoked:
- .. code-block:: nim
- for x in [1,2,3]: echo x
- If the for loop has exactly 2 variables, a `pairs` iterator is implicitly
- invoked.
- Symbol lookup of the identifiers `items`/`pairs` is performed after
- the rewriting step, so that all overloads of `items`/`pairs` are taken
- into account.
- First-class iterators
- ---------------------
- There are 2 kinds of iterators in Nim: *inline* and *closure* iterators.
- An `inline iterator`:idx: is an iterator that's always inlined by the compiler
- leading to zero overhead for the abstraction, but may result in a heavy
- increase in code size.
- Caution: the body of a for loop over an inline iterator is inlined into
- each `yield` statement appearing in the iterator code,
- so ideally the code should be refactored to contain a single yield when possible
- to avoid code bloat.
- Inline iterators are second class citizens;
- They can be passed as parameters only to other inlining code facilities like
- templates, macros, and other inline iterators.
- In contrast to that, a `closure iterator`:idx: can be passed around more freely:
- .. code-block:: nim
- iterator count0(): int {.closure.} =
- yield 0
- iterator count2(): int {.closure.} =
- var x = 1
- yield x
- inc x
- yield x
- proc invoke(iter: iterator(): int {.closure.}) =
- for x in iter(): echo x
- invoke(count0)
- invoke(count2)
- Closure iterators and inline iterators have some restrictions:
- 1. For now, a closure iterator cannot be executed at compile time.
- 2. `return` is allowed in a closure iterator but not in an inline iterator
- (but rarely useful) and ends the iteration.
- 3. Neither inline nor closure iterators can be (directly)* recursive.
- 4. Neither inline nor closure iterators have the special `result` variable.
- 5. Closure iterators are not supported by the JS backend.
- (*) Closure iterators can be co-recursive with a factory proc which results
- in similar syntax to a recursive iterator. More details follow.
- Iterators that are neither marked `{.closure.}` nor `{.inline.}` explicitly
- default to being inline, but this may change in future versions of the
- implementation.
- The `iterator` type is always of the calling convention `closure`
- implicitly; the following example shows how to use iterators to implement
- a `collaborative tasking`:idx: system:
- .. code-block:: nim
- # simple tasking:
- type
- Task = iterator (ticker: int)
- iterator a1(ticker: int) {.closure.} =
- echo "a1: A"
- yield
- echo "a1: B"
- yield
- echo "a1: C"
- yield
- echo "a1: D"
- iterator a2(ticker: int) {.closure.} =
- echo "a2: A"
- yield
- echo "a2: B"
- yield
- echo "a2: C"
- proc runTasks(t: varargs[Task]) =
- var ticker = 0
- while true:
- let x = t[ticker mod t.len]
- if finished(x): break
- x(ticker)
- inc ticker
- runTasks(a1, a2)
- The builtin `system.finished` can be used to determine if an iterator has
- finished its operation; no exception is raised on an attempt to invoke an
- iterator that has already finished its work.
- Note that `system.finished` is error prone to use because it only returns
- `true` one iteration after the iterator has finished:
- .. code-block:: nim
- iterator mycount(a, b: int): int {.closure.} =
- var x = a
- while x <= b:
- yield x
- inc x
- var c = mycount # instantiate the iterator
- while not finished(c):
- echo c(1, 3)
- # Produces
- 1
- 2
- 3
- 0
- Instead this code has to be used:
- .. code-block:: nim
- var c = mycount # instantiate the iterator
- while true:
- let value = c(1, 3)
- if finished(c): break # and discard 'value'!
- echo value
- It helps to think that the iterator actually returns a
- pair `(value, done)` and `finished` is used to access the hidden `done`
- field.
- Closure iterators are *resumable functions* and so one has to provide the
- arguments to every call. To get around this limitation one can capture
- parameters of an outer factory proc:
- .. code-block:: nim
- proc mycount(a, b: int): iterator (): int =
- result = iterator (): int =
- var x = a
- while x <= b:
- yield x
- inc x
- let foo = mycount(1, 4)
- for f in foo():
- echo f
- The call can be made more like an inline iterator with a for loop macro:
- .. code-block:: nim
- import std/macros
- macro toItr(x: ForLoopStmt): untyped =
- let expr = x[0]
- let call = x[1][1] # Get foo out of toItr(foo)
- let body = x[2]
- result = quote do:
- block:
- let itr = `call`
- for `expr` in itr():
- `body`
- for f in toItr(mycount(1, 4)): # using early `proc mycount`
- echo f
- Because of full backend function call aparatus involvment, closure iterator
- invocation is typically higher cost than inline iterators. Adornment by
- a macro wrapper at the call site like this is a possibly useful reminder.
- The factory `proc`, as an ordinary procedure, can be recursive. The
- above macro allows such recursion to look much like a recursive iterator
- would. For example:
- .. code-block:: nim
- proc recCountDown(n: int): iterator(): int =
- result = iterator(): int =
- if n > 0:
- yield n
- for e in toItr(recCountDown(n - 1)):
- yield e
- for i in toItr(recCountDown(6)): # Emits: 6 5 4 3 2 1
- echo i
- See also see `iterable <#overloading-resolution-iterable>`_ for passing iterators to templates and macros.
- Converters
- ==========
- A converter is like an ordinary proc except that it enhances
- the "implicitly convertible" type relation (see `Convertible relation`_):
- .. code-block:: nim
- # bad style ahead: Nim is not C.
- converter toBool(x: int): bool = x != 0
- if 4:
- echo "compiles"
- A converter can also be explicitly invoked for improved readability. Note that
- implicit converter chaining is not supported: If there is a converter from
- type A to type B and from type B to type C the implicit conversion from A to C
- is not provided.
- Type sections
- =============
- Example:
- .. code-block:: nim
- type # example demonstrating mutually recursive types
- Node = ref object # an object managed by the garbage collector (ref)
- le, ri: Node # left and right subtrees
- sym: ref Sym # leaves contain a reference to a Sym
- Sym = object # a symbol
- name: string # the symbol's name
- line: int # the line the symbol was declared in
- code: Node # the symbol's abstract syntax tree
- A type section begins with the `type` keyword. It contains multiple
- type definitions. A type definition binds a type to a name. Type definitions
- can be recursive or even mutually recursive. Mutually recursive types are only
- possible within a single `type` section. Nominal types like `objects`
- or `enums` can only be defined in a `type` section.
- Exception handling
- ==================
- Try statement
- -------------
- Example:
- .. code-block:: nim
- # read the first two lines of a text file that should contain numbers
- # and tries to add them
- var
- f: File
- if open(f, "numbers.txt"):
- try:
- var a = readLine(f)
- var b = readLine(f)
- echo "sum: " & $(parseInt(a) + parseInt(b))
- except OverflowDefect:
- echo "overflow!"
- except ValueError:
- echo "could not convert string to integer"
- except IOError:
- echo "IO error!"
- except:
- echo "Unknown exception!"
- finally:
- close(f)
- The statements after the `try` are executed in sequential order unless
- an exception `e` is raised. If the exception type of `e` matches any
- listed in an `except` clause, the corresponding statements are executed.
- The statements following the `except` clauses are called
- `exception handlers`:idx:.
- The empty `except`:idx: clause is executed if there is an exception that is
- not listed otherwise. It is similar to an `else` clause in `if` statements.
- If there is a `finally`:idx: clause, it is always executed after the
- exception handlers.
- The exception is *consumed* in an exception handler. However, an
- exception handler may raise another exception. If the exception is not
- handled, it is propagated through the call stack. This means that often
- the rest of the procedure - that is not within a `finally` clause -
- is not executed (if an exception occurs).
- Try expression
- --------------
- Try can also be used as an expression; the type of the `try` branch then
- needs to fit the types of `except` branches, but the type of the `finally`
- branch always has to be `void`:
- .. code-block:: nim
- from std/strutils import parseInt
- let x = try: parseInt("133a")
- except: -1
- finally: echo "hi"
- To prevent confusing code there is a parsing limitation; if the `try`
- follows a `(` it has to be written as a one liner:
- .. code-block:: nim
- let x = (try: parseInt("133a") except: -1)
- Except clauses
- --------------
- Within an `except` clause it is possible to access the current exception
- using the following syntax:
- .. code-block:: nim
- try:
- # ...
- except IOError as e:
- # Now use "e"
- echo "I/O error: " & e.msg
- Alternatively, it is possible to use `getCurrentException` to retrieve the
- exception that has been raised:
- .. code-block:: nim
- try:
- # ...
- except IOError:
- let e = getCurrentException()
- # Now use "e"
- Note that `getCurrentException` always returns a `ref Exception`
- type. If a variable of the proper type is needed (in the example
- above, `IOError`), one must convert it explicitly:
- .. code-block:: nim
- try:
- # ...
- except IOError:
- let e = (ref IOError)(getCurrentException())
- # "e" is now of the proper type
- However, this is seldom needed. The most common case is to extract an
- error message from `e`, and for such situations, it is enough to use
- `getCurrentExceptionMsg`:
- .. code-block:: nim
- try:
- # ...
- except:
- echo getCurrentExceptionMsg()
- Custom exceptions
- -----------------
- It is possible to create custom exceptions. A custom exception is a custom type:
- .. code-block:: nim
- type
- LoadError* = object of Exception
- Ending the custom exception's name with `Error` is recommended.
- Custom exceptions can be raised just like any other exception, e.g.:
- .. code-block:: nim
- raise newException(LoadError, "Failed to load data")
- Defer statement
- ---------------
- Instead of a `try finally` statement a `defer` statement can be used, which
- avoids lexical nesting and offers more flexibility in terms of scoping as shown
- below.
- Any statements following the `defer` in the current block will be considered
- to be in an implicit try block:
- .. code-block:: nim
- :test: "nim c $1"
- proc main =
- var f = open("numbers.txt", fmWrite)
- defer: close(f)
- f.write "abc"
- f.write "def"
- Is rewritten to:
- .. code-block:: nim
- :test: "nim c $1"
- proc main =
- var f = open("numbers.txt")
- try:
- f.write "abc"
- f.write "def"
- finally:
- close(f)
- When `defer` is at the outermost scope of a template/macro, its scope extends
- to the block where the template is called from:
- .. code-block:: nim
- :test: "nim c $1"
- template safeOpenDefer(f, path) =
- var f = open(path, fmWrite)
- defer: close(f)
- template safeOpenFinally(f, path, body) =
- var f = open(path, fmWrite)
- try: body # without `defer`, `body` must be specified as parameter
- finally: close(f)
- block:
- safeOpenDefer(f, "/tmp/z01.txt")
- f.write "abc"
- block:
- safeOpenFinally(f, "/tmp/z01.txt"):
- f.write "abc" # adds a lexical scope
- block:
- var f = open("/tmp/z01.txt", fmWrite)
- try:
- f.write "abc" # adds a lexical scope
- finally: close(f)
- Top-level `defer` statements are not supported
- since it's unclear what such a statement should refer to.
- Raise statement
- ---------------
- Example:
- .. code-block:: nim
- raise newException(IOError, "IO failed")
- Apart from built-in operations like array indexing, memory allocation, etc.
- the `raise` statement is the only way to raise an exception.
- .. XXX document this better!
- If no exception name is given, the current exception is `re-raised`:idx:. The
- `ReraiseDefect`:idx: exception is raised if there is no exception to
- re-raise. It follows that the `raise` statement *always* raises an
- exception.
- Exception hierarchy
- -------------------
- The exception tree is defined in the `system <system.html>`_ module.
- Every exception inherits from `system.Exception`. Exceptions that indicate
- programming bugs inherit from `system.Defect` (which is a subtype of `Exception`)
- and are strictly speaking not catchable as they can also be mapped to an operation
- that terminates the whole process. If panics are turned into exceptions, these
- exceptions inherit from `Defect`.
- Exceptions that indicate any other runtime error that can be caught inherit from
- `system.CatchableError` (which is a subtype of `Exception`).
- Imported exceptions
- -------------------
- It is possible to raise/catch imported C++ exceptions. Types imported using
- `importcpp` can be raised or caught. Exceptions are raised by value and
- caught by reference. Example:
- .. code-block:: nim
- :test: "nim cpp -r $1"
- type
- CStdException {.importcpp: "std::exception", header: "<exception>", inheritable.} = object
- ## does not inherit from `RootObj`, so we use `inheritable` instead
- CRuntimeError {.requiresInit, importcpp: "std::runtime_error", header: "<stdexcept>".} = object of CStdException
- ## `CRuntimeError` has no default constructor => `requiresInit`
- proc what(s: CStdException): cstring {.importcpp: "((char *)#.what())".}
- proc initRuntimeError(a: cstring): CRuntimeError {.importcpp: "std::runtime_error(@)", constructor.}
- proc initStdException(): CStdException {.importcpp: "std::exception()", constructor.}
- proc fn() =
- let a = initRuntimeError("foo")
- doAssert $a.what == "foo"
- var b: cstring
- try: raise initRuntimeError("foo2")
- except CStdException as e:
- doAssert e is CStdException
- b = e.what()
- doAssert $b == "foo2"
- try: raise initStdException()
- except CStdException: discard
- try: raise initRuntimeError("foo3")
- except CRuntimeError as e:
- b = e.what()
- except CStdException:
- doAssert false
- doAssert $b == "foo3"
- fn()
- **Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available
- for imported exceptions from C++. One needs to use the `except ImportedException as x:` syntax
- and rely on functionality of the `x` object to get exception details.
- Effect system
- =============
- Exception tracking
- ------------------
- Nim supports exception tracking. The `raises`:idx: pragma can be used
- to explicitly define which exceptions a proc/iterator/method/converter is
- allowed to raise. The compiler verifies this:
- .. code-block:: nim
- :test: "nim c $1"
- proc p(what: bool) {.raises: [IOError, OSError].} =
- if what: raise newException(IOError, "IO")
- else: raise newException(OSError, "OS")
- An empty `raises` list (`raises: []`) means that no exception may be raised:
- .. code-block:: nim
- proc p(): bool {.raises: [].} =
- try:
- unsafeCall()
- result = true
- except:
- result = false
- A `raises` list can also be attached to a proc type. This affects type
- compatibility:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- type
- Callback = proc (s: string) {.raises: [IOError].}
- var
- c: Callback
- proc p(x: string) =
- raise newException(OSError, "OS")
- c = p # type error
- For a routine `p`, the compiler uses inference rules to determine the set of
- possibly raised exceptions; the algorithm operates on `p`'s call graph:
- 1. Every indirect call via some proc type `T` is assumed to
- raise `system.Exception` (the base type of the exception hierarchy) and
- thus any exception unless `T` has an explicit `raises` list.
- However, if the call is of the form `f(...)` where `f` is a parameter of the currently analyzed routine it is ignored. The call is optimistically assumed to have no effect. Rule 2 compensates for this case.
- 2. Every expression of some proc type within a call that is not a call
- itself (and not nil) is assumed to be called indirectly somehow and thus
- its raises list is added to `p`'s raises list.
- 3. Every call to a proc `q` which has an unknown body (due to a forward
- declaration or an `importc` pragma) is assumed to
- raise `system.Exception` unless `q` has an explicit `raises` list.
- 4. Every call to a method `m` is assumed to
- raise `system.Exception` unless `m` has an explicit `raises` list.
- 5. For every other call, the analysis can determine an exact `raises` list.
- 6. For determining a `raises` list, the `raise` and `try` statements
- of `p` are taken into consideration.
- Rules 1-2 ensure the following works:
- .. code-block:: nim
- proc noRaise(x: proc()) {.raises: [].} =
- # unknown call that might raise anything, but valid:
- x()
- proc doRaise() {.raises: [IOError].} =
- raise newException(IOError, "IO")
- proc use() {.raises: [].} =
- # doesn't compile! Can raise IOError!
- noRaise(doRaise)
- So in many cases a callback does not cause the compiler to be overly
- conservative in its effect analysis.
- Exceptions inheriting from `system.Defect` are not tracked with
- the `.raises: []` exception tracking mechanism. This is more consistent with the
- built-in operations. The following code is valid:
- .. code-block:: nim
- proc mydiv(a, b): int {.raises: [].} =
- a div b # can raise an DivByZeroDefect
- And so is:
- .. code-block:: nim
- proc mydiv(a, b): int {.raises: [].} =
- if b == 0: raise newException(DivByZeroDefect, "division by zero")
- else: result = a div b
- The reason for this is that `DivByZeroDefect` inherits from `Defect` and
- with ``--panics:on`` Defects become unrecoverable errors.
- (Since version 1.4 of the language.)
- Tag tracking
- ------------
- Exception tracking is part of Nim's `effect system`:idx:. Raising an exception
- is an *effect*. Other effects can also be defined. A user defined effect is a
- means to *tag* a routine and to perform checks against this tag:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- type IO = object ## input/output effect
- proc readLine(): string {.tags: [IO].} = discard
- proc no_IO_please() {.tags: [].} =
- # the compiler prevents this:
- let x = readLine()
- A tag has to be a type name. A `tags` list - like a `raises` list - can
- also be attached to a proc type. This affects type compatibility.
- The inference for tag tracking is analogous to the inference for
- exception tracking.
- Effects pragma
- --------------
- The `effects` pragma has been designed to assist the programmer with the
- effects analysis. It is a statement that makes the compiler output all inferred
- effects up to the `effects`'s position:
- .. code-block:: nim
- proc p(what: bool) =
- if what:
- raise newException(IOError, "IO")
- {.effects.}
- else:
- raise newException(OSError, "OS")
- The compiler produces a hint message that `IOError` can be raised. `OSError`
- is not listed as it cannot be raised in the branch the `effects` pragma
- appears in.
- Generics
- ========
- Generics are Nim's means to parametrize procs, iterators or types with
- `type parameters`:idx:. Depending on the context, the brackets are used either to
- introduce type parameters or to instantiate a generic proc, iterator, or type.
- The following example shows how a generic binary tree can be modeled:
- .. code-block:: nim
- :test: "nim c $1"
- type
- BinaryTree*[T] = ref object # BinaryTree is a generic type with
- # generic param `T`
- le, ri: BinaryTree[T] # left and right subtrees; may be nil
- data: T # the data stored in a node
- proc newNode*[T](data: T): BinaryTree[T] =
- # constructor for a node
- result = BinaryTree[T](le: nil, ri: nil, data: data)
- proc add*[T](root: var BinaryTree[T], n: BinaryTree[T]) =
- # insert a node into the tree
- if root == nil:
- root = n
- else:
- var it = root
- while it != nil:
- # compare the data items; uses the generic `cmp` proc
- # that works for any type that has a `==` and `<` operator
- var c = cmp(it.data, n.data)
- if c < 0:
- if it.le == nil:
- it.le = n
- return
- it = it.le
- else:
- if it.ri == nil:
- it.ri = n
- return
- it = it.ri
- proc add*[T](root: var BinaryTree[T], data: T) =
- # convenience proc:
- add(root, newNode(data))
- iterator preorder*[T](root: BinaryTree[T]): T =
- # Preorder traversal of a binary tree.
- # This uses an explicit stack (which is more efficient than
- # a recursive iterator factory).
- var stack: seq[BinaryTree[T]] = @[root]
- while stack.len > 0:
- var n = stack.pop()
- while n != nil:
- yield n.data
- add(stack, n.ri) # push right subtree onto the stack
- n = n.le # and follow the left pointer
- var
- root: BinaryTree[string] # instantiate a BinaryTree with `string`
- add(root, newNode("hello")) # instantiates `newNode` and `add`
- add(root, "world") # instantiates the second `add` proc
- for str in preorder(root):
- stdout.writeLine(str)
- The `T` is called a `generic type parameter`:idx: or
- a `type variable`:idx:.
- Is operator
- -----------
- The `is` operator is evaluated during semantic analysis to check for type
- equivalence. It is therefore very useful for type specialization within generic
- code:
- .. code-block:: nim
- type
- Table[Key, Value] = object
- keys: seq[Key]
- values: seq[Value]
- when not (Key is string): # empty value for strings used for optimization
- deletedKeys: seq[bool]
- Type Classes
- ------------
- A type class is a special pseudo-type that can be used to match against
- types in the context of overload resolution or the `is` operator.
- Nim supports the following built-in type classes:
- ================== ===================================================
- type class matches
- ================== ===================================================
- `object` any object type
- `tuple` any tuple type
- `enum` any enumeration
- `proc` any proc type
- `ref` any `ref` type
- `ptr` any `ptr` type
- `var` any `var` type
- `distinct` any distinct type
- `array` any array type
- `set` any set type
- `seq` any seq type
- `auto` any type
- ================== ===================================================
- Furthermore, every generic type automatically creates a type class of the same
- name that will match any instantiation of the generic type.
- Type classes can be combined using the standard boolean operators to form
- more complex type classes:
- .. code-block:: nim
- # create a type class that will match all tuple and object types
- type RecordType = tuple or object
- proc printFields[T: RecordType](rec: T) =
- for key, value in fieldPairs(rec):
- echo key, " = ", value
- Type constraints on generic parameters can be grouped with `,` and propagation
- stops with `;`, similarly to parameters for macros and templates:
- .. code-block:: nim
- proc fn1[T; U, V: SomeFloat]() = discard # T is unconstrained
- template fn2(t; u, v: SomeFloat) = discard # t is unconstrained
- Whilst the syntax of type classes appears to resemble that of ADTs/algebraic data
- types in ML-like languages, it should be understood that type classes are static
- constraints to be enforced at type instantiations. Type classes are not really
- types in themselves but are instead a system of providing generic "checks" that
- ultimately *resolve* to some singular type. Type classes do not allow for
- runtime type dynamism, unlike object variants or methods.
- As an example, the following would not compile:
- .. code-block:: nim
- type TypeClass = int | string
- var foo: TypeClass = 2 # foo's type is resolved to an int here
- foo = "this will fail" # error here, because foo is an int
- Nim allows for type classes and regular types to be specified
- as `type constraints`:idx: of the generic type parameter:
- .. code-block:: nim
- proc onlyIntOrString[T: int|string](x, y: T) = discard
- onlyIntOrString(450, 616) # valid
- onlyIntOrString(5.0, 0.0) # type mismatch
- onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time
- Implicit generics
- -----------------
- A type class can be used directly as the parameter's type.
- .. code-block:: nim
- # create a type class that will match all tuple and object types
- type RecordType = tuple or object
- proc printFields(rec: RecordType) =
- for key, value in fieldPairs(rec):
- echo key, " = ", value
- Procedures utilizing type classes in such a manner are considered to be
- `implicitly generic`:idx:. They will be instantiated once for each unique
- combination of param types used within the program.
- By default, during overload resolution, each named type class will bind to
- exactly one concrete type. We call such type classes `bind once`:idx: types.
- Here is an example taken directly from the system module to illustrate this:
- .. code-block:: nim
- proc `==`*(x, y: tuple): bool =
- ## requires `x` and `y` to be of the same tuple type
- ## generic `==` operator for tuples that is lifted from the components
- ## of `x` and `y`.
- result = true
- for a, b in fields(x, y):
- if a != b: result = false
- Alternatively, the `distinct` type modifier can be applied to the type class
- to allow each param matching the type class to bind to a different type. Such
- type classes are called `bind many`:idx: types.
- Procs written with the implicitly generic style will often need to refer to the
- type parameters of the matched generic type. They can be easily accessed using
- the dot syntax:
- .. code-block:: nim
- type Matrix[T, Rows, Columns] = object
- ...
- proc `[]`(m: Matrix, row, col: int): Matrix.T =
- m.data[col * high(Matrix.Columns) + row]
- Here are more examples that illustrate implicit generics:
- .. code-block:: nim
- proc p(t: Table; k: Table.Key): Table.Value
- # is roughly the same as:
- proc p[Key, Value](t: Table[Key, Value]; k: Key): Value
- .. code-block:: nim
- proc p(a: Table, b: Table)
- # is roughly the same as:
- proc p[Key, Value](a, b: Table[Key, Value])
- .. code-block:: nim
- proc p(a: Table, b: distinct Table)
- # is roughly the same as:
- proc p[Key, Value, KeyB, ValueB](a: Table[Key, Value], b: Table[KeyB, ValueB])
- `typedesc` used as a parameter type also introduces an implicit
- generic. `typedesc` has its own set of rules:
- .. code-block:: nim
- proc p(a: typedesc)
- # is roughly the same as:
- proc p[T](a: typedesc[T])
- `typedesc` is a "bind many" type class:
- .. code-block:: nim
- proc p(a, b: typedesc)
- # is roughly the same as:
- proc p[T, T2](a: typedesc[T], b: typedesc[T2])
- A parameter of type `typedesc` is itself usable as a type. If it is used
- as a type, it's the underlying type. (In other words, one level
- of "typedesc"-ness is stripped off:
- .. code-block:: nim
- proc p(a: typedesc; b: a) = discard
- # is roughly the same as:
- proc p[T](a: typedesc[T]; b: T) = discard
- # hence this is a valid call:
- p(int, 4)
- # as parameter 'a' requires a type, but 'b' requires a value.
- Generic inference restrictions
- ------------------------------
- The types `var T` and `typedesc[T]` cannot be inferred in a generic
- instantiation. The following is not allowed:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- proc g[T](f: proc(x: T); x: T) =
- f(x)
- proc c(y: int) = echo y
- proc v(y: var int) =
- y += 100
- var i: int
- # allowed: infers 'T' to be of type 'int'
- g(c, 42)
- # not valid: 'T' is not inferred to be of type 'var int'
- g(v, i)
- # also not allowed: explicit instantiation via 'var int'
- g[var int](v, i)
- Symbol lookup in generics
- -------------------------
- Open and Closed symbols
- ~~~~~~~~~~~~~~~~~~~~~~~
- The symbol binding rules in generics are slightly subtle: There are "open" and
- "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
- context, an "open" symbol can. Per default, overloaded symbols are open
- and every other symbol is closed.
- Open symbols are looked up in two different contexts: Both the context
- at definition and the context at instantiation are considered:
- .. code-block:: nim
- :test: "nim c $1"
- type
- Index = distinct int
- proc `==` (a, b: Index): bool {.borrow.}
- var a = (0, 0.Index)
- var b = (0, 0.Index)
- echo a == b # works!
- In the example, the generic `==` for tuples (as defined in the system module)
- uses the `==` operators of the tuple's components. However, the `==` for
- the `Index` type is defined *after* the `==` for tuples; yet the example
- compiles as the instantiation takes the currently defined symbols into account
- too.
- Mixin statement
- ---------------
- A symbol can be forced to be open by a `mixin`:idx: declaration:
- .. code-block:: nim
- :test: "nim c $1"
- proc create*[T](): ref T =
- # there is no overloaded 'init' here, so we need to state that it's an
- # open symbol explicitly:
- mixin init
- new result
- init result
- `mixin` statements only make sense in templates and generics.
- Bind statement
- --------------
- The `bind` statement is the counterpart to the `mixin` statement. It
- can be used to explicitly declare identifiers that should be bound early (i.e.
- the identifiers should be looked up in the scope of the template/generic
- definition):
- .. code-block:: nim
- # Module A
- var
- lastId = 0
- template genId*: untyped =
- bind lastId
- inc(lastId)
- lastId
- .. code-block:: nim
- # Module B
- import A
- echo genId()
- But a `bind` is rarely useful because symbol binding from the definition
- scope is the default.
- `bind` statements only make sense in templates and generics.
- Delegating bind statements
- --------------------------
- The following example outlines a problem that can arise when generic
- instantiations cross multiple different modules:
- .. code-block:: nim
- # module A
- proc genericA*[T](x: T) =
- mixin init
- init(x)
- .. code-block:: nim
- import C
- # module B
- proc genericB*[T](x: T) =
- # Without the `bind init` statement C's init proc is
- # not available when `genericB` is instantiated:
- bind init
- genericA(x)
- .. code-block:: nim
- # module C
- type O = object
- proc init*(x: var O) = discard
- .. code-block:: nim
- # module main
- import B, C
- genericB O()
- In module B has an `init` proc from module C in its scope that is not
- taken into account when `genericB` is instantiated which leads to the
- instantiation of `genericA`. The solution is to `forward`:idx these
- symbols by a `bind` statement inside `genericB`.
- Templates
- =========
- A template is a simple form of a macro: It is a simple substitution
- mechanism that operates on Nim's abstract syntax trees. It is processed in
- the semantic pass of the compiler.
- The syntax to *invoke* a template is the same as calling a procedure.
- Example:
- .. code-block:: nim
- template `!=` (a, b: untyped): untyped =
- # this definition exists in the System module
- not (a == b)
- assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
- The `!=`, `>`, `>=`, `in`, `notin`, `isnot` operators are in fact
- templates:
- | `a > b` is transformed into `b < a`.
- | `a in b` is transformed into `contains(b, a)`.
- | `notin` and `isnot` have the obvious meanings.
- The "types" of templates can be the symbols `untyped`,
- `typed` or `typedesc`. These are "meta types", they can only be used in certain
- contexts. Regular types can be used too; this implies that `typed` expressions
- are expected.
- Typed vs untyped parameters
- ---------------------------
- An `untyped` parameter means that symbol lookups and type resolution is not
- performed before the expression is passed to the template. This means that
- *undeclared* identifiers, for example, can be passed to the template:
- .. code-block:: nim
- :test: "nim c $1"
- template declareInt(x: untyped) =
- var x: int
- declareInt(x) # valid
- x = 3
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- template declareInt(x: typed) =
- var x: int
- declareInt(x) # invalid, because x has not been declared and so it has no type
- A template where every parameter is `untyped` is called an `immediate`:idx:
- template. For historical reasons, templates can be explicitly annotated with
- an `immediate` pragma and then these templates do not take part in
- overloading resolution and the parameters' types are *ignored* by the
- compiler. Explicit immediate templates are now deprecated.
- **Note**: For historical reasons, `stmt` was an alias for `typed` and
- `expr` was an alias for `untyped`, but they are removed.
- Passing a code block to a template
- ----------------------------------
- One can pass a block of statements as the last argument to a template
- following the special `:` syntax:
- .. code-block:: nim
- :test: "nim c $1"
- template withFile(f, fn, mode, actions: untyped): untyped =
- var f: File
- if open(f, fn, mode):
- try:
- actions
- finally:
- close(f)
- else:
- quit("cannot open: " & fn)
- withFile(txt, "ttempl3.txt", fmWrite): # special colon
- txt.writeLine("line 1")
- txt.writeLine("line 2")
- In the example, the two `writeLine` statements are bound to the `actions`
- parameter.
- Usually, to pass a block of code to a template, the parameter that accepts
- the block needs to be of type `untyped`. Because symbol lookups are then
- delayed until template instantiation time:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- template t(body: typed) =
- proc p = echo "hey"
- block:
- body
- t:
- p() # fails with 'undeclared identifier: p'
- The above code fails with the error message that `p` is not declared.
- The reason for this is that the `p()` body is type-checked before getting
- passed to the `body` parameter and type checking in Nim implies symbol lookups.
- The same code works with `untyped` as the passed body is not required to be
- type-checked:
- .. code-block:: nim
- :test: "nim c $1"
- template t(body: untyped) =
- proc p = echo "hey"
- block:
- body
- t:
- p() # compiles
- Varargs of untyped
- ------------------
- In addition to the `untyped` meta-type that prevents type checking, there is
- also `varargs[untyped]` so that not even the number of parameters is fixed:
- .. code-block:: nim
- :test: "nim c $1"
- template hideIdentifiers(x: varargs[untyped]) = discard
- hideIdentifiers(undeclared1, undeclared2)
- However, since a template cannot iterate over varargs, this feature is
- generally much more useful for macros.
- Symbol binding in templates
- ---------------------------
- A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are
- bound from the definition scope of the template:
- .. code-block:: nim
- # Module A
- var
- lastId = 0
- template genId*: untyped =
- inc(lastId)
- lastId
- .. code-block:: nim
- # Module B
- import A
- echo genId() # Works as 'lastId' has been bound in 'genId's defining scope
- As in generics, symbol binding can be influenced via `mixin` or `bind`
- statements.
- Identifier construction
- -----------------------
- In templates, identifiers can be constructed with the backticks notation:
- .. code-block:: nim
- :test: "nim c $1"
- template typedef(name: untyped, typ: typedesc) =
- type
- `T name`* {.inject.} = typ
- `P name`* {.inject.} = ref `T name`
- typedef(myint, int)
- var x: PMyInt
- In the example, `name` is instantiated with `myint`, so \`T name\` becomes
- `Tmyint`.
- Lookup rules for template parameters
- ------------------------------------
- A parameter `p` in a template is even substituted in the expression `x.p`.
- Thus, template arguments can be used as field names and a global symbol can be
- shadowed by the same argument name even when fully qualified:
- .. code-block:: nim
- # module 'm'
- type
- Lev = enum
- levA, levB
- var abclev = levB
- template tstLev(abclev: Lev) =
- echo abclev, " ", m.abclev
- tstLev(levA)
- # produces: 'levA levA'
- But the global symbol can properly be captured by a `bind` statement:
- .. code-block:: nim
- # module 'm'
- type
- Lev = enum
- levA, levB
- var abclev = levB
- template tstLev(abclev: Lev) =
- bind m.abclev
- echo abclev, " ", m.abclev
- tstLev(levA)
- # produces: 'levA levB'
- Hygiene in templates
- --------------------
- Per default, templates are `hygienic`:idx:\: Local identifiers declared in a
- template cannot be accessed in the instantiation context:
- .. code-block:: nim
- :test: "nim c $1"
- template newException*(exceptn: typedesc, message: string): untyped =
- var
- e: ref exceptn # e is implicitly gensym'ed here
- new(e)
- e.msg = message
- e
- # so this works:
- let e = "message"
- raise newException(IoError, e)
- Whether a symbol that is declared in a template is exposed to the instantiation
- scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas:
- `gensym`'ed symbols are not exposed but `inject`'ed symbols are.
- The default for symbols of entity `type`, `var`, `let` and `const`
- is `gensym` and for `proc`, `iterator`, `converter`, `template`,
- `macro` is `inject`. However, if the name of the entity is passed as a
- template parameter, it is an `inject`'ed symbol:
- .. code-block:: nim
- template withFile(f, fn, mode: untyped, actions: untyped): untyped =
- block:
- var f: File # since 'f' is a template param, it's injected implicitly
- ...
- withFile(txt, "ttempl3.txt", fmWrite):
- txt.writeLine("line 1")
- txt.writeLine("line 2")
- The `inject` and `gensym` pragmas are second class annotations; they have
- no semantics outside of a template definition and cannot be abstracted over:
- .. code-block:: nim
- {.pragma myInject: inject.}
- template t() =
- var x {.myInject.}: int # does NOT work
- To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for
- a template. `inject` and `gensym` have no effect in `dirty` templates.
- `gensym`'ed symbols cannot be used as `field` in the `x.field` syntax.
- Nor can they be used in the `ObjectConstruction(field: value)`
- and `namedParameterCall(field = value)` syntactic constructs.
- The reason for this is that code like
- .. code-block:: nim
- :test: "nim c $1"
- type
- T = object
- f: int
- template tmp(x: T) =
- let f = 34
- echo x.f, T(f: 4)
- should work as expected.
- However, this means that the method call syntax is not available for
- `gensym`'ed symbols:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- template tmp(x) =
- type
- T {.gensym.} = int
- echo x.T # invalid: instead use: 'echo T(x)'.
- tmp(12)
- **Note**: The Nim compiler prior to version 1 was more lenient about this
- requirement. Use the ``--useVersion:0.19`` switch for a transition period.
- Limitations of the method call syntax
- -------------------------------------
- The expression `x` in `x.f` needs to be semantically checked (that means
- symbol lookup and type checking) before it can be decided that it needs to be
- rewritten to `f(x)`. Therefore the dot syntax has some limitations when it
- is used to invoke templates/macros:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- template declareVar(name: untyped) =
- const name {.inject.} = 45
- # Doesn't compile:
- unknownIdentifier.declareVar
- It is also not possible to use fully qualified identifiers with module
- symbol in method call syntax. The order in which the dot operator
- binds to symbols prohibits this.
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- import std/sequtils
- var myItems = @[1,3,3,7]
- let N1 = count(myItems, 3) # OK
- let N2 = sequtils.count(myItems, 3) # fully qualified, OK
- let N3 = myItems.count(3) # OK
- let N4 = myItems.sequtils.count(3) # illegal, `myItems.sequtils` can't be resolved
- This means that when for some reason a procedure needs a
- disambiguation through the module name, the call needs to be
- written in function call syntax.
- Macros
- ======
- A macro is a special function that is executed at compile time.
- Normally, the input for a macro is an abstract syntax
- tree (AST) of the code that is passed to it. The macro can then do
- transformations on it and return the transformed AST. This can be used to
- add custom language features and implement `domain-specific languages`:idx:.
- Macro invocation is a case where semantic analysis does **not** entirely proceed
- top to bottom and left to right. Instead, semantic analysis happens at least
- twice:
- * Semantic analysis recognizes and resolves the macro invocation.
- * The compiler executes the macro body (which may invoke other procs).
- * It replaces the AST of the macro invocation with the AST returned by the macro.
- * It repeats semantic analysis of that region of the code.
- * If the AST returned by the macro contains other macro invocations,
- this process iterates.
- While macros enable advanced compile-time code transformations, they
- cannot change Nim's syntax.
- Debug Example
- -------------
- The following example implements a powerful `debug` command that accepts a
- variable number of arguments:
- .. code-block:: nim
- :test: "nim c $1"
- # to work with Nim syntax trees, we need an API that is defined in the
- # `macros` module:
- import std/macros
- macro debug(args: varargs[untyped]): untyped =
- # `args` is a collection of `NimNode` values that each contain the
- # AST for an argument of the macro. A macro always has to
- # return a `NimNode`. A node of kind `nnkStmtList` is suitable for
- # this use case.
- result = nnkStmtList.newTree()
- # iterate over any argument that is passed to this macro:
- for n in args:
- # add a call to the statement list that writes the expression;
- # `toStrLit` converts an AST to its string representation:
- result.add newCall("write", newIdentNode("stdout"), newLit(n.repr))
- # add a call to the statement list that writes ": "
- result.add newCall("write", newIdentNode("stdout"), newLit(": "))
- # add a call to the statement list that writes the expressions value:
- result.add newCall("writeLine", newIdentNode("stdout"), n)
- var
- a: array[0..10, int]
- x = "some string"
- a[0] = 42
- a[1] = 45
- debug(a[0], a[1], x)
- The macro call expands to:
- .. code-block:: nim
- write(stdout, "a[0]")
- write(stdout, ": ")
- writeLine(stdout, a[0])
- write(stdout, "a[1]")
- write(stdout, ": ")
- writeLine(stdout, a[1])
- write(stdout, "x")
- write(stdout, ": ")
- writeLine(stdout, x)
- Arguments that are passed to a `varargs` parameter are wrapped in an array
- constructor expression. This is why `debug` iterates over all of `args`'s
- children.
- BindSym
- -------
- The above `debug` macro relies on the fact that `write`, `writeLine` and
- `stdout` are declared in the system module and are thus visible in the
- instantiating context. There is a way to use bound identifiers
- (aka `symbols`:idx:) instead of using unbound identifiers. The `bindSym`
- builtin can be used for that:
- .. code-block:: nim
- :test: "nim c $1"
- import std/macros
- macro debug(n: varargs[typed]): untyped =
- result = newNimNode(nnkStmtList, n)
- for x in n:
- # we can bind symbols in scope via 'bindSym':
- add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(x)))
- add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": ")))
- add(result, newCall(bindSym"writeLine", bindSym"stdout", x))
- var
- a: array[0..10, int]
- x = "some string"
- a[0] = 42
- a[1] = 45
- debug(a[0], a[1], x)
- The macro call expands to:
- .. code-block:: nim
- write(stdout, "a[0]")
- write(stdout, ": ")
- writeLine(stdout, a[0])
- write(stdout, "a[1]")
- write(stdout, ": ")
- writeLine(stdout, a[1])
- write(stdout, "x")
- write(stdout, ": ")
- writeLine(stdout, x)
- However, the symbols `write`, `writeLine` and `stdout` are already bound
- and are not looked up again. As the example shows, `bindSym` does work with
- overloaded symbols implicitly.
- Case-Of Macro
- -------------
- In Nim, it is possible to have a macro with the syntax of a *case-of*
- expression just with the difference that all *of-branches* are passed to
- and processed by the macro implementation. It is then up the macro
- implementation to transform the *of-branches* into a valid Nim
- statement. The following example should show how this feature could be
- used for a lexical analyzer.
- .. code-block:: nim
- import std/macros
- macro case_token(args: varargs[untyped]): untyped =
- echo args.treeRepr
- # creates a lexical analyzer from regular expressions
- # ... (implementation is an exercise for the reader ;-)
- discard
- case_token: # this colon tells the parser it is a macro statement
- of r"[A-Za-z_]+[A-Za-z_0-9]*":
- return tkIdentifier
- of r"0-9+":
- return tkInteger
- of r"[\+\-\*\?]+":
- return tkOperator
- else:
- return tkUnknown
- **Style note**: For code readability, it is best to use the least powerful
- programming construct that still suffices. So the "check list" is:
- (1) Use an ordinary proc/iterator, if possible.
- (2) Else: Use a generic proc/iterator, if possible.
- (3) Else: Use a template, if possible.
- (4) Else: Use a macro.
- For loop macro
- --------------
- A macro that takes as its only input parameter an expression of the special
- type `system.ForLoopStmt` can rewrite the entirety of a `for` loop:
- .. code-block:: nim
- :test: "nim c $1"
- import std/macros
- macro enumerate(x: ForLoopStmt): untyped =
- expectKind x, nnkForStmt
- # check if the starting count is specified:
- var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1]
- result = newStmtList()
- # we strip off the first for loop variable and use it as an integer counter:
- result.add newVarStmt(x[0], countStart)
- var body = x[^1]
- if body.kind != nnkStmtList:
- body = newTree(nnkStmtList, body)
- body.add newCall(bindSym"inc", x[0])
- var newFor = newTree(nnkForStmt)
- for i in 1..x.len-3:
- newFor.add x[i]
- # transform enumerate(X) to 'X'
- newFor.add x[^2][^1]
- newFor.add body
- result.add newFor
- # now wrap the whole macro in a block to create a new scope
- result = quote do:
- block: `result`
- for a, b in enumerate(items([1, 2, 3])):
- echo a, " ", b
- # without wrapping the macro in a block, we'd need to choose different
- # names for `a` and `b` here to avoid redefinition errors
- for a, b in enumerate(10, [1, 2, 3, 5]):
- echo a, " ", b
- Special Types
- =============
- static[T]
- ---------
- As their name suggests, static parameters must be constant expressions:
- .. code-block:: nim
- proc precompiledRegex(pattern: static string): RegEx =
- var res {.global.} = re(pattern)
- return res
- precompiledRegex("/d+") # Replaces the call with a precompiled
- # regex, stored in a global variable
- precompiledRegex(paramStr(1)) # Error, command-line options
- # are not constant expressions
- For the purposes of code generation, all static params are treated as
- generic params - the proc will be compiled separately for each unique
- supplied value (or combination of values).
- Static params can also appear in the signatures of generic types:
- .. code-block:: nim
- type
- Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T]
- # Note how `Number` is just a type constraint here, while
- # `static int` requires us to supply an int value
- AffineTransform2D[T] = Matrix[3, 3, T]
- AffineTransform3D[T] = Matrix[4, 4, T]
- var m1: AffineTransform3D[float] # OK
- var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
- Please note that `static T` is just a syntactic convenience for the underlying
- generic type `static[T]`. The type param can be omitted to obtain the type
- class of all constant expressions. A more specific type class can be created by
- instantiating `static` with another type class.
- One can force an expression to be evaluated at compile time as a constant
- expression by coercing it to a corresponding `static` type:
- .. code-block:: nim
- import std/math
- echo static(fac(5)), " ", static[bool](16.isPowerOfTwo)
- The compiler will report any failure to evaluate the expression or a
- possible type mismatch error.
- typedesc[T]
- -----------
- In many contexts, Nim treats the names of types as regular
- values. These values exist only during the compilation phase, but since
- all values must have a type, `typedesc` is considered their special type.
- `typedesc` acts as a generic type. For instance, the type of the symbol
- `int` is `typedesc[int]`. Just like with regular generic types, when the
- generic param is omitted, `typedesc` denotes the type class of all types.
- As a syntactic convenience, one can also use `typedesc` as a modifier.
- Procs featuring `typedesc` params are considered implicitly generic.
- They will be instantiated for each unique combination of supplied types,
- and within the body of the proc, the name of each param will refer to
- the bound concrete type:
- .. code-block:: nim
- proc new(T: typedesc): ref T =
- echo "allocating ", T.name
- new(result)
- var n = Node.new
- var tree = new(BinaryTree[int])
- When multiple type params are present, they will bind freely to different
- types. To force a bind-once behavior, one can use an explicit generic param:
- .. code-block:: nim
- proc acceptOnlyTypePairs[T, U](A, B: typedesc[T]; C, D: typedesc[U])
- Once bound, type params can appear in the rest of the proc signature:
- .. code-block:: nim
- :test: "nim c $1"
- template declareVariableWithType(T: typedesc, value: T) =
- var x: T = value
- declareVariableWithType int, 42
- Overload resolution can be further influenced by constraining the set
- of types that will match the type param. This works in practice by
- attaching attributes to types via templates. The constraint can be a
- concrete type or a type class.
- .. code-block:: nim
- :test: "nim c $1"
- template maxval(T: typedesc[int]): int = high(int)
- template maxval(T: typedesc[float]): float = Inf
- var i = int.maxval
- var f = float.maxval
- when false:
- var s = string.maxval # error, maxval is not implemented for string
- template isNumber(t: typedesc[object]): string = "Don't think so."
- template isNumber(t: typedesc[SomeInteger]): string = "Yes!"
- template isNumber(t: typedesc[SomeFloat]): string = "Maybe, could be NaN."
- echo "is int a number? ", isNumber(int)
- echo "is float a number? ", isNumber(float)
- echo "is RootObj a number? ", isNumber(RootObj)
- Passing `typedesc` is almost identical, just with the difference that
- the macro is not instantiated generically. The type expression is
- simply passed as a `NimNode` to the macro, like everything else.
- .. code-block:: nim
- import std/macros
- macro forwardType(arg: typedesc): typedesc =
- # `arg` is of type `NimNode`
- let tmp: NimNode = arg
- result = tmp
- var tmp: forwardType(int)
- typeof operator
- ---------------
- **Note**: `typeof(x)` can for historical reasons also be written as
- `type(x)` but `type(x)` is discouraged.
- One can obtain the type of a given expression by constructing a `typeof`
- value from it (in many other languages this is known as the `typeof`:idx:
- operator):
- .. code-block:: nim
- var x = 0
- var y: typeof(x) # y has type int
- If `typeof` is used to determine the result type of a proc/iterator/converter
- call `c(X)` (where `X` stands for a possibly empty list of arguments), the
- interpretation, where `c` is an iterator, is preferred over the
- other interpretations, but this behavior can be changed by
- passing `typeOfProc` as the second argument to `typeof`:
- .. code-block:: nim
- :test: "nim c $1"
- iterator split(s: string): string = discard
- proc split(s: string): seq[string] = discard
- # since an iterator is the preferred interpretation, `y` has the type `string`:
- assert typeof("a b c".split) is string
- assert typeof("a b c".split, typeOfProc) is seq[string]
- Modules
- =======
- Nim supports splitting a program into pieces by a module concept.
- Each module needs to be in its own file and has its own `namespace`:idx:.
- Modules enable `information hiding`:idx: and `separate compilation`:idx:.
- A module may gain access to symbols of another module by the `import`:idx:
- statement. `Recursive module dependencies`:idx: are allowed, but are slightly
- subtle. Only top-level symbols that are marked with an asterisk (`*`) are
- exported. A valid module name can only be a valid Nim identifier (and thus its
- filename is ``identifier.nim``).
- The algorithm for compiling modules is:
- - Compile the whole module as usual, following import statements recursively.
- - If there is a cycle, only import the already parsed symbols (that are
- exported); if an unknown identifier occurs then abort.
- This is best illustrated by an example:
- .. code-block:: nim
- # Module A
- type
- T1* = int # Module A exports the type `T1`
- import B # the compiler starts parsing B
- proc main() =
- var i = p(3) # works because B has been parsed completely here
- main()
- .. code-block:: nim
- # Module B
- import A # A is not parsed here! Only the already known symbols
- # of A are imported.
- proc p*(x: A.T1): A.T1 =
- # this works because the compiler has already
- # added T1 to A's interface symbol table
- result = x + 1
- Import statement
- ----------------
- After the `import` statement, a list of module names can follow or a single
- module name followed by an `except` list to prevent some symbols from being
- imported:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- import std/strutils except `%`, toUpperAscii
- # doesn't work then:
- echo "$1" % "abc".toUpperAscii
- It is not checked that the `except` list is really exported from the module.
- This feature allows us to compile against an older version of the module that
- does not export these identifiers.
- The `import` statement is only allowed at the top level.
- Include statement
- -----------------
- The `include` statement does something fundamentally different than
- importing a module: it merely includes the contents of a file. The `include`
- statement is useful to split up a large module into several files:
- .. code-block:: nim
- include fileA, fileB, fileC
- The `include` statement can be used outside of the top level, as such:
- .. code-block:: nim
- # Module A
- echo "Hello World!"
- .. code-block:: nim
- # Module B
- proc main() =
- include A
- main() # => Hello World!
- Module names in imports
- -----------------------
- A module alias can be introduced via the `as` keyword:
- .. code-block:: nim
- import std/strutils as su, std/sequtils as qu
- echo su.format("$1", "lalelu")
- The original module name is then not accessible. The notations
- `path/to/module` or `"path/to/module"` can be used to refer to a module
- in subdirectories:
- .. code-block:: nim
- import lib/pure/os, "lib/pure/times"
- Note that the module name is still `strutils` and not `lib/pure/strutils`
- and so one **cannot** do:
- .. code-block:: nim
- import lib/pure/strutils
- echo lib/pure/strutils.toUpperAscii("abc")
- Likewise, the following does not make sense as the name is `strutils` already:
- .. code-block:: nim
- import lib/pure/strutils as strutils
- Collective imports from a directory
- -----------------------------------
- The syntax `import dir / [moduleA, moduleB]` can be used to import multiple modules
- from the same directory.
- Path names are syntactically either Nim identifiers or string literals. If the path
- name is not a valid Nim identifier it needs to be a string literal:
- .. code-block:: nim
- import "gfx/3d/somemodule" # in quotes because '3d' is not a valid Nim identifier
- Pseudo import/include paths
- ---------------------------
- A directory can also be a so-called "pseudo directory". They can be used to
- avoid ambiguity when there are multiple modules with the same path.
- There are two pseudo directories:
- 1. `std`: The `std` pseudo directory is the abstract location of Nim's standard
- library. For example, the syntax `import std / strutils` is used to unambiguously
- refer to the standard library's `strutils` module.
- 2. `pkg`: The `pkg` pseudo directory is used to unambiguously refer to a Nimble
- package. However, for technical details that lie outside the scope of this document,
- its semantics are: *Use the search path to look for module name but ignore the standard
- library locations*. In other words, it is the opposite of `std`.
- From import statement
- ---------------------
- After the `from` statement, a module name follows followed by
- an `import` to list the symbols one likes to use without explicit
- full qualification:
- .. code-block:: nim
- :test: "nim c $1"
- from std/strutils import `%`
- echo "$1" % "abc"
- # always possible: full qualification:
- echo strutils.replace("abc", "a", "z")
- It's also possible to use `from module import nil` if one wants to import
- the module but wants to enforce fully qualified access to every symbol
- in `module`.
- Export statement
- ----------------
- An `export` statement can be used for symbol forwarding so that client
- modules don't need to import a module's dependencies:
- .. code-block:: nim
- # module B
- type MyObject* = object
- .. code-block:: nim
- # module A
- import B
- export B.MyObject
- proc `$`*(x: MyObject): string = "my object"
- .. code-block:: nim
- # module C
- import A
- # B.MyObject has been imported implicitly here:
- var x: MyObject
- echo $x
- When the exported symbol is another module, all of its definitions will
- be forwarded. One can use an `except` list to exclude some of the symbols.
- Notice that when exporting, one needs to specify only the module name:
- .. code-block:: nim
- import foo/bar/baz
- export baz
- Scope rules
- -----------
- Identifiers are valid from the point of their declaration until the end of
- the block in which the declaration occurred. The range where the identifier
- is known is the scope of the identifier. The exact scope of an
- identifier depends on the way it was declared.
- Block scope
- ~~~~~~~~~~~
- The *scope* of a variable declared in the declaration part of a block
- is valid from the point of declaration until the end of the block. If a
- block contains a second block, in which the identifier is redeclared,
- then inside this block, the second declaration will be valid. Upon
- leaving the inner block, the first declaration is valid again. An
- identifier cannot be redefined in the same block, except if valid for
- procedure or iterator overloading purposes.
- Tuple or object scope
- ~~~~~~~~~~~~~~~~~~~~~
- The field identifiers inside a tuple or object definition are valid in the
- following places:
- * To the end of the tuple/object definition.
- * Field designators of a variable of the given tuple/object type.
- * In all descendant types of the object type.
- Module scope
- ~~~~~~~~~~~~
- All identifiers of a module are valid from the point of declaration until
- the end of the module. Identifiers from indirectly dependent modules are *not*
- available. The `system`:idx: module is automatically imported in every module.
- If a module imports an identifier by two different modules, each occurrence of
- the identifier has to be qualified unless it is an overloaded procedure or
- iterator in which case the overloading resolution takes place:
- .. code-block:: nim
- # Module A
- var x*: string
- .. code-block:: nim
- # Module B
- var x*: int
- .. code-block:: nim
- # Module C
- import A, B
- write(stdout, x) # error: x is ambiguous
- write(stdout, A.x) # no error: qualifier used
- var x = 4
- write(stdout, x) # not ambiguous: uses the module C's x
- Compiler Messages
- =================
- The Nim compiler emits different kinds of messages: `hint`:idx:,
- `warning`:idx:, and `error`:idx: messages. An *error* message is emitted if
- the compiler encounters any static error.
- Pragmas
- =======
- Pragmas are Nim's method to give the compiler additional information /
- commands without introducing a massive number of new keywords. Pragmas are
- processed on the fly during semantic checking. Pragmas are enclosed in the
- special `{.` and `.}` curly brackets. Pragmas are also often used as a
- first implementation to play with a language feature before a nicer syntax
- to access the feature becomes available.
- deprecated pragma
- -----------------
- The deprecated pragma is used to mark a symbol as deprecated:
- .. code-block:: nim
- proc p() {.deprecated.}
- var x {.deprecated.}: char
- This pragma can also take in an optional warning string to relay to developers.
- .. code-block:: nim
- proc thing(x: bool) {.deprecated: "use thong instead".}
- noSideEffect pragma
- -------------------
- The `noSideEffect` pragma is used to mark a proc/iterator that can have only
- side effects through parameters. This means that the proc/iterator only changes locations that are
- reachable from its parameters and the return value only depends on the
- parameters. If none of its parameters have the type `var`, `ref`, `ptr`, `cstring`, or `proc`,
- then no locations are modified.
- It is a static error to mark a proc/iterator to have no side effect if the compiler cannot verify this.
- As a special semantic rule, the built-in `debugEcho
- <system.html#debugEcho,varargs[typed,]>`_ pretends to be free of side effects
- so that it can be used for debugging routines marked as `noSideEffect`.
- `func` is syntactic sugar for a proc with no side effects:
- .. code-block:: nim
- func `+` (x, y: int): int
- To override the compiler's side effect analysis a `{.noSideEffect.}`
- `cast` pragma block can be used:
- .. code-block:: nim
- func f() =
- {.cast(noSideEffect).}:
- echo "test"
- When a `noSideEffect` proc has proc params `bar`, whether it can be used inside a `noSideEffect` context
- depends on what the compiler knows about `bar`:
- .. code-block:: nim
- :test: "nim c $1"
- func foo(bar: proc(): int): int = bar()
- var count = 0
- proc fn1(): int = 1
- proc fn2(): int = (count.inc; count)
- func fun1() = discard foo(fn1) # ok because fn1 is inferred as `func`
- # func fun2() = discard foo(fn2) # would give: Error: 'fun2' can have side effects
- # with callbacks, the compiler is conservative, ie that bar will have side effects
- var foo2: type(foo) = foo
- func main() =
- discard foo(fn1) # ok
- # discard foo2(fn1) # now this errors
- compileTime pragma
- ------------------
- The `compileTime` pragma is used to mark a proc or variable to be used only
- during compile-time execution. No code will be generated for it. Compile-time
- procs are useful as helpers for macros. Since version 0.12.0 of the language, a
- proc that uses `system.NimNode` within its parameter types is implicitly
- declared `compileTime`:
- .. code-block:: nim
- proc astHelper(n: NimNode): NimNode =
- result = n
- Is the same as:
- .. code-block:: nim
- proc astHelper(n: NimNode): NimNode {.compileTime.} =
- result = n
- `compileTime` variables are available at runtime too. This simplifies certain
- idioms where variables are filled at compile-time (for example, lookup tables)
- but accessed at runtime:
- .. code-block:: nim
- :test: "nim c -r $1"
- import std/macros
- var nameToProc {.compileTime.}: seq[(string, proc (): string {.nimcall.})]
- macro registerProc(p: untyped): untyped =
- result = newTree(nnkStmtList, p)
- let procName = p[0]
- let procNameAsStr = $p[0]
- result.add quote do:
- nameToProc.add((`procNameAsStr`, `procName`))
- proc foo: string {.registerProc.} = "foo"
- proc bar: string {.registerProc.} = "bar"
- proc baz: string {.registerProc.} = "baz"
- doAssert nameToProc[2][1]() == "baz"
- noReturn pragma
- ---------------
- The `noreturn` pragma is used to mark a proc that never returns.
- acyclic pragma
- --------------
- The `acyclic` pragma can be used for object types to mark them as acyclic
- even though they seem to be cyclic. This is an **optimization** for the garbage
- collector to not consider objects of this type as part of a cycle:
- .. code-block:: nim
- type
- Node = ref NodeObj
- NodeObj {.acyclic.} = object
- left, right: Node
- data: string
- Or if we directly use a ref object:
- .. code-block:: nim
- type
- Node {.acyclic.} = ref object
- left, right: Node
- data: string
- In the example, a tree structure is declared with the `Node` type. Note that
- the type definition is recursive and the GC has to assume that objects of
- this type may form a cyclic graph. The `acyclic` pragma passes the
- information that this cannot happen to the GC. If the programmer uses the
- `acyclic` pragma for data types that are in reality cyclic, this may result
- in memory leaks, but memory safety is preserved.
- final pragma
- ------------
- The `final` pragma can be used for an object type to specify that it
- cannot be inherited from. Note that inheritance is only available for
- objects that inherit from an existing object (via the `object of SuperType`
- syntax) or that have been marked as `inheritable`.
- shallow pragma
- --------------
- The `shallow` pragma affects the semantics of a type: The compiler is
- allowed to make a shallow copy. This can cause serious semantic issues and
- break memory safety! However, it can speed up assignments considerably,
- because the semantics of Nim require deep copying of sequences and strings.
- This can be expensive, especially if sequences are used to build a tree
- structure:
- .. code-block:: nim
- type
- NodeKind = enum nkLeaf, nkInner
- Node {.shallow.} = object
- case kind: NodeKind
- of nkLeaf:
- strVal: string
- of nkInner:
- children: seq[Node]
- pure pragma
- -----------
- An object type can be marked with the `pure` pragma so that its type field
- which is used for runtime type identification is omitted. This used to be
- necessary for binary compatibility with other compiled languages.
- An enum type can be marked as `pure`. Then access of its fields always
- requires full qualification.
- asmNoStackFrame pragma
- ----------------------
- A proc can be marked with the `asmNoStackFrame` pragma to tell the compiler
- it should not generate a stack frame for the proc. There are also no exit
- statements like `return result;` generated and the generated C function is
- declared as `__declspec(naked)`:c: or `__attribute__((naked))`:c: (depending on
- the used C compiler).
- **Note**: This pragma should only be used by procs which consist solely of
- assembler statements.
- error pragma
- ------------
- The `error` pragma is used to make the compiler output an error message
- with the given content. The compilation does not necessarily abort after an error
- though.
- The `error` pragma can also be used to
- annotate a symbol (like an iterator or proc). The *usage* of the symbol then
- triggers a static error. This is especially useful to rule out that some
- operation is valid due to overloading and type conversions:
- .. code-block:: nim
- ## check that underlying int values are compared and not the pointers:
- proc `==`(x, y: ptr int): bool {.error.}
- fatal pragma
- ------------
- The `fatal` pragma is used to make the compiler output an error message
- with the given content. In contrast to the `error` pragma, the compilation
- is guaranteed to be aborted by this pragma. Example:
- .. code-block:: nim
- when not defined(objc):
- {.fatal: "Compile this program with the objc command!".}
- warning pragma
- --------------
- The `warning` pragma is used to make the compiler output a warning message
- with the given content. Compilation continues after the warning.
- hint pragma
- -----------
- The `hint` pragma is used to make the compiler output a hint message with
- the given content. Compilation continues after the hint.
- line pragma
- -----------
- The `line` pragma can be used to affect line information of the annotated
- statement, as seen in stack backtraces:
- .. code-block:: nim
- template myassert*(cond: untyped, msg = "") =
- if not cond:
- # change run-time line information of the 'raise' statement:
- {.line: instantiationInfo().}:
- raise newException(EAssertionFailed, msg)
- If the `line` pragma is used with a parameter, the parameter needs be a
- `tuple[filename: string, line: int]`. If it is used without a parameter,
- `system.InstantiationInfo()` is used.
- linearScanEnd pragma
- --------------------
- The `linearScanEnd` pragma can be used to tell the compiler how to
- compile a Nim `case`:idx: statement. Syntactically it has to be used as a
- statement:
- .. code-block:: nim
- case myInt
- of 0:
- echo "most common case"
- of 1:
- {.linearScanEnd.}
- echo "second most common case"
- of 2: echo "unlikely: use branch table"
- else: echo "unlikely too: use branch table for ", myInt
- In the example, the case branches `0` and `1` are much more common than
- the other cases. Therefore the generated assembler code should test for these
- values first so that the CPU's branch predictor has a good chance to succeed
- (avoiding an expensive CPU pipeline stall). The other cases might be put into a
- jump table for O(1) overhead but at the cost of a (very likely) pipeline
- stall.
- The `linearScanEnd` pragma should be put into the last branch that should be
- tested against via linear scanning. If put into the last branch of the
- whole `case` statement, the whole `case` statement uses linear scanning.
- computedGoto pragma
- -------------------
- The `computedGoto` pragma can be used to tell the compiler how to
- compile a Nim `case`:idx: in a `while true` statement.
- Syntactically it has to be used as a statement inside the loop:
- .. code-block:: nim
- type
- MyEnum = enum
- enumA, enumB, enumC, enumD, enumE
- proc vm() =
- var instructions: array[0..100, MyEnum]
- instructions[2] = enumC
- instructions[3] = enumD
- instructions[4] = enumA
- instructions[5] = enumD
- instructions[6] = enumC
- instructions[7] = enumA
- instructions[8] = enumB
- instructions[12] = enumE
- var pc = 0
- while true:
- {.computedGoto.}
- let instr = instructions[pc]
- case instr
- of enumA:
- echo "yeah A"
- of enumC, enumD:
- echo "yeah CD"
- of enumB:
- echo "yeah B"
- of enumE:
- break
- inc(pc)
- vm()
- As the example shows, `computedGoto` is mostly useful for interpreters. If
- the underlying backend (C compiler) does not support the computed goto
- extension the pragma is simply ignored.
- immediate pragma
- ----------------
- The immediate pragma is obsolete. See `Typed vs untyped parameters
- <#templates-typed-vs-untyped-parameters>`_.
- compilation option pragmas
- --------------------------
- The listed pragmas here can be used to override the code generation options
- for a proc/method/converter.
- The implementation currently provides the following possible options (various
- others may be added later).
- =============== =============== ============================================
- pragma allowed values description
- =============== =============== ============================================
- checks on|off Turns the code generation for all runtime
- checks on or off.
- boundChecks on|off Turns the code generation for array bound
- checks on or off.
- overflowChecks on|off Turns the code generation for over- or
- underflow checks on or off.
- nilChecks on|off Turns the code generation for nil pointer
- checks on or off.
- assertions on|off Turns the code generation for assertions
- on or off.
- warnings on|off Turns the warning messages of the compiler
- on or off.
- hints on|off Turns the hint messages of the compiler
- on or off.
- optimization none|speed|size Optimize the code for speed or size, or
- disable optimization.
- patterns on|off Turns the term rewriting templates/macros
- on or off.
- callconv cdecl|... Specifies the default calling convention for
- all procedures (and procedure types) that
- follow.
- =============== =============== ============================================
- Example:
- .. code-block:: nim
- {.checks: off, optimization: speed.}
- # compile without runtime checks and optimize for speed
- push and pop pragmas
- --------------------
- The `push/pop`:idx: pragmas are very similar to the option directive,
- but are used to override the settings temporarily. Example:
- .. code-block:: nim
- {.push checks: off.}
- # compile this section without runtime checks as it is
- # speed critical
- # ... some code ...
- {.pop.} # restore old settings
- `push/pop`:idx: can switch on/off some standard library pragmas, example:
- .. code-block:: nim
- {.push inline.}
- proc thisIsInlined(): int = 42
- func willBeInlined(): float = 42.0
- {.pop.}
- proc notInlined(): int = 9
- {.push discardable, boundChecks: off, compileTime, noSideEffect, experimental.}
- template example(): string = "https://nim-lang.org"
- {.pop.}
- {.push deprecated, hint[LineTooLong]: off, used, stackTrace: off.}
- proc sample(): bool = true
- {.pop.}
- For third party pragmas, it depends on its implementation but uses the same syntax.
- register pragma
- ---------------
- The `register` pragma is for variables only. It declares the variable as
- `register`, giving the compiler a hint that the variable should be placed
- in a hardware register for faster access. C compilers usually ignore this
- though and for good reasons: Often they do a better job without it anyway.
- However, in highly specific cases (a dispatch loop of a bytecode interpreter
- for example) it may provide benefits.
- global pragma
- -------------
- The `global` pragma can be applied to a variable within a proc to instruct
- the compiler to store it in a global location and initialize it once at program
- startup.
- .. code-block:: nim
- proc isHexNumber(s: string): bool =
- var pattern {.global.} = re"[0-9a-fA-F]+"
- result = s.match(pattern)
- When used within a generic proc, a separate unique global variable will be
- created for each instantiation of the proc. The order of initialization of
- the created global variables within a module is not defined, but all of them
- will be initialized after any top-level variables in their originating module
- and before any variable in a module that imports it.
- Disabling certain messages
- --------------------------
- Nim generates some warnings and hints ("line too long") that may annoy the
- user. A mechanism for disabling certain messages is provided: Each hint
- and warning message contains a symbol in brackets. This is the message's
- identifier that can be used to enable or disable it:
- .. code-block:: Nim
- {.hint[LineTooLong]: off.} # turn off the hint about too long lines
- This is often better than disabling all warnings at once.
- used pragma
- -----------
- Nim produces a warning for symbols that are not exported and not used either.
- The `used` pragma can be attached to a symbol to suppress this warning. This
- is particularly useful when the symbol was generated by a macro:
- .. code-block:: nim
- template implementArithOps(T) =
- proc echoAdd(a, b: T) {.used.} =
- echo a + b
- proc echoSub(a, b: T) {.used.} =
- echo a - b
- # no warning produced for the unused 'echoSub'
- implementArithOps(int)
- echoAdd 3, 5
- `used` can also be used as a top-level statement to mark a module as "used".
- This prevents the "Unused import" warning:
- .. code-block:: nim
- # module: debughelper.nim
- when defined(nimHasUsed):
- # 'import debughelper' is so useful for debugging
- # that Nim shouldn't produce a warning for that import,
- # even if currently unused:
- {.used.}
- experimental pragma
- -------------------
- The `experimental` pragma enables experimental language features. Depending
- on the concrete feature, this means that the feature is either considered
- too unstable for an otherwise stable release or that the future of the feature
- is uncertain (it may be removed at any time).
- Example:
- .. code-block:: nim
- import std/threadpool
- {.experimental: "parallel".}
- proc threadedEcho(s: string, i: int) =
- echo(s, " ", $i)
- proc useParallel() =
- parallel:
- for i in 0..4:
- spawn threadedEcho("echo in parallel", i)
- useParallel()
- As a top-level statement, the experimental pragma enables a feature for the
- rest of the module it's enabled in. This is problematic for macro and generic
- instantiations that cross a module scope. Currently, these usages have to be
- put into a `.push/pop` environment:
- .. code-block:: nim
- # client.nim
- proc useParallel*[T](unused: T) =
- # use a generic T here to show the problem.
- {.push experimental: "parallel".}
- parallel:
- for i in 0..4:
- echo "echo in parallel"
- {.pop.}
- .. code-block:: nim
- import client
- useParallel(1)
- Implementation Specific Pragmas
- ===============================
- This section describes additional pragmas that the current Nim implementation
- supports but which should not be seen as part of the language specification.
- Bitsize pragma
- --------------
- The `bitsize` pragma is for object field members. It declares the field as
- a bitfield in C/C++.
- .. code-block:: Nim
- type
- mybitfield = object
- flag {.bitsize:1.}: cuint
- generates:
- .. code-block:: C
- struct mybitfield {
- unsigned int flag:1;
- };
- Align pragma
- ------------
- The `align`:idx: pragma is for variables and object field members. It
- modifies the alignment requirement of the entity being declared. The
- argument must be a constant power of 2. Valid non-zero
- alignments that are weaker than other align pragmas on the same
- declaration are ignored. Alignments that are weaker than the
- alignment requirement of the type are ignored.
- .. code-block:: Nim
- type
- sseType = object
- sseData {.align(16).}: array[4, float32]
- # every object will be aligned to 128-byte boundary
- Data = object
- x: char
- cacheline {.align(128).}: array[128, char] # over-aligned array of char,
- proc main() =
- echo "sizeof(Data) = ", sizeof(Data), " (1 byte + 127 bytes padding + 128-byte array)"
- # output: sizeof(Data) = 256 (1 byte + 127 bytes padding + 128-byte array)
- echo "alignment of sseType is ", alignof(sseType)
- # output: alignment of sseType is 16
- var d {.align(2048).}: Data # this instance of data is aligned even stricter
- main()
- This pragma has no effect on the JS backend.
- Volatile pragma
- ---------------
- The `volatile` pragma is for variables only. It declares the variable as
- `volatile`:c:, whatever that means in C/C++ (its semantics are not well defined
- in C/C++).
- **Note**: This pragma will not exist for the LLVM backend.
- nodecl pragma
- -------------
- The `nodecl` pragma can be applied to almost any symbol (variable, proc,
- type, etc.) and is sometimes useful for interoperability with C:
- It tells Nim that it should not generate a declaration for the symbol in
- the C code. For example:
- .. code-block:: Nim
- var
- EACCES {.importc, nodecl.}: cint # pretend EACCES was a variable, as
- # Nim does not know its value
- However, the `header` pragma is often the better alternative.
- **Note**: This will not work for the LLVM backend.
- Header pragma
- -------------
- The `header` pragma is very similar to the `nodecl` pragma: It can be
- applied to almost any symbol and specifies that it should not be declared
- and instead, the generated code should contain an `#include`:c:\:
- .. code-block:: Nim
- type
- PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
- # import C's FILE* type; Nim will treat it as a new pointer type
- The `header` pragma always expects a string constant. The string constant
- contains the header file: As usual for C, a system header file is enclosed
- in angle brackets: `<>`:c:. If no angle brackets are given, Nim
- encloses the header file in `""`:c: in the generated C code.
- **Note**: This will not work for the LLVM backend.
- IncompleteStruct pragma
- -----------------------
- The `incompleteStruct` pragma tells the compiler to not use the
- underlying C `struct`:c: in a `sizeof` expression:
- .. code-block:: Nim
- type
- DIR* {.importc: "DIR", header: "<dirent.h>",
- pure, incompleteStruct.} = object
- Compile pragma
- --------------
- The `compile` pragma can be used to compile and link a C/C++ source file
- with the project:
- .. code-block:: Nim
- {.compile: "myfile.cpp".}
- **Note**: Nim computes a SHA1 checksum and only recompiles the file if it
- has changed. One can use the ``-f`` command-line option to force
- the recompilation of the file.
- Since 1.4 the `compile` pragma is also available with this syntax:
- .. code-block:: Nim
- {.compile("myfile.cpp", "--custom flags here").}
- As can be seen in the example, this new variant allows for custom flags
- that are passed to the C compiler when the file is recompiled.
- Link pragma
- -----------
- The `link` pragma can be used to link an additional file with the project:
- .. code-block:: Nim
- {.link: "myfile.o".}
- PassC pragma
- ------------
- The `passc` pragma can be used to pass additional parameters to the C
- compiler like one would using the command-line switch ``--passc``:
- .. code-block:: Nim
- {.passc: "-Wall -Werror".}
- Note that one can use `gorge` from the `system module <system.html>`_ to
- embed parameters from an external command that will be executed
- during semantic analysis:
- .. code-block:: Nim
- {.passc: gorge("pkg-config --cflags sdl").}
- LocalPassc pragma
- -----------------
- The `localPassc` pragma can be used to pass additional parameters to the C
- compiler, but only for the C/C++ file that is produced from the Nim module
- the pragma resides in:
- .. code-block:: Nim
- # Module A.nim
- # Produces: A.nim.cpp
- {.localPassc: "-Wall -Werror".} # Passed when compiling A.nim.cpp
- PassL pragma
- ------------
- The `passL` pragma can be used to pass additional parameters to the linker
- like one would be using the command-line switch ``--passL``:
- .. code-block:: Nim
- {.passL: "-lSDLmain -lSDL".}
- Note that one can use `gorge` from the `system module <system.html>`_ to
- embed parameters from an external command that will be executed
- during semantic analysis:
- .. code-block:: Nim
- {.passL: gorge("pkg-config --libs sdl").}
- Emit pragma
- -----------
- The `emit` pragma can be used to directly affect the output of the
- compiler's code generator. The code is then unportable to other code
- generators/backends. Its usage is highly discouraged! However, it can be
- extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
- Example:
- .. code-block:: Nim
- {.emit: """
- static int cvariable = 420;
- """.}
- {.push stackTrace:off.}
- proc embedsC() =
- var nimVar = 89
- # access Nim symbols within an emit section outside of string literals:
- {.emit: ["""fprintf(stdout, "%d\n", cvariable + (int)""", nimVar, ");"].}
- {.pop.}
- embedsC()
- `nimbase.h` defines `NIM_EXTERNC` C macro that can be used for
- `extern "C"`:cpp: code to work with both `nim c` and `nim cpp`, e.g.:
- .. code-block:: Nim
- proc foobar() {.importc:"$1".}
- {.emit: """
- #include <stdio.h>
- NIM_EXTERNC
- void fun(){}
- """.}
- .. note:: For backward compatibility, if the argument to the `emit` statement
- is a single string literal, Nim symbols can be referred to via backticks.
- This usage is however deprecated.
- For a top-level emit statement, the section where in the generated C/C++ file
- the code should be emitted can be influenced via the prefixes
- `/*TYPESECTION*/`:c: or `/*VARSECTION*/`:c: or `/*INCLUDESECTION*/`:c:\:
- .. code-block:: Nim
- {.emit: """/*TYPESECTION*/
- struct Vector3 {
- public:
- Vector3(): x(5) {}
- Vector3(float x_): x(x_) {}
- float x;
- };
- """.}
- type Vector3 {.importcpp: "Vector3", nodecl} = object
- x: cfloat
- proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
- ImportCpp pragma
- ----------------
- **Note**: `c2nim <https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst>`_ can parse a large subset of C++ and knows
- about the `importcpp` pragma pattern language. It is not necessary
- to know all the details described here.
- Similar to the `importc pragma for C
- <#foreign-function-interface-importc-pragma>`_, the
- `importcpp` pragma can be used to import `C++`:idx: methods or C++ symbols
- in general. The generated code then uses the C++ method calling
- syntax: `obj->method(arg)`:cpp:. In combination with the `header` and `emit`
- pragmas this allows *sloppy* interfacing with libraries written in C++:
- .. code-block:: Nim
- # Horrible example of how to interface with a C++ engine ... ;-)
- {.link: "/usr/lib/libIrrlicht.so".}
- {.emit: """
- using namespace irr;
- using namespace core;
- using namespace scene;
- using namespace video;
- using namespace io;
- using namespace gui;
- """.}
- const
- irr = "<irrlicht/irrlicht.h>"
- type
- IrrlichtDeviceObj {.header: irr,
- importcpp: "IrrlichtDevice".} = object
- IrrlichtDevice = ptr IrrlichtDeviceObj
- proc createDevice(): IrrlichtDevice {.
- header: irr, importcpp: "createDevice(@)".}
- proc run(device: IrrlichtDevice): bool {.
- header: irr, importcpp: "#.run(@)".}
- The compiler needs to be told to generate C++ (command ``cpp``) for
- this to work. The conditional symbol `cpp` is defined when the compiler
- emits C++ code.
- Namespaces
- ~~~~~~~~~~
- The *sloppy interfacing* example uses `.emit` to produce `using namespace`:cpp:
- declarations. It is usually much better to instead refer to the imported name
- via the `namespace::identifier`:cpp: notation:
- .. code-block:: nim
- type
- IrrlichtDeviceObj {.header: irr,
- importcpp: "irr::IrrlichtDevice".} = object
- Importcpp for enums
- ~~~~~~~~~~~~~~~~~~~
- When `importcpp` is applied to an enum type the numerical enum values are
- annotated with the C++ enum type, like in this example:
- `((TheCppEnum)(3))`:cpp:.
- (This turned out to be the simplest way to implement it.)
- Importcpp for procs
- ~~~~~~~~~~~~~~~~~~~
- Note that the `importcpp` variant for procs uses a somewhat cryptic pattern
- language for maximum flexibility:
- - A hash ``#`` symbol is replaced by the first or next argument.
- - A dot following the hash ``#.`` indicates that the call should use C++'s dot
- or arrow notation.
- - An at symbol ``@`` is replaced by the remaining arguments,
- separated by commas.
- For example:
- .. code-block:: nim
- proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".}
- var x: ptr CppObj
- cppMethod(x[], 1, 2, 3)
- Produces:
- .. code-block:: C
- x->CppMethod(1, 2, 3)
- As a special rule to keep backward compatibility with older versions of the
- `importcpp` pragma, if there is no special pattern
- character (any of ``# ' @``) at all, C++'s
- dot or arrow notation is assumed, so the above example can also be written as:
- .. code-block:: nim
- proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}
- Note that the pattern language naturally also covers C++'s operator overloading
- capabilities:
- .. code-block:: nim
- proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".}
- proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
- - An apostrophe ``'`` followed by an integer ``i`` in the range 0..9
- is replaced by the i'th parameter *type*. The 0th position is the result
- type. This can be used to pass types to C++ function templates. Between
- the ``'`` and the digit, an asterisk can be used to get to the base type
- of the type. (So it "takes away a star" from the type; `T*`:c: becomes `T`.)
- Two stars can be used to get to the element type of the element type etc.
- For example:
- .. code-block:: nim
- type Input {.importcpp: "System::Input".} = object
- proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
- let x: ptr Input = getSubsystem[Input]()
- Produces:
- .. code-block:: C
- x = SystemManager::getSubsystem<System::Input>()
- - ``#@`` is a special case to support a `cnew` operation. It is required so
- that the call expression is inlined directly, without going through a
- temporary location. This is only required to circumvent a limitation of the
- current code generator.
- For example C++'s `new`:cpp: operator can be "imported" like this:
- .. code-block:: nim
- proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
- # constructor of 'Foo':
- proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".}
- let x = cnew constructFoo(3, 4)
- Produces:
- .. code-block:: C
- x = new Foo(3, 4)
- However, depending on the use case `new Foo`:cpp: can also be wrapped like this
- instead:
- .. code-block:: nim
- proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
- let x = newFoo(3, 4)
- Wrapping constructors
- ~~~~~~~~~~~~~~~~~~~~~
- Sometimes a C++ class has a private copy constructor and so code like
- `Class c = Class(1,2);`:cpp: must not be generated but instead
- `Class c(1,2);`:cpp:.
- For this purpose the Nim proc that wraps a C++ constructor needs to be
- annotated with the `constructor`:idx: pragma. This pragma also helps to generate
- faster C++ code since construction then doesn't invoke the copy constructor:
- .. code-block:: nim
- # a better constructor of 'Foo':
- proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
- Wrapping destructors
- ~~~~~~~~~~~~~~~~~~~~
- Since Nim generates C++ directly, any destructor is called implicitly by the
- C++ compiler at the scope exits. This means that often one can get away with
- not wrapping the destructor at all! However, when it needs to be invoked
- explicitly, it needs to be wrapped. The pattern language provides
- everything that is required:
- .. code-block:: nim
- proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}
- Importcpp for objects
- ~~~~~~~~~~~~~~~~~~~~~
- Generic `importcpp`'ed objects are mapped to C++ templates. This means that
- one can import C++'s templates rather easily without the need for a pattern
- language for object types:
- .. code-block:: nim
- :test: "nim cpp $1"
- type
- StdMap[K, V] {.importcpp: "std::map", header: "<map>".} = object
- proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
- importcpp: "#[#] = #", header: "<map>".}
- var x: StdMap[cint, cdouble]
- x[6] = 91.4
- Produces:
- .. code-block:: C
- std::map<int, double> x;
- x[6] = 91.4;
- - If more precise control is needed, the apostrophe `'` can be used in the
- supplied pattern to denote the concrete type parameters of the generic type.
- See the usage of the apostrophe operator in proc patterns for more details.
- .. code-block:: nim
- type
- VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
- var x: VectorIterator[cint]
- Produces:
- .. code-block:: C
- std::vector<int>::iterator x;
- ImportJs pragma
- ---------------
- Similar to the `importcpp pragma for C++ <#implementation-specific-pragmas-importcpp-pragma>`_,
- the `importjs` pragma can be used to import Javascript methods or
- symbols in general. The generated code then uses the Javascript method
- calling syntax: ``obj.method(arg)``.
- ImportObjC pragma
- -----------------
- Similar to the `importc pragma for C
- <#foreign-function-interface-importc-pragma>`_, the `importobjc` pragma can
- be used to import `Objective C`:idx: methods. The generated code then uses the
- Objective C method calling syntax: ``[obj method param1: arg]``.
- In addition with the `header` and `emit` pragmas this
- allows *sloppy* interfacing with libraries written in Objective C:
- .. code-block:: Nim
- # horrible example of how to interface with GNUStep ...
- {.passL: "-lobjc".}
- {.emit: """
- #include <objc/Object.h>
- @interface Greeter:Object
- {
- }
- - (void)greet:(long)x y:(long)dummy;
- @end
- #include <stdio.h>
- @implementation Greeter
- - (void)greet:(long)x y:(long)dummy
- {
- printf("Hello, World!\n");
- }
- @end
- #include <stdlib.h>
- """.}
- type
- Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
- proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}
- proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}
- proc free(self: Id) {.importobjc: "free", nodecl.}
- var g = newGreeter()
- g.greet(12, 34)
- g.free()
- The compiler needs to be told to generate Objective C (command ``objc``) for
- this to work. The conditional symbol ``objc`` is defined when the compiler
- emits Objective C code.
- CodegenDecl pragma
- ------------------
- The `codegenDecl` pragma can be used to directly influence Nim's code
- generator. It receives a format string that determines how the variable
- or proc is declared in the generated code.
- For variables, $1 in the format string represents the type of the variable
- and $2 is the name of the variable.
- The following Nim code:
- .. code-block:: nim
- var
- a {.codegenDecl: "$# progmem $#".}: int
- will generate this C code:
- .. code-block:: c
- int progmem a
- For procedures, $1 is the return type of the procedure, $2 is the name of
- the procedure, and $3 is the parameter list.
- The following nim code:
- .. code-block:: nim
- proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
- echo "realistic interrupt handler"
- will generate this code:
- .. code-block:: c
- __interrupt void myinterrupt()
- `cppNonPod` pragma
- ------------------
- The `.cppNonPod` pragma should be used for non-POD `importcpp` types so that they
- work properly (in particular regarding constructor and destructor) for
- `.threadvar` variables. This requires ``--tlsEmulation:off``.
- .. code-block:: nim
- type Foo {.cppNonPod, importcpp, header: "funs.h".} = object
- x: cint
- proc main()=
- var a {.threadvar.}: Foo
- InjectStmt pragma
- -----------------
- The `injectStmt` pragma can be used to inject a statement before every
- other statement in the current module. It is only supposed to be used for
- debugging:
- .. code-block:: nim
- {.injectStmt: gcInvariants().}
- # ... complex code here that produces crashes ...
- compile-time define pragmas
- ---------------------------
- The pragmas listed here can be used to optionally accept values from
- the -d/--define option at compile time.
- The implementation currently provides the following possible options (various
- others may be added later).
- ================= ============================================
- pragma description
- ================= ============================================
- `intdefine`:idx: Reads in a build-time define as an integer
- `strdefine`:idx: Reads in a build-time define as a string
- `booldefine`:idx: Reads in a build-time define as a bool
- ================= ============================================
- .. code-block:: nim
- const FooBar {.intdefine.}: int = 5
- echo FooBar
- ::
- nim c -d:FooBar=42 foobar.nim
- In the above example, providing the ``-d`` flag causes the symbol
- `FooBar` to be overwritten at compile-time, printing out 42. If the
- ``-d:FooBar=42`` were to be omitted, the default value of 5 would be
- used. To see if a value was provided, `defined(FooBar)` can be used.
- The syntax ``-d:flag`` is actually just a shortcut for ``-d:flag=true``.
- User-defined pragmas
- ====================
- pragma pragma
- -------------
- The `pragma` pragma can be used to declare user-defined pragmas. This is
- useful because Nim's templates and macros do not affect pragmas. User-defined pragmas are in a different module-wide scope than all other symbols.
- They cannot be imported from a module.
- Example:
- .. code-block:: nim
- when appType == "lib":
- {.pragma: rtl, exportc, dynlib, cdecl.}
- else:
- {.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
- proc p*(a, b: int): int {.rtl.} =
- result = a+b
- In the example, a new pragma named `rtl` is introduced that either imports
- a symbol from a dynamic library or exports the symbol for dynamic library
- generation.
- Custom annotations
- ------------------
- It is possible to define custom typed pragmas. Custom pragmas do not affect
- code generation directly, but their presence can be detected by macros.
- Custom pragmas are defined using templates annotated with pragma `pragma`:
- .. code-block:: nim
- template dbTable(name: string, table_space: string = "") {.pragma.}
- template dbKey(name: string = "", primary_key: bool = false) {.pragma.}
- template dbForeignKey(t: typedesc) {.pragma.}
- template dbIgnore {.pragma.}
- Consider this stylized example of a possible Object Relation Mapping (ORM)
- implementation:
- .. code-block:: nim
- const tblspace {.strdefine.} = "dev" # switch for dev, test and prod environments
- type
- User {.dbTable("users", tblspace).} = object
- id {.dbKey(primary_key = true).}: int
- name {.dbKey"full_name".}: string
- is_cached {.dbIgnore.}: bool
- age: int
- UserProfile {.dbTable("profiles", tblspace).} = object
- id {.dbKey(primary_key = true).}: int
- user_id {.dbForeignKey: User.}: int
- read_access: bool
- write_access: bool
- admin_acess: bool
- In this example, custom pragmas are used to describe how Nim objects are
- mapped to the schema of the relational database. Custom pragmas can have
- zero or more arguments. In order to pass multiple arguments use one of
- template call syntaxes. All arguments are typed and follow standard
- overload resolution rules for templates. Therefore, it is possible to have
- default values for arguments, pass by name, varargs, etc.
- Custom pragmas can be used in all locations where ordinary pragmas can be
- specified. It is possible to annotate procs, templates, type and variable
- definitions, statements, etc.
- The macros module includes helpers which can be used to simplify custom pragma
- access `hasCustomPragma`, `getCustomPragmaVal`. Please consult the
- `macros <macros.html>`_ module documentation for details. These macros are not
- magic, everything they do can also be achieved by walking the AST of the object
- representation.
- More examples with custom pragmas:
- - Better serialization/deserialization control:
- .. code-block:: nim
- type MyObj = object
- a {.dontSerialize.}: int
- b {.defaultDeserialize: 5.}: int
- c {.serializationKey: "_c".}: string
- - Adopting type for gui inspector in a game engine:
- .. code-block:: nim
- type MyComponent = object
- position {.editable, animatable.}: Vector3
- alpha {.editRange: [0.0..1.0], animatable.}: float32
- Macro pragmas
- -------------
- All macros and templates can also be used as pragmas. They can be attached
- to routines (procs, iterators, etc), type names, or type expressions. The
- compiler will perform the following simple syntactic transformations:
- .. code-block:: nim
- template command(name: string, def: untyped) = discard
- proc p() {.command("print").} = discard
- This is translated to:
- .. code-block:: nim
- command("print"):
- proc p() = discard
- ------
- .. code-block:: nim
- type
- AsyncEventHandler = proc (x: Event) {.async.}
- This is translated to:
- .. code-block:: nim
- type
- AsyncEventHandler = async(proc (x: Event))
- ------
- .. code-block:: nim
- type
- MyObject {.schema: "schema.protobuf".} = object
- This is translated to a call to the `schema` macro with a `nnkTypeDef`
- AST node capturing both the left-hand side and right-hand side of the
- definition. The macro can return a potentially modified `nnkTypeDef` tree
- which will replace the original row in the type section.
- When multiple macro pragmas are applied to the same definition, the
- compiler will apply them consequently from left to right. Each macro
- will receive as input the output of the previous one.
- Foreign function interface
- ==========================
- Nim's `FFI`:idx: (foreign function interface) is extensive and only the
- parts that scale to other future backends (like the LLVM/JavaScript backends)
- are documented here.
- Importc pragma
- --------------
- The `importc` pragma provides a means to import a proc or a variable
- from C. The optional argument is a string containing the C identifier. If
- the argument is missing, the C name is the Nim identifier *exactly as
- spelled*:
- .. code-block::
- proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
- When `importc` is applied to a `let` statement it can omit its value which
- will then be expected to come from C. This can be used to import a C `const`:c:\:
- .. code-block::
- {.emit: "const int cconst = 42;".}
- let cconst {.importc, nodecl.}: cint
- assert cconst == 42
- Note that this pragma has been abused in the past to also work in the
- JS backend for JS objects and functions. Other backends do provide
- the same feature under the same name. Also, when the target language
- is not set to C, other pragmas are available:
- * `importcpp <manual.html#implementation-specific-pragmas-importcpp-pragma>`_
- * `importobjc <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
- * `importjs <manual.html#implementation-specific-pragmas-importjs-pragma>`_
- .. code-block:: Nim
- proc p(s: cstring) {.importc: "prefix$1".}
- In the example, the external name of `p` is set to `prefixp`. Only ``$1``
- is available and a literal dollar sign must be written as ``$$``.
- Exportc pragma
- --------------
- The `exportc` pragma provides a means to export a type, a variable, or a
- procedure to C. Enums and constants can't be exported. The optional argument
- is a string containing the C identifier. If the argument is missing, the C
- name is the Nim identifier *exactly as spelled*:
- .. code-block:: Nim
- proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
- Note that this pragma is somewhat of a misnomer: Other backends do provide
- the same feature under the same name.
- The string literal passed to `exportc` can be a format string:
- .. code-block:: Nim
- proc p(s: string) {.exportc: "prefix$1".} =
- echo s
- In the example, the external name of `p` is set to `prefixp`. Only ``$1``
- is available and a literal dollar sign must be written as ``$$``.
- If the symbol should also be exported to a dynamic library, the `dynlib`
- pragma should be used in addition to the `exportc` pragma. See
- `Dynlib pragma for export <#foreign-function-interface-dynlib-pragma-for-export>`_.
- Extern pragma
- -------------
- Like `exportc` or `importc`, the `extern` pragma affects name
- mangling. The string literal passed to `extern` can be a format string:
- .. code-block:: Nim
- proc p(s: string) {.extern: "prefix$1".} =
- echo s
- In the example, the external name of `p` is set to `prefixp`. Only ``$1``
- is available and a literal dollar sign must be written as ``$$``.
- Bycopy pragma
- -------------
- The `bycopy` pragma can be applied to an object or tuple type and
- instructs the compiler to pass the type by value to procs:
- .. code-block:: nim
- type
- Vector {.bycopy.} = object
- x, y, z: float
- Byref pragma
- ------------
- The `byref` pragma can be applied to an object or tuple type and instructs
- the compiler to pass the type by reference (hidden pointer) to procs.
- Varargs pragma
- --------------
- The `varargs` pragma can be applied to procedures only (and procedure
- types). It tells Nim that the proc can take a variable number of parameters
- after the last specified parameter. Nim string values will be converted to C
- strings automatically:
- .. code-block:: Nim
- proc printf(formatstr: cstring) {.nodecl, varargs.}
- printf("hallo %s", "world") # "world" will be passed as C string
- Union pragma
- ------------
- The `union` pragma can be applied to any `object` type. It means all
- of the object's fields are overlaid in memory. This produces a `union`:c:
- instead of a `struct`:c: in the generated C/C++ code. The object declaration
- then must not use inheritance or any GC'ed memory but this is currently not
- checked.
- **Future directions**: GC'ed memory should be allowed in unions and the GC
- should scan unions conservatively.
- Packed pragma
- -------------
- The `packed` pragma can be applied to any `object` type. It ensures
- that the fields of an object are packed back-to-back in memory. It is useful
- to store packets or messages from/to network or hardware drivers, and for
- interoperability with C. Combining packed pragma with inheritance is not
- defined, and it should not be used with GC'ed memory (ref's).
- **Future directions**: Using GC'ed memory in packed pragma will result in
- a static error. Usage with inheritance should be defined and documented.
- Dynlib pragma for import
- ------------------------
- With the `dynlib` pragma, a procedure or a variable can be imported from
- a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX).
- The non-optional argument has to be the name of the dynamic library:
- .. code-block:: Nim
- proc gtk_image_new(): PGtkWidget
- {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.}
- In general, importing a dynamic library does not require any special linker
- options or linking with import libraries. This also implies that no *devel*
- packages need to be installed.
- The `dynlib` import mechanism supports a versioning scheme:
- .. code-block:: nim
- proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl,
- importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".}
- At runtime, the dynamic library is searched for (in this order)::
- libtcl.so.1
- libtcl.so.0
- libtcl8.5.so.1
- libtcl8.5.so.0
- libtcl8.4.so.1
- libtcl8.4.so.0
- libtcl8.3.so.1
- libtcl8.3.so.0
- The `dynlib` pragma supports not only constant strings as an argument but also
- string expressions in general:
- .. code-block:: nim
- import std/os
- proc getDllName: string =
- result = "mylib.dll"
- if fileExists(result): return
- result = "mylib2.dll"
- if fileExists(result): return
- quit("could not load dynamic library")
- proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}
- **Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant
- strings, because they are precompiled.
- **Note**: Passing variables to the `dynlib` pragma will fail at runtime
- because of order of initialization problems.
- **Note**: A `dynlib` import can be overridden with
- the ``--dynlibOverride:name`` command-line option. The
- `Compiler User Guide <nimc.html>`_ contains further information.
- Dynlib pragma for export
- ------------------------
- With the `dynlib` pragma, a procedure can also be exported to
- a dynamic library. The pragma then has no argument and has to be used in
- conjunction with the `exportc` pragma:
- .. code-block:: Nim
- proc exportme(): int {.cdecl, exportc, dynlib.}
- This is only useful if the program is compiled as a dynamic library via the
- ``--app:lib`` command-line option.
- Threads
- =======
- To enable thread support the ``--threads:on`` command-line switch needs to
- be used. The system_ module then contains several threading primitives.
- See the `threads <threads.html>`_ and `channels <channels.html>`_ modules
- for the low-level thread API. There are also high-level parallelism constructs
- available. See `spawn <manual_experimental.html#parallel-amp-spawn>`_ for
- further details.
- Nim's memory model for threads is quite different than that of other common
- programming languages (C, Pascal, Java): Each thread has its own (garbage
- collected) heap, and sharing of memory is restricted to global variables. This
- helps to prevent race conditions. GC efficiency is improved quite a lot,
- because the GC never has to stop other threads and see what they reference.
- Thread pragma
- -------------
- A proc that is executed as a new thread of execution should be marked by the
- `thread` pragma for reasons of readability. The compiler checks for
- violations of the `no heap sharing restriction`:idx:\: This restriction implies
- that it is invalid to construct a data structure that consists of memory
- allocated from different (thread-local) heaps.
- A thread proc is passed to `createThread` or `spawn` and invoked
- indirectly; so the `thread` pragma implies `procvar`.
- GC safety
- ---------
- We call a proc `p` `GC safe`:idx: when it doesn't access any global variable
- that contains GC'ed memory (`string`, `seq`, `ref` or a closure) either
- directly or indirectly through a call to a GC unsafe proc.
- The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe,
- otherwise this property is inferred by the compiler. Note that `noSideEffect`
- implies `gcsafe`. The only way to create a thread is via `spawn` or
- `createThread`. The invoked proc must not use `var` parameters nor must
- any of its parameters contain a `ref` or `closure` type. This enforces
- the *no heap sharing restriction*.
- Routines that are imported from C are always assumed to be `gcsafe`.
- To disable the GC-safety checking the ``--threadAnalysis:off`` command-line
- switch can be used. This is a temporary workaround to ease the porting effort
- from old code to the new threading model.
- To override the compiler's gcsafety analysis a `{.cast(gcsafe).}` pragma block can
- be used:
- .. code-block:: nim
- var
- someGlobal: string = "some string here"
- perThread {.threadvar.}: string
- proc setPerThread() =
- {.cast(gcsafe).}:
- deepCopy(perThread, someGlobal)
- See also:
- - `Shared heap memory management <gc.html>`_.
- Threadvar pragma
- ----------------
- A variable can be marked with the `threadvar` pragma, which makes it a
- `thread-local`:idx: variable; Additionally, this implies all the effects
- of the `global` pragma.
- .. code-block:: nim
- var checkpoints* {.threadvar.}: seq[string]
- Due to implementation restrictions, thread-local variables cannot be
- initialized within the `var` section. (Every thread-local variable needs to
- be replicated at thread creation.)
- Threads and exceptions
- ----------------------
- The interaction between threads and exceptions is simple: A *handled* exception
- in one thread cannot affect any other thread. However, an *unhandled* exception
- in one thread terminates the whole *process*.
|