123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665 |
- <?xml version="1.0" encoding="utf-8" ?>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <!-- This file is generated by Nim. -->
- <html xmlns="https://www.w3.org/1999/xhtml" xml:lang="en" lang="en" data-theme="auto">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Nim Experimental Features</title>
- <!-- Google fonts -->
- <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
- <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
- <!-- Favicon -->
- <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
- <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
- <!-- CSS -->
- <link rel="stylesheet" type="text/css" href="nimdoc.out.css?v=2.3.1">
- <!-- JS -->
- <script type="text/javascript" src="dochack.js?v=2.3.1"></script>
- </head>
- <body>
- <div class="document" id="documentId">
- <div class="container">
- <h1 class="title">Nim Experimental Features</h1>
- <div class="row">
- <div class="three columns">
- <div class="theme-select-wrapper">
- <label for="theme-select">Theme: </label>
- <select id="theme-select" onchange="setTheme(this.value)">
- <option value="auto">🌗 Match OS</option>
- <option value="dark">🌑 Dark</option>
- <option value="light">🌕 Light</option>
- </select>
- </div>
- <div id="global-links">
- <ul class="simple-boot">
- <li><a href="manual.html">Manual</a></li>
- <li><a href="lib.html">Standard library</a></li>
- <li> <a id="indexLink" href="theindex.html">Index</a></li>
- <li><a href="compiler/theindex.html">Compiler docs</a></li>
- <li><a href="https://nim-lang.github.io/fusion/theindex.html">Fusion docs</a></li>
- <li><a href="https://nim-lang.github.io/Nim/">devel</a>, <a href="https://nim-lang.org/documentation.html">stable</a></li>
- </ul>
- </div>
- <div id="searchInputDiv">
- Search: <input type="search" id="searchInput"
- oninput="search()" />
- </div>
- <div class="search-groupby">
- Group by:
- <select onchange="groupBy(this.value)">
- <option value="section">Section</option>
- <option value="type">Type</option>
- </select>
- </div>
- <ul class="simple simple-toc" id="toc-list">
- <li><a class="reference" id="about-this-document_toc" href="#about-this-document">About this document</a></li>
- <li><a class="reference" id="void-type_toc" href="#void-type">Void type</a></li>
- <li><a class="reference" id="generic-nimdefine-pragma_toc" href="#generic-nimdefine-pragma">Generic <tt class="docutils literal"><span class="pre"><span class="Identifier">define</span></span></tt> pragma</a></li>
- <li><a class="reference" id="topminusdown-type-inference_toc" href="#topminusdown-type-inference">Top-down type inference</a></li>
- <ul class="simple"><li><a class="reference" id="topminusdown-type-inference-inferred-generic-parameters_toc" href="#topminusdown-type-inference-inferred-generic-parameters">Inferred generic parameters</a></li>
- <li><a class="reference" id="topminusdown-type-inference-sequence-literals_toc" href="#topminusdown-type-inference-sequence-literals">Sequence literals</a></li>
- </ul><li><a class="reference" id="package-level-objects_toc" href="#package-level-objects">Package level objects</a></li>
- <li><a class="reference" id="importing-private-symbols_toc" href="#importing-private-symbols">Importing private symbols</a></li>
- <li><a class="reference" id="code-reordering_toc" href="#code-reordering">Code reordering</a></li>
- <li><a class="reference" id="special-operators_toc" href="#special-operators">Special Operators</a></li>
- <ul class="simple"><li><a class="reference" id="special-operators-dot-operators_toc" href="#special-operators-dot-operators">dot operators</a></li>
- <li><a class="reference" id="special-operators-operator-nimdot_toc" href="#special-operators-operator-nimdot">operator <tt class="docutils literal"><span class="pre"><span class="Operator">.</span></span></tt></a></li>
- <li><a class="reference" id="special-operators-operator-nimdot_toc" href="#special-operators-operator-nimdot">operator <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt></a></li>
- <li><a class="reference" id="special-operators-operator-nimdoteq_toc" href="#special-operators-operator-nimdoteq">operator <tt class="docutils literal"><span class="pre"><span class="Operator">.=</span></span></tt></a></li>
- <li><a class="reference" id="special-operators-call-operator_toc" href="#special-operators-call-operator">Call operator</a></li>
- </ul><li><a class="reference" id="extended-macro-pragmas_toc" href="#extended-macro-pragmas">Extended macro pragmas</a></li>
- <li><a class="reference" id="symbols-as-templateslashmacro-calls-alias-syntax_toc" href="#symbols-as-templateslashmacro-calls-alias-syntax">Symbols as template/macro calls (alias syntax)</a></li>
- <li><a class="reference" id="not-nil-annotation_toc" href="#not-nil-annotation">Not nil annotation</a></li>
- <li><a class="reference" id="strict-not-nil-checking_toc" href="#strict-not-nil-checking">Strict not nil checking</a></li>
- <ul class="simple"><li><a class="reference" id="strict-not-nil-checking-nil_toc" href="#strict-not-nil-checking-nil">nil</a></li>
- <li><a class="reference" id="strict-not-nil-checking-not-nil_toc" href="#strict-not-nil-checking-not-nil">not nil</a></li>
- <li><a class="reference" id="strict-not-nil-checking-local-turn-onslashoff_toc" href="#strict-not-nil-checking-local-turn-onslashoff">local turn on/off</a></li>
- <li><a class="reference" id="strict-not-nil-checking-nilability-state_toc" href="#strict-not-nil-checking-nilability-state">nilability state</a></li>
- <li><a class="reference" id="strict-not-nil-checking-type-nilability_toc" href="#strict-not-nil-checking-type-nilability">type nilability</a></li>
- <li><a class="reference" id="strict-not-nil-checking-params-rules_toc" href="#strict-not-nil-checking-params-rules">params rules</a></li>
- <li><a class="reference" id="strict-not-nil-checking-assignment-rules_toc" href="#strict-not-nil-checking-assignment-rules">assignment rules</a></li>
- <li><a class="reference" id="strict-not-nil-checking-call-args-rules_toc" href="#strict-not-nil-checking-call-args-rules">call args rules</a></li>
- <li><a class="reference" id="strict-not-nil-checking-branches-rules_toc" href="#strict-not-nil-checking-branches-rules">branches rules</a></li>
- <li><a class="reference" id="strict-not-nil-checking-compound-expressionscolon-field-index-expressions_toc" href="#strict-not-nil-checking-compound-expressionscolon-field-index-expressions">compound expressions: field, index expressions</a></li>
- <li><a class="reference" id="strict-not-nil-checking-element-tracking_toc" href="#strict-not-nil-checking-element-tracking">element tracking</a></li>
- <li><a class="reference" id="strict-not-nil-checking-unstructured-control-flow-rules_toc" href="#strict-not-nil-checking-unstructured-control-flow-rules">unstructured control flow rules</a></li>
- <li><a class="reference" id="strict-not-nil-checking-aliasing_toc" href="#strict-not-nil-checking-aliasing">aliasing</a></li>
- <li><a class="reference" id="strict-not-nil-checking-warnings-and-errors_toc" href="#strict-not-nil-checking-warnings-and-errors">warnings and errors</a></li>
- </ul><li><a class="reference" id="aliasing-restrictions-in-parameter-passing_toc" href="#aliasing-restrictions-in-parameter-passing">Aliasing restrictions in parameter passing</a></li>
- <li><a class="reference" id="strict-funcs_toc" href="#strict-funcs">Strict funcs</a></li>
- <li><a class="reference" id="view-types_toc" href="#view-types">View types</a></li>
- <ul class="simple"><li><a class="reference" id="view-types-path-expressions_toc" href="#view-types-path-expressions">Path expressions</a></li>
- <li><a class="reference" id="view-types-start-of-a-borrow_toc" href="#view-types-start-of-a-borrow">Start of a borrow</a></li>
- <li><a class="reference" id="view-types-end-of-a-borrow_toc" href="#view-types-end-of-a-borrow">End of a borrow</a></li>
- <li><a class="reference" id="view-types-reborrows_toc" href="#view-types-reborrows">Reborrows</a></li>
- <li><a class="reference" id="view-types-algorithm_toc" href="#view-types-algorithm">Algorithm</a></li>
- </ul><li><a class="reference" id="concepts_toc" href="#concepts">Concepts</a></li>
- <ul class="simple"><li><a class="reference" id="concepts-concept-diagnostics_toc" href="#concepts-concept-diagnostics">Concept diagnostics</a></li>
- <li><a class="reference" id="concepts-generic-concepts-and-type-binding-rules_toc" href="#concepts-generic-concepts-and-type-binding-rules">Generic concepts and type binding rules</a></li>
- <li><a class="reference" id="concepts-concept-derived-values_toc" href="#concepts-concept-derived-values">Concept derived values</a></li>
- <li><a class="reference" id="concepts-concept-refinement_toc" href="#concepts-concept-refinement">Concept refinement</a></li>
- </ul><li><a class="reference" id="dynamic-arguments-for-bindsym_toc" href="#dynamic-arguments-for-bindsym">Dynamic arguments for bindSym</a></li>
- <li><a class="reference" id="term-rewriting-macros_toc" href="#term-rewriting-macros">Term rewriting macros</a></li>
- <ul class="simple"><li><a class="reference" id="term-rewriting-macros-parameter-constraints_toc" href="#term-rewriting-macros-parameter-constraints">Parameter constraints</a></li>
- <li><a class="reference" id="term-rewriting-macros-pattern-operators_toc" href="#term-rewriting-macros-pattern-operators">Pattern operators</a></li>
- <ul class="simple"><li><a class="reference" id="pattern-operators-the-nimbar-operator_toc" href="#pattern-operators-the-nimbar-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">|</span></span></tt> operator</a></li>
- <li><a class="reference" id="pattern-operators-the-nim-operator_toc" href="#pattern-operators-the-nim-operator">The <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Punctuation">}</span></span></tt> operator</a></li>
- <li><a class="reference" id="pattern-operators-the-nimtilde-operator_toc" href="#pattern-operators-the-nimtilde-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">~</span></span></tt> operator</a></li>
- <li><a class="reference" id="pattern-operators-the-nimstar-operator_toc" href="#pattern-operators-the-nimstar-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> operator</a></li>
- <li><a class="reference" id="pattern-operators-the-nimstarstar-operator_toc" href="#pattern-operators-the-nimstarstar-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">**</span></span></tt> operator</a></li>
- </ul><li><a class="reference" id="term-rewriting-macros-parameters_toc" href="#term-rewriting-macros-parameters">Parameters</a></li>
- <li><a class="reference" id="term-rewriting-macros-norewrite-pragma_toc" href="#term-rewriting-macros-norewrite-pragma">noRewrite pragma</a></li>
- <li><a class="reference" id="term-rewriting-macros-examplecolon-partial-evaluation_toc" href="#term-rewriting-macros-examplecolon-partial-evaluation">Example: Partial evaluation</a></li>
- <li><a class="reference" id="term-rewriting-macros-examplecolon-hoisting_toc" href="#term-rewriting-macros-examplecolon-hoisting">Example: Hoisting</a></li>
- </ul><li><a class="reference" id="ast-based-overloading_toc" href="#ast-based-overloading">AST based overloading</a></li>
- <li><a class="reference" id="parallel-amp-spawn_toc" href="#parallel-amp-spawn">Parallel & Spawn</a></li>
- <ul class="simple"><li><a class="reference" id="parallel-amp-spawn-spawn-statement_toc" href="#parallel-amp-spawn-spawn-statement">Spawn statement</a></li>
- <li><a class="reference" id="parallel-amp-spawn-parallel-statement_toc" href="#parallel-amp-spawn-parallel-statement">Parallel statement</a></li>
- </ul><li><a class="reference" id="strict-case-objects_toc" href="#strict-case-objects">Strict case objects</a></li>
- <li><a class="reference" id="quirky-routines_toc" href="#quirky-routines">Quirky routines</a></li>
- <li><a class="reference" id="threading-under-arcslashorc_toc" href="#threading-under-arcslashorc">Threading under ARC/ORC</a></li>
- <ul class="simple"><li><a class="reference" id="threading-under-arcslashorc-isolation_toc" href="#threading-under-arcslashorc-isolation">Isolation</a></li>
- <li><a class="reference" id="threading-under-arcslashorc-alias-analysis_toc" href="#threading-under-arcslashorc-alias-analysis">Alias analysis</a></li>
- <li><a class="reference" id="threading-under-arcslashorc-sendable-pragma_toc" href="#threading-under-arcslashorc-sendable-pragma">Sendable pragma</a></li>
- </ul><li><a class="reference" id="virtual-pragma_toc" href="#virtual-pragma">Virtual pragma</a></li>
- <li><a class="reference" id="constructor-pragma_toc" href="#constructor-pragma">Constructor pragma</a></li>
- <li><a class="reference" id="constructor-initializer_toc" href="#constructor-initializer">Constructor Initializer</a></li>
- <li><a class="reference" id="member-pragma_toc" href="#member-pragma">Member pragma</a></li>
- <li><a class="reference" id="injected-symbols-in-generic-procs-and-templates_toc" href="#injected-symbols-in-generic-procs-and-templates">Injected symbols in generic procs and templates</a></li>
- <li><a class="reference" id="vtable-for-methods_toc" href="#vtable-for-methods">VTable for methods</a></li>
- <li><a class="reference" id="asmsyntax-pragma_toc" href="#asmsyntax-pragma">asmSyntax pragma</a></li>
- <li><a class="reference" id="typeminusbound-overloads_toc" href="#typeminusbound-overloads">Type-bound overloads</a></li>
- </ul>
- </div>
- <div class="nine columns" id="content">
- <a href="https://github.com/nim-lang/Nim/tree/devel/doc/manual_experimental.md#L1" class="link-seesrc" target="_blank">Source</a>
- <a href="https://github.com/nim-lang/Nim/edit/devel/doc/manual_experimental.md#L1" class="link-seesrc" target="_blank" >Edit</a>
- <div id="tocRoot"></div>
-
- <p class="module-desc"><table class="docinfo" frame="void" rules="none"><col class="docinfo-name" /><col class="docinfo-content" /><tbody valign="top"><tr><th class="docinfo-name">Authors:</th><td>Andreas Rumpf</td></tr>
- <tr><th class="docinfo-name">Version:</th><td>2.3.1</td></tr>
- </tbody></table>
- <h1><a class="toc-backref" id="about-this-document" href="#about-this-document">About this document</a></h1><p>This document describes features of Nim that are to be considered experimental. Some of these are not covered by the <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">experimental</span></span></tt> pragma or <tt class="docutils literal"><span class="pre option">--experimental</span></tt> switch because they are already behind a special syntax and one may want to use Nim libraries using these features without using them oneself.</p>
- <div class="admonition admonition-info"><span class="admonition-info-text"><b>Note:</b></span>
- Unless otherwise indicated, these features are not to be removed, but refined and overhauled.</div>
- <h1><a class="toc-backref" id="void-type" href="#void-type">Void type</a></h1><p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt> type denotes the absence of any value, i.e. it is the type that contains no values. Consequently, no value can be provided for parameters of type <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt>, and no value can be returned from a function with return type <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt>:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">nothing</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">void</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">void</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"ha"</span>
- <span class="Identifier">nothing</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># writes "ha" to stdout</span></pre></p>
- <p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt> type is particularly useful for generic code:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">callProc</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">p</span><span class="Punctuation">:</span> <span class="Keyword">proc</span> <span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">T</span><span class="Punctuation">)</span><span class="Punctuation">,</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">T</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">when</span> <span class="Identifier">T</span> <span class="Keyword">is</span> <span class="Identifier">void</span><span class="Punctuation">:</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Keyword">else</span><span class="Punctuation">:</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">intProc</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Keyword">discard</span>
- <span class="Keyword">proc</span> <span class="Identifier">emptyProc</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Keyword">discard</span>
- <span class="Identifier">callProc</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">intProc</span><span class="Punctuation">,</span> <span class="DecNumber">12</span><span class="Punctuation">)</span>
- <span class="Identifier">callProc</span><span class="Punctuation">[</span><span class="Identifier">void</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">emptyProc</span><span class="Punctuation">)</span></pre></p>
- <p>However, a <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt> type cannot be inferred in generic code:</p>
- <p><pre class="listing"><span class="Identifier">callProc</span><span class="Punctuation">(</span><span class="Identifier">emptyProc</span><span class="Punctuation">)</span>
- <span class="Comment"># Error: type mismatch: got (proc ())</span>
- <span class="Comment"># but expected one of:</span>
- <span class="Comment"># callProc(p: proc (T), x: T)</span></pre></p>
- <p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt> type is only valid for parameters and return types; other symbols cannot have the type <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt>.</p>
- <h1><a class="toc-backref" id="generic-nimdefine-pragma" href="#generic-nimdefine-pragma">Generic <tt class="docutils literal"><span class="pre"><span class="Identifier">define</span></span></tt> pragma</a></h1><p>Aside the <a class="reference external" href="manual.html#implementation-specific-pragmas-compileminustime-define-pragmas">typed define pragmas for constants</a>, there is a generic <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">define</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt> pragma that interprets the value of the define based on the type of the constant value.</p>
- <p><pre class="listing"><span class="Keyword">const</span> <span class="Identifier">foo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">define</span><span class="Punctuation">:</span> <span class="StringLit">"package.foo"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="DecNumber">123</span>
- <span class="Keyword">const</span> <span class="Identifier">bar</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">define</span><span class="Punctuation">:</span> <span class="StringLit">"package.bar"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Identifier">false</span></pre></p>
- <p><pre class="listing"><span class="program">nim</span> <span class="option">c</span> <span class="Identifier">-d:package.foo=456</span> <span class="Identifier">-d:package.bar</span> <span class="Identifier">foobar.nim</span></pre></p>
- <p>The following types are supported:</p>
- <ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">cstring</span></span></tt></li>
- <li>Signed and unsigned integer types</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">bool</span></span></tt></li>
- <li>Enums</li>
- </ul>
- <h1><a class="toc-backref" id="topminusdown-type-inference" href="#topminusdown-type-inference">Top-down type inference</a></h1><p>In expressions such as:</p>
- <p><pre class="listing"><span class="Keyword">let</span> <span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">T</span> <span class="Operator">=</span> <span class="Identifier">ex</span></pre></p>
- <p>Normally, the compiler type checks the expression <tt class="docutils literal"><span class="pre"><span class="Identifier">ex</span></span></tt> by itself, then attempts to statically convert the type-checked expression to the given type <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> as much as it can, while making sure it matches the type. The extent of this process is limited however due to the expression usually having an assumed type that might clash with the given type.</p>
- <p>With top-down type inference, the expression is type checked with the extra knowledge that it is supposed to be of type <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>. For example, the following code is does not compile with the former method, but compiles with top-down type inference:</p>
- <p><pre class="listing"><span class="Keyword">let</span> <span class="Identifier">foo</span><span class="Punctuation">:</span> <span class="Punctuation">(</span><span class="Identifier">float</span><span class="Punctuation">,</span> <span class="Identifier">uint8</span><span class="Punctuation">,</span> <span class="Identifier">cstring</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Punctuation">(</span><span class="DecNumber">1</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">,</span> <span class="StringLit">"abc"</span><span class="Punctuation">)</span></pre></p>
- <p>The tuple expression has an expected type of <tt class="docutils literal"><span class="pre"><span class="Punctuation">(</span><span class="Identifier">float</span><span class="Punctuation">,</span> <span class="Identifier">uint8</span><span class="Punctuation">,</span> <span class="Identifier">cstring</span><span class="Punctuation">)</span></span></tt>. Since it is a tuple literal, we can use this information to assume the types of its elements. The expected types for the expressions <tt class="docutils literal"><span class="pre"><span class="DecNumber">1</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="DecNumber">2</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="StringLit">"abc"</span></span></tt> are respectively <tt class="docutils literal"><span class="pre"><span class="Identifier">float</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">uint8</span></span></tt>, and <tt class="docutils literal"><span class="pre"><span class="Identifier">cstring</span></span></tt>; and these expressions can be statically converted to these types.</p>
- <p>Without this information, the type of the tuple expression would have been assumed to be <tt class="docutils literal"><span class="pre"><span class="Punctuation">(</span><span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">string</span><span class="Punctuation">)</span></span></tt>. Thus the type of the tuple expression would not match the type of the variable, and an error would be given.</p>
- <p>The extent of this varies, but there are some notable special cases.</p>
- <h2><a class="toc-backref" id="topminusdown-type-inference-inferred-generic-parameters" href="#topminusdown-type-inference-inferred-generic-parameters">Inferred generic parameters</a></h2><p>In expressions making use of generic procs or templates, the expected (unbound) types are often able to be inferred based on context. This feature has to be enabled via <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"inferGenericTypes"</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt></p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"inferGenericTypes"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">options</span>
- <span class="Keyword">var</span> <span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">newSeq</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="DecNumber">1</span><span class="Punctuation">)</span>
- <span class="Comment"># Do some work on 'x'...</span>
- <span class="Comment"># Works!</span>
- <span class="Comment"># 'x' is 'seq[int]' so 'newSeq[int]' is implied</span>
- <span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">newSeq</span><span class="Punctuation">(</span><span class="DecNumber">10</span><span class="Punctuation">)</span>
- <span class="Comment"># Works!</span>
- <span class="Comment"># 'T' of 'none' is bound to the 'T' of 'noneProducer', passing it along.</span>
- <span class="Comment"># Effectively 'none.T = noneProducer.T'</span>
- <span class="Keyword">proc</span> <span class="Identifier">noneProducer</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">none</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Keyword">let</span> <span class="Identifier">myNone</span> <span class="Operator">=</span> <span class="Identifier">noneProducer</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Comment"># Also works</span>
- <span class="Comment"># 'myOtherNone' binds its 'T' to 'float' and 'noneProducer' inherits it</span>
- <span class="Comment"># noneProducer.T = myOtherNone.T</span>
- <span class="Keyword">let</span> <span class="Identifier">myOtherNone</span><span class="Punctuation">:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">float</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">noneProducer</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Comment"># Works as well</span>
- <span class="Comment"># none.T = myOtherOtherNone.T</span>
- <span class="Keyword">let</span> <span class="Identifier">myOtherOtherNone</span><span class="Punctuation">:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">none</span><span class="Punctuation">(</span><span class="Punctuation">)</span></pre></p>
- <p>This is achieved by reducing the types on the lhs and rhs until the <em>lhs</em> is left with only types such as <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>. While lhs and rhs are reduced together, this does <em>not</em> mean that the <em>rhs</em> will also only be left with a flat type <tt class="docutils literal"><span class="pre"><span class="Identifier">Z</span></span></tt>, it may be of the form <tt class="docutils literal"><span class="pre"><span class="Identifier">MyType</span><span class="Punctuation">[</span><span class="Identifier">Z</span><span class="Punctuation">]</span></span></tt>.</p>
- <p>After the types have been reduced, the types <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> are bound to the types that are left on the rhs.</p>
- <p>If bindings <em>cannot be inferred</em>, compilation will fail and manual specification is required.</p>
- <p>An example for <em>failing inference</em> can be found when passing a generic expression to a function/template call:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"inferGenericTypes"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">myProc</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">T</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Keyword">discard</span>
- <span class="Comment"># Fails! Unable to infer that 'T' is supposed to be 'int'</span>
- <span class="Identifier">myProc</span><span class="Punctuation">(</span><span class="Identifier">newSeq</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span> <span class="Identifier">newSeq</span><span class="Punctuation">(</span><span class="DecNumber">1</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Comment"># Works! Manual specification of 'T' as 'int' necessary</span>
- <span class="Identifier">myProc</span><span class="Punctuation">(</span><span class="Identifier">newSeq</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span> <span class="Identifier">newSeq</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="DecNumber">1</span><span class="Punctuation">)</span><span class="Punctuation">)</span></pre></p>
- <p>Combination of generic inference with the <tt class="docutils literal"><span class="pre"><span class="Identifier">auto</span></span></tt> type is also unsupported:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"inferGenericTypes"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">produceValue</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">:</span> <span class="Identifier">auto</span> <span class="Operator">=</span> <span class="Identifier">default</span><span class="Punctuation">(</span><span class="Identifier">T</span><span class="Punctuation">)</span>
- <span class="Keyword">let</span> <span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">produceValue</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># 'auto' cannot be inferred here</span></pre></p>
- <p><strong>Note</strong>: The described inference does not permit the creation of overrides based on the return type of a procedure. It is a mapping mechanism that does not attempt to perform deeper inference, nor does it modify what is a valid override.</p>
- <p><pre class="listing"><span class="Comment"># Doesn't affect the following code, it is invalid either way</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"inferGenericTypes"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="DecNumber">0</span>
- <span class="Keyword">proc</span> <span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">float</span> <span class="Operator">=</span> <span class="FloatNumber">1.0</span> <span class="Comment"># Fails! Invalid code and not recommended</span></pre></p>
- <h2><a class="toc-backref" id="topminusdown-type-inference-sequence-literals" href="#topminusdown-type-inference-sequence-literals">Sequence literals</a></h2><p>Top-down type inference applies to sequence literals.</p>
- <p><pre class="listing"><span class="Keyword">let</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">float</span><span class="Punctuation">]</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="Operator">@</span><span class="Punctuation">[</span><span class="DecNumber">1</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">,</span> <span class="DecNumber">3</span><span class="Punctuation">]</span><span class="Punctuation">,</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="DecNumber">5</span><span class="Punctuation">,</span> <span class="DecNumber">6</span><span class="Punctuation">]</span><span class="Punctuation">]</span></pre></p>
- <p>This behavior is tied to the <tt class="docutils literal"><span class="pre"><span class="Operator">@</span></span></tt> overloads in the <tt class="docutils literal"><span class="pre"><span class="Identifier">system</span></span></tt> module, so overloading <tt class="docutils literal"><span class="pre"><span class="Operator">@</span></span></tt> can disable this behavior. This can be circumvented by specifying the `` system.<tt class="docutils literal"><span class="pre"><span class="Operator">@</span></span></tt> `` overload.</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">@</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span> <span class="StringLit">"@"</span> <span class="Operator">&</span> <span class="Identifier">x</span>
- <span class="Comment"># does not compile:</span>
- <span class="Keyword">let</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">float</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="DecNumber">1</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">,</span> <span class="DecNumber">3</span><span class="Punctuation">]</span>
- <span class="Comment"># compiles:</span>
- <span class="Keyword">let</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">float</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">system</span><span class="Operator">.</span><span class="Punctuation">`</span><span class="Operator">@</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Punctuation">[</span><span class="DecNumber">1</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">,</span> <span class="DecNumber">3</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre></p>
- <h1><a class="toc-backref" id="package-level-objects" href="#package-level-objects">Package level objects</a></h1><p>Every Nim module resides in a (nimble) package. An object type can be attached to the package it resides in. If that is done, the type can be referenced from other modules as an <span id="incomplete_1">incomplete</span> object type. This feature allows to break up recursive type dependencies across module boundaries. Incomplete object types are always passed <tt class="docutils literal"><span class="pre"><span class="Identifier">byref</span></span></tt> and can only be used in pointer like contexts (<tt class="docutils literal"><span class="pre"><span class="Keyword">var</span><span class="Operator">/</span><span class="Keyword">ref</span><span class="Operator">/</span><span class="Keyword">ptr</span> <span class="Identifier">IncompleteObject</span></span></tt>) in general, since the compiler does not yet know the size of the object. To complete an incomplete object, the <tt class="docutils literal"><span class="pre"><span class="Identifier">package</span></span></tt> pragma has to be used. <tt class="docutils literal"><span class="pre"><span class="Identifier">package</span></span></tt> implies <tt class="docutils literal"><span class="pre"><span class="Identifier">byref</span></span></tt>.</p>
- <p>As long as a type <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is incomplete, no runtime type information for <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is available.</p>
- <p>Example:</p>
- <p><pre class="listing"><span class="Comment"># module A (in an arbitrary package)</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Pack</span><span class="Operator">.</span><span class="Identifier">SomeObject</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Comment"># declare as incomplete object of package 'Pack'</span>
- <span class="Identifier">Triple</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">,</span> <span class="Identifier">c</span><span class="Punctuation">:</span> <span class="Keyword">ref</span> <span class="Identifier">SomeObject</span> <span class="Comment"># pointers to incomplete objects are allowed</span>
- <span class="Comment"># Incomplete objects can be used as parameters:</span>
- <span class="Keyword">proc</span> <span class="Identifier">myproc</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">SomeObject</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Keyword">discard</span></pre></p>
- <p><pre class="listing"><span class="Comment"># module B (in package "Pack")</span>
- <span class="Keyword">type</span>
- <span class="Identifier">SomeObject</span><span class="Operator">*</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">package</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Comment"># Use 'package' to complete the object</span>
- <span class="Identifier">s</span><span class="Punctuation">,</span> <span class="Identifier">t</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
- <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">int</span></pre></p>
- <p>This feature will likely be superseded in the future by support for recursive module dependencies.</p>
- <h1><a class="toc-backref" id="importing-private-symbols" href="#importing-private-symbols">Importing private symbols</a></h1><p>In some situations, it may be useful to import all symbols (public or private) from a module. The syntax <tt class="docutils literal"><span class="pre"><span class="Keyword">import</span> <span class="Identifier">foo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">all</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt> can be used to import all symbols from the module <tt class="docutils literal"><span class="pre"><span class="Identifier">foo</span></span></tt>. Note that importing private symbols is generally not recommended.</p>
- <p>See also the experimental <a class="reference external" href="importutils.html">importutils</a> module.</p>
- <h1><a class="toc-backref" id="code-reordering" href="#code-reordering">Code reordering</a></h1><p>The code reordering feature can implicitly rearrange procedure, template, and macro definitions along with variable declarations and initializations at the top level scope so that, to a large extent, a programmer should not have to worry about ordering definitions correctly or be forced to use forward declarations to preface definitions inside a module.</p>
- <p>Example:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"codeReordering"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">bar</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">bar</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">10</span><span class="Punctuation">)</span></pre></p>
- <p>Variables can also be reordered as well. Variables that are <em>initialized</em> (i.e. variables that have their declaration and assignment combined in a single statement) can have their entire initialization statement reordered. Be wary of what code is executed at the top level:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"codeReordering"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">a</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span><span class="Punctuation">(</span><span class="Identifier">foo</span><span class="Punctuation">)</span>
- <span class="Keyword">var</span> <span class="Identifier">foo</span> <span class="Operator">=</span> <span class="DecNumber">5</span>
- <span class="Identifier">a</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># outputs: "5"</span></pre></p>
- <p>It is important to note that reordering <em>only</em> works for symbols at top level scope. Therefore, the following will <em>fail to compile:</em></p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"codeReordering"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">a</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">b</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">b</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span><span class="Punctuation">(</span><span class="StringLit">"Hello!"</span><span class="Punctuation">)</span>
- <span class="Identifier">a</span><span class="Punctuation">(</span><span class="Punctuation">)</span></pre></p>
- <p>This feature will likely be replaced with a better solution to remove the need for forward declarations.</p>
- <h1><a class="toc-backref" id="special-operators" href="#special-operators">Special Operators</a></h1>
- <h2><a class="toc-backref" id="special-operators-dot-operators" href="#special-operators-dot-operators">dot operators</a></h2><div class="admonition admonition-info"><span class="admonition-info-text"><b>Note:</b></span>
- Dot operators are still experimental and so need to be enabled via <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"dotOperators"</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt>.</div>
- <p>Nim offers a special family of dot operators that can be used to intercept and rewrite proc call and field access attempts, referring to previously undeclared symbol names. They can be used to provide a fluent interface to objects lying outside the static confines of the type system such as values from dynamic scripting languages or dynamic file formats such as JSON or XML.</p>
- <p>When Nim encounters an expression that cannot be resolved by the standard overload resolution rules, the current scope will be searched for a dot operator that can be matched against a re-written form of the expression, where the unknown field or proc name is passed to an <tt class="docutils literal"><span class="pre"><span class="Identifier">untyped</span></span></tt> parameter:</p>
- <p><pre class="listing"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span> <span class="Comment"># becomes `.`(a, b)</span>
- <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span><span class="Punctuation">(</span><span class="Identifier">c</span><span class="Punctuation">,</span> <span class="Identifier">d</span><span class="Punctuation">)</span> <span class="Comment"># becomes `.`(a, b, c, d)</span></pre></p>
- <p>The matched dot operators can be symbols of any callable kind (procs, templates and macros), depending on the desired effect:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Punctuation">`</span><span class="Operator">.</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">js</span><span class="Punctuation">:</span> <span class="Identifier">PJsonNode</span><span class="Punctuation">,</span> <span class="Identifier">field</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">JSON</span> <span class="Operator">=</span> <span class="Identifier">js</span><span class="Punctuation">[</span><span class="Identifier">astToStr</span><span class="Punctuation">(</span><span class="Identifier">field</span><span class="Punctuation">)</span><span class="Punctuation">]</span>
- <span class="Keyword">var</span> <span class="Identifier">js</span> <span class="Operator">=</span> <span class="Identifier">parseJson</span><span class="Punctuation">(</span><span class="StringLit">"{ x: 1, y: 2}"</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="Identifier">js</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Comment"># outputs 1</span>
- <span class="Identifier">echo</span> <span class="Identifier">js</span><span class="Operator">.</span><span class="Identifier">y</span> <span class="Comment"># outputs 2</span></pre></p>
- <p>The following dot operators are available:</p>
- <h2><a class="toc-backref" id="special-operators-operator-nimdot" href="#special-operators-operator-nimdot">operator <tt class="docutils literal"><span class="pre"><span class="Operator">.</span></span></tt></a></h2><p>This operator will be matched against both field accesses and method calls.</p>
- <h2><a class="toc-backref" id="special-operators-operator-nimdot" href="#special-operators-operator-nimdot">operator <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt></a></h2><p>This operator will be matched exclusively against method calls. It has higher precedence than the <tt class="docutils literal"><span class="pre"><span class="Operator">.</span></span></tt> operator and this allows one to handle expressions like <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">y</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">y</span><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt> differently if one is interfacing with a scripting language for example.</p>
- <h2><a class="toc-backref" id="special-operators-operator-nimdoteq" href="#special-operators-operator-nimdoteq">operator <tt class="docutils literal"><span class="pre"><span class="Operator">.=</span></span></tt></a></h2><p>This operator will be matched against assignments to missing fields.</p>
- <p><pre class="listing"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span> <span class="Operator">=</span> <span class="Identifier">c</span> <span class="Comment"># becomes `.=`(a, b, c)</span></pre></p>
- <h2><a class="toc-backref" id="special-operators-call-operator" href="#special-operators-call-operator">Call operator</a></h2><p>The call operator, <tt class="docutils literal"><span class="pre"><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt>, matches all kinds of unresolved calls and takes precedence over dot operators, however it does not match missing overloads for existing routines. The experimental <tt class="docutils literal"><span class="pre"><span class="Identifier">callOperator</span></span></tt> switch must be enabled to use this operator.</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"callOperator"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">template</span> <span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">float</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="Operator">$</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">)</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Keyword">let</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="FloatNumber">1.0</span>
- <span class="Keyword">let</span> <span class="Identifier">b</span> <span class="Operator">=</span> <span class="DecNumber">2</span>
- <span class="Identifier">doAssert</span> <span class="Identifier">b</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">,</span> <span class="Identifier">a</span><span class="Punctuation">)</span>
- <span class="Identifier">doAssert</span> <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span> <span class="Operator">==</span> <span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">,</span> <span class="Identifier">a</span><span class="Punctuation">)</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Keyword">let</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="FloatNumber">1.0</span>
- <span class="Keyword">proc</span> <span class="Identifier">b</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="DecNumber">2</span>
- <span class="Identifier">doAssert</span> <span class="Keyword">not</span> <span class="Identifier">compiles</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Identifier">doAssert</span> <span class="Keyword">not</span> <span class="Identifier">compiles</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span><span class="Punctuation">)</span> <span class="Comment"># `()` not called</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Keyword">let</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="FloatNumber">1.0</span>
- <span class="Keyword">proc</span> <span class="Identifier">b</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">float</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">int</span><span class="Punctuation">(</span><span class="Identifier">x</span> <span class="Operator">+</span> <span class="DecNumber">1</span><span class="Punctuation">)</span>
- <span class="Keyword">let</span> <span class="Identifier">c</span> <span class="Operator">=</span> <span class="FloatNumber">3.0</span>
-
- <span class="Identifier">doAssert</span> <span class="Keyword">not</span> <span class="Identifier">compiles</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span><span class="Punctuation">(</span><span class="Identifier">c</span><span class="Punctuation">)</span><span class="Punctuation">)</span> <span class="Comment"># gives a type mismatch error same as b(a, c)</span>
- <span class="Identifier">doAssert</span> <span class="Punctuation">(</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span><span class="Punctuation">)</span><span class="Punctuation">(</span><span class="Identifier">c</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">b</span><span class="Punctuation">,</span> <span class="Identifier">c</span><span class="Punctuation">)</span></pre></p>
- <h1><a class="toc-backref" id="extended-macro-pragmas" href="#extended-macro-pragmas">Extended macro pragmas</a></h1><p>Macro pragmas as described in <a class="reference external" href="manual.html#userminusdefined-pragmas-macro-pragmas">the manual</a> can also be applied to type, variable and constant declarations.</p>
- <p>For types:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">MyObject</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">schema</span><span class="Punctuation">:</span> <span class="StringLit">"schema.protobuf"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span></pre></p>
- <p>This is translated to a call to the <tt class="docutils literal"><span class="pre"><span class="Identifier">schema</span></span></tt> macro with a <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkTypeDef</span></span></tt> AST node capturing the left-hand side, remaining pragmas and the right-hand side of the definition. The macro can return either a type section or another <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkTypeDef</span></span></tt> node, both of which will replace the original row in the type section.</p>
- <p>In the future, this <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkTypeDef</span></span></tt> argument may be replaced with a unary type section node containing the type definition, or some other node that may be more convenient to work with. The ability to return nodes other than type definitions may also be supported, however currently this is not convenient when dealing with mutual type recursion. For now, macros can return an unused type definition where the right-hand node is of kind <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkStmtListType</span></span></tt>. Declarations in this node will be attached to the same scope as the parent scope of the type section.</p>
- <hr />
- <p>For variables and constants, it is largely the same, except a unary node with the same kind as the section containing a single definition is passed to macros, and macros can return any expression.</p>
- <p><pre class="listing"><span class="Keyword">var</span>
- <span class="Identifier">a</span> <span class="Operator">=</span> <span class="Operator">...</span>
- <span class="Identifier">b</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importc</span><span class="Punctuation">,</span> <span class="Identifier">foo</span><span class="Punctuation">,</span> <span class="Identifier">nodecl</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Operator">...</span>
- <span class="Identifier">c</span> <span class="Operator">=</span> <span class="Operator">...</span></pre></p>
- <p>Assuming <tt class="docutils literal"><span class="pre"><span class="Identifier">foo</span></span></tt> is a macro or a template, this is roughly equivalent to:</p>
- <p><pre class="listing"><span class="Keyword">var</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="Operator">...</span>
- <span class="Identifier">foo</span><span class="Punctuation">:</span>
- <span class="Keyword">var</span> <span class="Identifier">b</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importc</span><span class="Punctuation">,</span> <span class="Identifier">nodecl</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Operator">...</span>
- <span class="Keyword">var</span> <span class="Identifier">c</span> <span class="Operator">=</span> <span class="Operator">...</span></pre></p>
- <h1><a class="toc-backref" id="symbols-as-templateslashmacro-calls-alias-syntax" href="#symbols-as-templateslashmacro-calls-alias-syntax">Symbols as template/macro calls (alias syntax)</a></h1><p>Templates and macros that have no generic parameters and no required arguments can be called as lone symbols, i.e. without parentheses. This is useful for repeated uses of complex expressions that cannot conveniently be represented as runtime values.</p>
- <p><pre class="listing"><span class="Keyword">type</span> <span class="Identifier">Foo</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">bar</span><span class="Punctuation">:</span> <span class="Identifier">int</span>
- <span class="Keyword">var</span> <span class="Identifier">foo</span> <span class="Operator">=</span> <span class="Identifier">Foo</span><span class="Punctuation">(</span><span class="Identifier">bar</span><span class="Punctuation">:</span> <span class="DecNumber">10</span><span class="Punctuation">)</span>
- <span class="Keyword">template</span> <span class="Identifier">bar</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">foo</span><span class="Operator">.</span><span class="Identifier">bar</span>
- <span class="Identifier">assert</span> <span class="Identifier">bar</span> <span class="Operator">==</span> <span class="DecNumber">10</span>
- <span class="Identifier">bar</span> <span class="Operator">=</span> <span class="DecNumber">15</span>
- <span class="Identifier">assert</span> <span class="Identifier">bar</span> <span class="Operator">==</span> <span class="DecNumber">15</span></pre></p>
- <h1><a class="toc-backref" id="not-nil-annotation" href="#not-nil-annotation">Not nil annotation</a></h1><p><strong>Note:</strong> This is an experimental feature. It can be enabled with <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"notnil"</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt>.</p>
- <p>All types for which <tt class="docutils literal"><span class="pre"><span class="Keyword">nil</span></span></tt> is a valid value can be annotated with the <tt class="docutils literal"><span class="pre"><span class="Keyword">not</span> <span class="Keyword">nil</span></span></tt> annotation to exclude <tt class="docutils literal"><span class="pre"><span class="Keyword">nil</span></span></tt> as a valid value. Note that only local symbols are checked.</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"notnil"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">TObj</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">PObject</span> <span class="Operator">=</span> <span class="Keyword">ref</span> <span class="Identifier">TObj</span> <span class="Keyword">not</span> <span class="Keyword">nil</span>
- <span class="Identifier">TProc</span> <span class="Operator">=</span> <span class="Punctuation">(</span><span class="Keyword">proc</span> <span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">)</span> <span class="Keyword">not</span> <span class="Keyword">nil</span>
- <span class="Keyword">proc</span> <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">PObject</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"not nil"</span>
- <span class="Comment"># compiler catches this:</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Keyword">nil</span><span class="Punctuation">)</span>
- <span class="Comment"># and also this:</span>
- <span class="Keyword">proc</span> <span class="Identifier">foo</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">PObject</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Punctuation">)</span></pre></p>
- <p>The compiler ensures that every code path initializes variables which contain non-nilable pointers. The details of this analysis are still to be specified here.</p>
- <h1><a class="toc-backref" id="strict-not-nil-checking" href="#strict-not-nil-checking">Strict not nil checking</a></h1><p><strong>Note:</strong> This feature is experimental, you need to enable it with</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"strictNotNil"</span><span class="Operator">.</span><span class="Punctuation">}</span></pre></p>
- <p>or</p>
- <p><pre class="listing"><span class="program">nim</span> <span class="option">c</span> <span class="option">--experimental:strictNotNil</span> <span class="option"><program></span></pre></p>
- <p>In the second case it would check builtin and imported modules as well.</p>
- <p>It checks the nilability of ref-like types and makes dereferencing safer based on flow typing and <tt class="docutils literal"><span class="pre"><span class="Keyword">not</span> <span class="Keyword">nil</span></span></tt> annotations.</p>
- <p>Its implementation is different than the <tt class="docutils literal"><span class="pre"><span class="Identifier">notnil</span></span></tt> one: defined under <tt class="docutils literal"><span class="pre"><span class="Identifier">strictNotNil</span></span></tt>. Keep in mind the difference in option names, be careful with distinguishing them.</p>
- <p>We check several kinds of types for nilability:</p>
- <ul class="simple"><li>ref types</li>
- <li>pointer types</li>
- <li>proc types</li>
- <li>cstrings</li>
- </ul>
- <h2><a class="toc-backref" id="strict-not-nil-checking-nil" href="#strict-not-nil-checking-nil">nil</a></h2><p>The default kind of nilability types is the nilable kind: they can have the value <tt class="docutils literal"><span class="pre"><span class="Keyword">nil</span></span></tt>. If you have a non-nilable type <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>, you can use <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span> <span class="Keyword">nil</span></span></tt> to get a nilable type for it.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-not-nil" href="#strict-not-nil-checking-not-nil">not nil</a></h2><p>You can annotate a type where nil isn't a valid value with <tt class="docutils literal"><span class="pre"><span class="Keyword">not</span> <span class="Keyword">nil</span></span></tt>.</p>
- <p><pre class="listing"> <span class="Keyword">type</span>
- <span class="Identifier">NilableObject</span> <span class="Operator">=</span> <span class="Keyword">ref</span> <span class="Keyword">object</span>
- <span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span>
- <span class="Keyword">Object</span> <span class="Operator">=</span> <span class="Identifier">NilableObject</span> <span class="Keyword">not</span> <span class="Keyword">nil</span>
-
- <span class="Keyword">Proc</span> <span class="Operator">=</span> <span class="Punctuation">(</span><span class="Keyword">proc</span> <span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
-
- <span class="Keyword">proc</span> <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Keyword">Object</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">a</span> <span class="Comment"># ensured to dereference without an error</span>
- <span class="Comment"># compiler catches this:</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Keyword">nil</span><span class="Punctuation">)</span>
- <span class="Comment"># and also this:</span>
- <span class="Keyword">var</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">NilableObject</span>
- <span class="Keyword">if</span> <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">isNil</span><span class="Punctuation">:</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Keyword">else</span><span class="Punctuation">:</span>
- <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span> <span class="Comment"># ok</span></pre></p>
- <p>If a type can include <tt class="docutils literal"><span class="pre"><span class="Keyword">nil</span></span></tt> as a valid value, dereferencing values of the type is checked by the compiler: if a value which might be nil is dereferenced, this produces a warning by default, you can turn this into an error using the compiler options <tt class="docutils literal"><span class="pre option">--warningAsError:strictNotNil</span></tt>.</p>
- <p>If a type is nilable, you should dereference its values only after a <tt class="docutils literal"><span class="pre"><span class="Identifier">isNil</span></span></tt> or equivalent check.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-local-turn-onslashoff" href="#strict-not-nil-checking-local-turn-onslashoff">local turn on/off</a></h2><p>You can still turn off nil checking on function/module level by using a <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">strictNotNil</span><span class="Punctuation">:</span> <span class="Identifier">off</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt> pragma.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-nilability-state" href="#strict-not-nil-checking-nilability-state">nilability state</a></h2><p>Currently, a nilable value can be <tt class="docutils literal"><span class="pre"><span class="Identifier">Safe</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">Nil</span></span></tt> : we use internally <tt class="docutils literal"><span class="pre"><span class="Identifier">Parent</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">Unreachable</span></span></tt> but this is an implementation detail(a parent layer has the actual nilability).</p>
- <ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">Safe</span></span></tt> means it shouldn't be nil at that point: e.g. after assignment to a non-nil value or <tt class="docutils literal"><span class="pre"><span class="Keyword">not</span> <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">isNil</span></span></tt> check</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt> means it might be nil, but it might not be nil: e.g. an argument, a call argument or a value after an <tt class="docutils literal"><span class="pre"><span class="Keyword">if</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Keyword">else</span></span></tt>.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Keyword">Nil</span></span></tt> means it should be nil at that point; e.g. after an assignment to <tt class="docutils literal"><span class="pre"><span class="Keyword">nil</span></span></tt> or a <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">isNil</span></span></tt> check.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">Unreachable</span></span></tt> means it shouldn't be possible to access this in this branch: so we do generate a warning as well.</li>
- </ul>
- <p>We show an error for each dereference (<tt class="docutils literal"><span class="pre"><span class="Punctuation">[</span><span class="Punctuation">]</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">field</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Punctuation">[</span><span class="Identifier">index</span><span class="Punctuation">]</span></span></tt> <tt class="docutils literal"><span class="pre"><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt> etc.) which is of a tracked expression which is in <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">Nil</span></span></tt> state.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-type-nilability" href="#strict-not-nil-checking-type-nilability">type nilability</a></h2><p>Types are either nilable or non-nilable. When you pass a param or a default value, we use the type : for nilable types we return <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt> and for non-nilable <tt class="docutils literal"><span class="pre"><span class="Identifier">Safe</span></span></tt>.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-params-rules" href="#strict-not-nil-checking-params-rules">params rules</a></h2><p>Param's nilability is detected based on type nilability. We use the type of the argument to detect the nilability.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-assignment-rules" href="#strict-not-nil-checking-assignment-rules">assignment rules</a></h2><p>Let's say we have <tt class="docutils literal"><span class="pre"><span class="Identifier">left</span> <span class="Operator">=</span> <span class="Identifier">right</span></span></tt>.</p>
- <p>When we assign, we pass the right's nilability to the left's expression. There should be special handling of aliasing and compound expressions which we specify in their sections. (Assignment is a possible alias <tt class="docutils literal"><span class="pre"><span class="Identifier">move</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Identifier">move</span> <span class="Keyword">out</span></span></tt>).</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-call-args-rules" href="#strict-not-nil-checking-call-args-rules">call args rules</a></h2><p>When we call with arguments, we have two cases when we might change the nilability.</p>
- <p><pre class="listing"><span class="Identifier">callByVar</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span></pre></p>
- <p>Here <tt class="docutils literal"><span class="pre"><span class="Identifier">callByVar</span></span></tt> can re-assign <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt>, so this might change <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt>'s nilability, so we change it to <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt>. This is also a possible aliasing <tt class="docutils literal"><span class="pre"><span class="Identifier">move</span> <span class="Keyword">out</span></span></tt> (moving out of a current alias set).</p>
- <p><pre class="listing"><span class="Identifier">call</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span></pre></p>
- <p>Here <tt class="docutils literal"><span class="pre"><span class="Identifier">call</span></span></tt> can change a field or element of <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt>, so if we have a dependant expression of <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt> : e.g. <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">field</span></span></tt>. Dependants become <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt>.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-branches-rules" href="#strict-not-nil-checking-branches-rules">branches rules</a></h2><p>Branches are the reason we do nil checking like this: with flow checking. Sources of branching are <tt class="docutils literal"><span class="pre"><span class="Keyword">if</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">while</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">for</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">and</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">or</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">case</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">try</span></span></tt> and combinations with <tt class="docutils literal"><span class="pre"><span class="Keyword">return</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">break</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">continue</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Keyword">raise</span></span></tt></p>
- <p>We create a new layer/"scope" for each branch where we map expressions to nilability. This happens when we "fork": usually on the beginning of a construct. When branches "join" we usually unify their expression maps or/and nilabilities.</p>
- <p>Merging usually merges maps and alias sets: nilabilities are merged like this:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">union</span><span class="Punctuation">(</span><span class="Identifier">l</span><span class="Punctuation">:</span> <span class="Identifier">Nilability</span><span class="Punctuation">,</span> <span class="Identifier">r</span><span class="Punctuation">:</span> <span class="Identifier">Nilability</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Nilability</span> <span class="Operator">=</span>
- <span class="Comment">## unify two states</span>
- <span class="Keyword">if</span> <span class="Identifier">l</span> <span class="Operator">==</span> <span class="Identifier">r</span><span class="Punctuation">:</span>
- <span class="Identifier">l</span>
- <span class="Keyword">else</span><span class="Punctuation">:</span>
- <span class="Identifier">MaybeNil</span></pre></p>
- <p>Special handling is for <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">isNil</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Operator">==</span> <span class="Keyword">nil</span></span></tt>, also for <tt class="docutils literal"><span class="pre"><span class="Keyword">not</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">and</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Keyword">or</span></span></tt>.</p>
- <p><tt class="docutils literal"><span class="pre"><span class="Keyword">not</span></span></tt> reverses the nilability, <tt class="docutils literal"><span class="pre"><span class="Keyword">and</span></span></tt> is similar to "forking" : the right expression is checked in the layer resulting from the left one and <tt class="docutils literal"><span class="pre"><span class="Keyword">or</span></span></tt> is similar to "merging": the right and left expression should be both checked in the original layer.</p>
- <p><tt class="docutils literal"><span class="pre"><span class="Identifier">isNil</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">==</span> <span class="Keyword">nil</span></span></tt> make expressions <tt class="docutils literal"><span class="pre"><span class="Keyword">Nil</span></span></tt>. If there is a <tt class="docutils literal"><span class="pre"><span class="Keyword">not</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Operator">!=</span> <span class="Keyword">nil</span></span></tt>, they make them <tt class="docutils literal"><span class="pre"><span class="Identifier">Safe</span></span></tt>. We also reverse the nilability in the opposite branch: e.g. <tt class="docutils literal"><span class="pre"><span class="Keyword">else</span></span></tt>.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-compound-expressionscolon-field-index-expressions" href="#strict-not-nil-checking-compound-expressionscolon-field-index-expressions">compound expressions: field, index expressions</a></h2><p>We want to track also field(dot) and index(bracket) expressions.</p>
- <p>We track some of those compound expressions which might be nilable as dependants of their bases: <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">field</span></span></tt> is changed if <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt> is moved (re-assigned), similarly <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="Identifier">index</span><span class="Punctuation">]</span></span></tt> is dependent on <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">field</span><span class="Operator">.</span><span class="Identifier">field</span></span></tt> on <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">field</span></span></tt>.</p>
- <p>When we move the base, we update dependants to <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt>. Otherwise, we usually start with type nilability.</p>
- <p>When we call args, we update the nilability of their dependants to <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt> as the calls usually can change them. We might need to check for <tt class="docutils literal"><span class="pre"><span class="Identifier">strictFuncs</span></span></tt> pure funcs and not do that then.</p>
- <p>For field expressions <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">field</span></span></tt>, we calculate an integer value based on a hash of the tree and just accept equivalent trees as equivalent expressions.</p>
- <p>For item expression <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="Identifier">index</span><span class="Punctuation">]</span></span></tt>, we also calculate an integer value based on a hash of the tree and accept equivalent trees as equivalent expressions: for static values only. For now, we support only constant indices: we don't track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">warning</span><span class="Punctuation">[</span><span class="Identifier">StrictNotNil</span><span class="Punctuation">]</span><span class="Punctuation">:</span><span class="Identifier">off</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt>.</p>
- <p>For bracket expressions, in the future we might count <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="Operator"><</span><span class="Identifier">any</span><span class="Operator">></span><span class="Punctuation">]</span></span></tt> as the same general expression. This means we should the index but otherwise handle it the same for assign (maybe "aliasing" all the non-static elements) and differentiate only for static: e.g. <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="DecNumber">0</span><span class="Punctuation">]</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="DecNumber">1</span><span class="Punctuation">]</span></span></tt>.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-element-tracking" href="#strict-not-nil-checking-element-tracking">element tracking</a></h2><p>When we assign an object construction, we should track the fields as well:</p>
- <p><pre class="listing"><span class="Keyword">var</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="Identifier">Nilable</span><span class="Punctuation">(</span><span class="Identifier">field</span><span class="Punctuation">:</span> <span class="Identifier">Nilable</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">)</span> <span class="Comment"># a : Safe, a.field: Safe</span></pre></p>
- <p>Usually we just track the result of an expression: probably this should apply for elements in other cases as well. Also related to tracking initialization of expressions/fields.</p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-unstructured-control-flow-rules" href="#strict-not-nil-checking-unstructured-control-flow-rules">unstructured control flow rules</a></h2><p>Unstructured control flow keywords as <tt class="docutils literal"><span class="pre"><span class="Keyword">return</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">break</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">continue</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">raise</span></span></tt> mean that we jump from a branch out. This means that if there is code after the finishing of the branch, it would be run if one hasn't hit the direct parent branch of those: so it is similar to an <tt class="docutils literal"><span class="pre"><span class="Keyword">else</span></span></tt>. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g.</p>
- <p><pre class="listing"><span class="Keyword">for</span> <span class="Identifier">a</span> <span class="Keyword">in</span> <span class="Identifier">c</span><span class="Punctuation">:</span>
- <span class="Keyword">if</span> <span class="Keyword">not</span> <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">isNil</span><span class="Punctuation">:</span>
- <span class="Identifier">b</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Keyword">break</span>
- <span class="Identifier">code</span> <span class="Comment"># here a: Nil , because if not, we would have breaked</span></pre></p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-aliasing" href="#strict-not-nil-checking-aliasing">aliasing</a></h2><p>We support alias detection for local expressions.</p>
- <p>We track sets of aliased expressions. We start with all nilable local expressions in separate sets. Assignments and other changes to nilability can move / move out expressions of sets.</p>
- <p><tt class="docutils literal"><span class="pre"><span class="Identifier">move</span></span></tt>: Moving <tt class="docutils literal"><span class="pre"><span class="Identifier">left</span></span></tt> to <tt class="docutils literal"><span class="pre"><span class="Identifier">right</span></span></tt> means we remove <tt class="docutils literal"><span class="pre"><span class="Identifier">left</span></span></tt> from its current set and unify it with the <tt class="docutils literal"><span class="pre"><span class="Identifier">right</span></span></tt>'s set. This means it stops being aliased with its previous aliases.</p>
- <p><pre class="listing"><span class="Keyword">var</span> <span class="Identifier">left</span> <span class="Operator">=</span> <span class="Identifier">b</span>
- <span class="Identifier">left</span> <span class="Operator">=</span> <span class="Identifier">right</span> <span class="Comment"># moving left to right</span></pre></p>
- <p><tt class="docutils literal"><span class="pre"><span class="Identifier">move</span> <span class="Keyword">out</span></span></tt>: Moving out <tt class="docutils literal"><span class="pre"><span class="Identifier">left</span></span></tt> might remove it from the current set and ensure that it's in its own set as a single element. e.g.</p>
- <p><pre class="listing"><span class="Keyword">var</span> <span class="Identifier">left</span> <span class="Operator">=</span> <span class="Identifier">b</span>
- <span class="Identifier">left</span> <span class="Operator">=</span> <span class="Keyword">nil</span> <span class="Comment"># moving out</span></pre></p>
- <h2><a class="toc-backref" id="strict-not-nil-checking-warnings-and-errors" href="#strict-not-nil-checking-warnings-and-errors">warnings and errors</a></h2><p>We show an error for each dereference (<tt class="docutils literal"><span class="pre"><span class="Punctuation">[</span><span class="Punctuation">]</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">field</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Punctuation">[</span><span class="Identifier">index</span><span class="Punctuation">]</span></span></tt> <tt class="docutils literal"><span class="pre"><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt> etc.) which is of a tracked expression which is in <tt class="docutils literal"><span class="pre"><span class="Identifier">MaybeNil</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">Nil</span></span></tt> state.</p>
- <p>We might also show a history of the transitions and the reasons for them that might change the nilability of the expression.</p>
- <h1><a class="toc-backref" id="aliasing-restrictions-in-parameter-passing" href="#aliasing-restrictions-in-parameter-passing">Aliasing restrictions in parameter passing</a></h1><div class="admonition admonition-info"><span class="admonition-info-text"><b>Note:</b></span>
- The aliasing restrictions are currently not enforced by the implementation and need to be fleshed out further.</div>
- <p>"Aliasing" here means that the underlying storage locations overlap in memory at runtime. An "output parameter" is a parameter of type <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span> <span class="Identifier">T</span></span></tt>, an input parameter is any parameter that is not of type <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt>.</p>
- <ol class="simple"><li>Two output parameters should never be aliased.</li>
- <li>An input and an output parameter should not be aliased.</li>
- <li>An output parameter should never be aliased with a global or thread local variable referenced by the called proc.</li>
- <li>An input parameter should not be aliased with a global or thread local variable updated by the called proc.</li>
- </ol>
- <p>One problem with rules 3 and 4 is that they affect specific global or thread local variables, but Nim's effect tracking only tracks "uses no global variable" via <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">noSideEffect</span></span></tt>. The rules 3 and 4 can also be approximated by a different rule:</p>
- <ol class="simple" start="5"><li>A global or thread local variable (or a location derived from such a location) can only passed to a parameter of a <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">noSideEffect</span></span></tt> proc.</li>
- </ol>
- <h1><a class="toc-backref" id="strict-funcs" href="#strict-funcs">Strict funcs</a></h1><p>Since version 1.4, a stricter definition of "side effect" is available. In addition to the existing rule that a side effect is calling a function with side effects, the following rule is also enforced:</p>
- <p>A store to the heap via a <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">ptr</span></span></tt> indirection is not allowed.</p>
- <p>For example:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"strictFuncs"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Node</span> <span class="Operator">=</span> <span class="Keyword">ref</span> <span class="Keyword">object</span>
- <span class="Identifier">le</span><span class="Punctuation">,</span> <span class="Identifier">ri</span><span class="Punctuation">:</span> <span class="Identifier">Node</span>
- <span class="Identifier">data</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
- <span class="Keyword">func</span> <span class="Identifier">len</span><span class="Punctuation">(</span><span class="Identifier">n</span><span class="Punctuation">:</span> <span class="Identifier">Node</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span>
- <span class="Comment"># valid: len does not have side effects</span>
- <span class="Keyword">var</span> <span class="Identifier">it</span> <span class="Operator">=</span> <span class="Identifier">n</span>
- <span class="Keyword">while</span> <span class="Identifier">it</span> <span class="Operator">!=</span> <span class="Keyword">nil</span><span class="Punctuation">:</span>
- <span class="Identifier">inc</span> <span class="Identifier">result</span>
- <span class="Identifier">it</span> <span class="Operator">=</span> <span class="Identifier">it</span><span class="Operator">.</span><span class="Identifier">ri</span>
- <span class="Keyword">func</span> <span class="Identifier">mut</span><span class="Punctuation">(</span><span class="Identifier">n</span><span class="Punctuation">:</span> <span class="Identifier">Node</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">it</span> <span class="Operator">=</span> <span class="Identifier">n</span>
- <span class="Keyword">while</span> <span class="Identifier">it</span> <span class="Operator">!=</span> <span class="Keyword">nil</span><span class="Punctuation">:</span>
- <span class="Identifier">it</span><span class="Operator">.</span><span class="Identifier">data</span> <span class="Operator">=</span> <span class="StringLit">"yeah"</span> <span class="Comment"># forbidden mutation</span>
- <span class="Identifier">it</span> <span class="Operator">=</span> <span class="Identifier">it</span><span class="Operator">.</span><span class="Identifier">ri</span>
- </pre></p>
- <h1><a class="toc-backref" id="view-types" href="#view-types">View types</a></h1><div class="admonition admonition-info"><span class="admonition-info-text"><b>Tip:</b></span>
- <tt class="docutils literal"><span class="pre option">--experimental:views</span></tt> is more effective with <tt class="docutils literal"><span class="pre option">--experimental:strictFuncs</span></tt>.</div>
- <p>A view type is a type that is or contains one of the following types:</p>
- <ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">lent</span> <span class="Identifier">T</span></span></tt> (view into <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>)</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> (pair of (pointer to array of <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>, size))</li>
- </ul>
- <p>For example:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">View1</span> <span class="Operator">=</span> <span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">byte</span><span class="Punctuation">]</span>
- <span class="Identifier">View2</span> <span class="Operator">=</span> <span class="Identifier">lent</span> <span class="Identifier">string</span>
- <span class="Identifier">View3</span> <span class="Operator">=</span> <span class="Identifier">Table</span><span class="Punctuation">[</span><span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">char</span><span class="Punctuation">]</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">]</span></pre></p>
- <p>Exceptions to this rule are types constructed via <tt class="docutils literal"><span class="pre"><span class="Keyword">ptr</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">proc</span></span></tt>. For example, the following types are <strong>not</strong> view types:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">NotView1</span> <span class="Operator">=</span> <span class="Keyword">proc</span> <span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
- <span class="Identifier">NotView2</span> <span class="Operator">=</span> <span class="Keyword">ptr</span> <span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">char</span><span class="Punctuation">]</span>
- <span class="Identifier">NotView3</span> <span class="Operator">=</span> <span class="Keyword">ptr</span> <span class="Identifier">array</span><span class="Punctuation">[</span><span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="Identifier">lent</span> <span class="Identifier">int</span><span class="Punctuation">]</span></pre></p>
- <p>The mutability aspect of a view type is not part of the type but part of the locations it's derived from. More on this later.</p>
- <p>A <em>view</em> is a symbol (a let, var, const, etc.) that has a view type.</p>
- <p>Since version 1.4, Nim allows view types to be used as local variables. This feature needs to be enabled via <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"views"</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt>.</p>
- <p>A local variable of a view type <em>borrows</em> from the locations and it is statically enforced that the view does not outlive the location it was borrowed from.</p>
- <p>For example:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"views"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">take</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">len</span>
- <span class="Keyword">proc</span> <span class="Identifier">main</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">openArray</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">s</span> <span class="Comment"># 'x' is a view into 's'</span>
- <span class="Comment"># it is checked that 'x' does not outlive 's' and</span>
- <span class="Comment"># that 's' is not mutated.</span>
- <span class="Keyword">for</span> <span class="Identifier">i</span> <span class="Keyword">in</span> <span class="DecNumber">0</span> <span class="Operator">..</span> <span class="Identifier">high</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Identifier">echo</span> <span class="Identifier">x</span><span class="Punctuation">[</span><span class="Identifier">i</span><span class="Punctuation">]</span>
- <span class="Identifier">take</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
-
- <span class="Identifier">take</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">toOpenArray</span><span class="Punctuation">(</span><span class="DecNumber">0</span><span class="Punctuation">,</span> <span class="DecNumber">1</span><span class="Punctuation">)</span><span class="Punctuation">)</span> <span class="Comment"># slicing remains possible</span>
- <span class="Keyword">let</span> <span class="Identifier">y</span> <span class="Operator">=</span> <span class="Identifier">x</span> <span class="Comment"># create a view from a view</span>
- <span class="Identifier">take</span> <span class="Identifier">y</span>
- <span class="Comment"># it is checked that 'y' does not outlive 'x' and</span>
- <span class="Comment"># that 'x' is not mutated as long as 'y' lives.</span>
- <span class="Identifier">main</span><span class="Punctuation">(</span><span class="Operator">@</span><span class="Punctuation">[</span><span class="DecNumber">11</span><span class="Punctuation">,</span> <span class="DecNumber">22</span><span class="Punctuation">,</span> <span class="DecNumber">33</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre></p>
- <p>A local variable of a view type can borrow from a location derived from a parameter, another local variable, a global <tt class="docutils literal"><span class="pre"><span class="Keyword">const</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt> symbol or a thread-local <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt>.</p>
- <p>Let <tt class="docutils literal"><span class="pre"><span class="Identifier">p</span></span></tt> the proc that is analysed for the correctness of the borrow operation.</p>
- <p>Let <tt class="docutils literal"><span class="pre"><span class="Identifier">source</span></span></tt> be one of:</p>
- <ul class="simple"><li>A formal parameter of <tt class="docutils literal"><span class="pre"><span class="Identifier">p</span></span></tt>. Note that this does not cover parameters of inner procs.</li>
- <li>The <tt class="docutils literal"><span class="pre"><span class="Identifier">result</span></span></tt> symbol of <tt class="docutils literal"><span class="pre"><span class="Identifier">p</span></span></tt>.</li>
- <li>A local <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">const</span></span></tt> of <tt class="docutils literal"><span class="pre"><span class="Identifier">p</span></span></tt>. Note that this does not cover locals of inner procs.</li>
- <li>A thread-local <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt>.</li>
- <li>A global <tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">const</span></span></tt>.</li>
- <li>A constant array/seq/object/tuple constructor.</li>
- </ul>
- <h2><a class="toc-backref" id="view-types-path-expressions" href="#view-types-path-expressions">Path expressions</a></h2><p>A location derived from <tt class="docutils literal"><span class="pre"><span class="Identifier">source</span></span></tt> is then defined as a path expression that has <tt class="docutils literal"><span class="pre"><span class="Identifier">source</span></span></tt> as the owner. A path expression <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span></span></tt> is defined recursively:</p>
- <ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">source</span></span></tt> itself is a path expression.</li>
- <li>Container access like <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span><span class="Punctuation">[</span><span class="Identifier">i</span><span class="Punctuation">]</span></span></tt> is a path expression.</li>
- <li>Tuple access <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span><span class="Punctuation">[</span><span class="DecNumber">0</span><span class="Punctuation">]</span></span></tt> is a path expression.</li>
- <li>Object field access <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span><span class="Operator">.</span><span class="Identifier">field</span></span></tt> is a path expression.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">system</span><span class="Operator">.</span><span class="Identifier">toOpenArray</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span></span></tt> is a path expression.</li>
- <li>Pointer dereference <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span><span class="Punctuation">[</span><span class="Punctuation">]</span></span></tt> is a path expression.</li>
- <li>An address <tt class="docutils literal"><span class="pre"><span class="Keyword">addr</span> <span class="Identifier">e</span></span></tt> is a path expression.</li>
- <li>A type conversion <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">)</span></span></tt> is a path expression.</li>
- <li>A cast expression <tt class="docutils literal"><span class="pre"><span class="Keyword">cast</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">)</span></span></tt> is a path expression.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span></span></tt> is a path expression if <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt>'s return type is a view type. Because the view can only have been borrowed from <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span></span></tt>, we then know that the owner of <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span></span></tt> is <tt class="docutils literal"><span class="pre"><span class="Identifier">e</span></span></tt>.</li>
- </ul>
- <p>If a view type is used as a return type, the location must borrow from a location that is derived from the first parameter that is passed to the proc. See <a class="reference external" href="manual.html#procedures-var-return-type">the manual</a> for details about how this is done for <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span> <span class="Identifier">T</span></span></tt>.</p>
- <p>A mutable view can borrow from a mutable location, an immutable view can borrow from both a mutable or an immutable location.</p>
- <p>If a view borrows from a mutable location, the view can be used to update the location. Otherwise it cannot be used for mutations.</p>
- <p>The <em>duration</em> of a borrow is the span of commands beginning from the assignment to the view and ending with the last usage of the view.</p>
- <p>For the duration of the borrow operation, no mutations to the borrowed locations may be performed except via the view that borrowed from the location. The borrowed location is said to be <em>sealed</em> during the borrow.</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"views"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Obj</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">field</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
- <span class="Keyword">proc</span> <span class="Identifier">dangerous</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">Obj</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">let</span> <span class="Identifier">v</span><span class="Punctuation">:</span> <span class="Identifier">lent</span> <span class="Identifier">Obj</span> <span class="Operator">=</span> <span class="Identifier">s</span><span class="Punctuation">[</span><span class="DecNumber">0</span><span class="Punctuation">]</span> <span class="Comment"># seal 's'</span>
- <span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">setLen</span> <span class="DecNumber">0</span> <span class="Comment"># prevented at compile-time because 's' is sealed.</span>
- <span class="Identifier">echo</span> <span class="Identifier">v</span><span class="Operator">.</span><span class="Identifier">field</span></pre></p>
- <p>The scope of the view does not matter:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">valid</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">Obj</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">let</span> <span class="Identifier">v</span><span class="Punctuation">:</span> <span class="Identifier">lent</span> <span class="Identifier">Obj</span> <span class="Operator">=</span> <span class="Identifier">s</span><span class="Punctuation">[</span><span class="DecNumber">0</span><span class="Punctuation">]</span> <span class="Comment"># begin of borrow</span>
- <span class="Identifier">echo</span> <span class="Identifier">v</span><span class="Operator">.</span><span class="Identifier">field</span> <span class="Comment"># end of borrow</span>
- <span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">setLen</span> <span class="DecNumber">0</span> <span class="Comment"># valid because 'v' isn't used afterwards</span></pre></p>
- <p>The analysis requires as much precision about mutations as is reasonably obtainable, so it is more effective with the experimental <a class="reference internal" href="#strict-funcs">strict funcs</a> feature. In other words <tt class="docutils literal"><span class="pre option">--experimental:views</span></tt> works better with <tt class="docutils literal"><span class="pre option">--experimental:strictFuncs</span></tt>.</p>
- <p>The analysis is currently control flow insensitive:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">invalid</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">Obj</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">let</span> <span class="Identifier">v</span><span class="Punctuation">:</span> <span class="Identifier">lent</span> <span class="Identifier">Obj</span> <span class="Operator">=</span> <span class="Identifier">s</span><span class="Punctuation">[</span><span class="DecNumber">0</span><span class="Punctuation">]</span>
- <span class="Keyword">if</span> <span class="Identifier">false</span><span class="Punctuation">:</span>
- <span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">setLen</span> <span class="DecNumber">0</span>
- <span class="Identifier">echo</span> <span class="Identifier">v</span><span class="Operator">.</span><span class="Identifier">field</span></pre></p>
- <p>In this example, the compiler assumes that <tt class="docutils literal"><span class="pre"><span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">setLen</span> <span class="DecNumber">0</span></span></tt> invalidates the borrow operation of <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> even though a human being can easily see that it will never do that at runtime.</p>
- <h2><a class="toc-backref" id="view-types-start-of-a-borrow" href="#view-types-start-of-a-borrow">Start of a borrow</a></h2><p>A borrow starts with one of the following:</p>
- <ul class="simple"><li>The assignment of a non-view-type to a view-type.</li>
- <li>The assignment of a location that is derived from a local parameter to a view-type.</li>
- </ul>
- <h2><a class="toc-backref" id="view-types-end-of-a-borrow" href="#view-types-end-of-a-borrow">End of a borrow</a></h2><p>A borrow operation ends with the last usage of the view variable.</p>
- <h2><a class="toc-backref" id="view-types-reborrows" href="#view-types-reborrows">Reborrows</a></h2><p>A view <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> can borrow from multiple different locations. However, the borrow is always the full span of <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt>'s lifetime and every location that is borrowed from is sealed during <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt>'s lifetime.</p>
- <h2><a class="toc-backref" id="view-types-algorithm" href="#view-types-algorithm">Algorithm</a></h2><p>The following section is an outline of the algorithm that the current implementation uses. The algorithm performs two traversals over the AST of the procedure or global section of code that uses a view variable. No fixpoint iterations are performed, the complexity of the analysis is O(N) where N is the number of nodes of the AST.</p>
- <p>The first pass over the AST computes the lifetime of each local variable based on a notion of an "abstract time", in the implementation it's a simple integer that is incremented for every visited node.</p>
- <p>In the second pass, information about the underlying object "graphs" is computed. Let <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> be a parameter or a local variable. Let <tt class="docutils literal"><span class="pre"><span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">v</span><span class="Punctuation">)</span></span></tt> be the graph that <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> belongs to. A graph is defined by the set of variables that belong to the graph. Initially for all <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt>: <tt class="docutils literal"><span class="pre"><span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">v</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Punctuation">{</span><span class="Identifier">v</span><span class="Punctuation">}</span></span></tt>. Every variable can only be part of a single graph.</p>
- <p>Assignments like <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span> <span class="Operator">=</span> <span class="Identifier">b</span></span></tt> "connect" two variables, both variables end up in the same graph <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">)</span></span></tt>. Unfortunately, the pattern to look for is much more complex than that and can involve multiple assignment targets and sources:</p>
- <pre>f(x, y) = g(a, b)</pre>
- <p>connects <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">y</span></span></tt> to <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">b</span></span></tt>: <tt class="docutils literal"><span class="pre"><span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">y</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Punctuation">{</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">}</span></span></tt>. A type based alias analysis rules out some of these combinations, for example a <tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt> value cannot possibly be connected to a <tt class="docutils literal"><span class="pre"><span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span></span></tt>.</p>
- <p>A pattern like <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span><span class="Punctuation">[</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">value</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span><span class="Operator">.</span><span class="Identifier">field</span> <span class="Operator">=</span> <span class="Identifier">value</span></span></tt> marks <tt class="docutils literal"><span class="pre"><span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">v</span><span class="Punctuation">)</span></span></tt> as mutated. After the second pass a set of disjoint graphs was computed.</p>
- <p>For strict functions it is then enforced that there is no graph that is both mutated and has an element that is an immutable parameter (that is a parameter that is not of type <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span> <span class="Identifier">T</span></span></tt>).</p>
- <p>For borrow checking, a different set of checks is performed. Let <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> be the view and <tt class="docutils literal"><span class="pre"><span class="Identifier">b</span></span></tt> the location that is borrowed from.</p>
- <ul class="simple"><li>The lifetime of <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> must not exceed <tt class="docutils literal"><span class="pre"><span class="Identifier">b</span></span></tt>'s lifetime. Note: The lifetime of a parameter is the complete proc body.</li>
- <li>If <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> is used for a mutation, <tt class="docutils literal"><span class="pre"><span class="Identifier">b</span></span></tt> must be a mutable location too.</li>
- <li>During <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt>'s lifetime, <tt class="docutils literal"><span class="pre"><span class="Identifier">G</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">)</span></span></tt> can only be modified by <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> (and only if <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> is a mutable view).</li>
- <li>If <tt class="docutils literal"><span class="pre"><span class="Identifier">v</span></span></tt> is <tt class="docutils literal"><span class="pre"><span class="Identifier">result</span></span></tt> then <tt class="docutils literal"><span class="pre"><span class="Identifier">b</span></span></tt> has to be a location derived from the first formal parameter or from a constant location.</li>
- <li>A view cannot be used for a read or a write access before it was assigned to.</li>
- </ul>
- <h1><a class="toc-backref" id="concepts" href="#concepts">Concepts</a></h1><p>Concepts, also known as "user-defined type classes", are used to specify an arbitrary set of requirements that the matched type must satisfy.</p>
- <p>Concepts are written in the following form:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">Comparable</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span>
- <span class="Punctuation">(</span><span class="Identifier">x</span> <span class="Operator"><</span> <span class="Identifier">y</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">bool</span>
-
- <span class="Identifier">Stack</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">s</span><span class="Punctuation">,</span> <span class="Keyword">var</span> <span class="Identifier">v</span>
- <span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">pop</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Identifier">v</span><span class="Operator">.</span><span class="Identifier">push</span><span class="Punctuation">(</span><span class="Identifier">T</span><span class="Punctuation">)</span>
-
- <span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">len</span> <span class="Keyword">is</span> <span class="Identifier">Ordinal</span>
-
- <span class="Keyword">for</span> <span class="Identifier">value</span> <span class="Keyword">in</span> <span class="Identifier">s</span><span class="Punctuation">:</span>
- <span class="Identifier">value</span> <span class="Keyword">is</span> <span class="Identifier">T</span></pre></p>
- <p>The concept matches if:</p>
- <ol class="loweralpha simple"><li>all expressions within the body can be compiled for the tested type</li>
- <li>all statically evaluable boolean expressions in the body are true</li>
- <li>all type modifiers specified match their respective definitions</li>
- </ol>
- <p>The identifiers following the <tt class="docutils literal"><span class="pre"><span class="Keyword">concept</span></span></tt> keyword represent instances of the currently matched type. You can apply any of the standard type modifiers such as <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">ptr</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Keyword">static</span></span></tt> to denote a more specific type of instance. You can also apply the <tt class="docutils literal"><span class="pre"><span class="Keyword">type</span></span></tt> modifier to create a named instance of the type itself:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">MyConcept</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Keyword">var</span> <span class="Identifier">v</span><span class="Punctuation">,</span> <span class="Keyword">ref</span> <span class="Identifier">r</span><span class="Punctuation">,</span> <span class="Keyword">ptr</span> <span class="Identifier">p</span><span class="Punctuation">,</span> <span class="Keyword">static</span> <span class="Identifier">s</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">T</span>
- <span class="Operator">...</span></pre></p>
- <p>Within the concept body, types can appear in positions where ordinary values and parameters are expected. This provides a more convenient way to check for the presence of callable symbols with specific signatures:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">OutputStream</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Keyword">var</span> <span class="Identifier">s</span>
- <span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">write</span><span class="Punctuation">(</span><span class="Identifier">string</span><span class="Punctuation">)</span></pre></p>
- <p>In order to check for symbols accepting <tt class="docutils literal"><span class="pre"><span class="Keyword">type</span></span></tt> params, you must prefix the type with the explicit <tt class="docutils literal"><span class="pre"><span class="Keyword">type</span></span></tt> modifier. The named instance of the type, following the <tt class="docutils literal"><span class="pre"><span class="Keyword">concept</span></span></tt> keyword is also considered to have the explicit modifier and will be matched only as a type.</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Comment"># Let's imagine a user-defined casting framework with operators</span>
- <span class="Comment"># such as `val.to(string)` and `val.to(JSonValue)`. We can test</span>
- <span class="Comment"># for these with the following concept:</span>
- <span class="Identifier">MyCastables</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">to</span><span class="Punctuation">(</span><span class="Keyword">type</span> <span class="Identifier">string</span><span class="Punctuation">)</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">to</span><span class="Punctuation">(</span><span class="Keyword">type</span> <span class="Identifier">JSonValue</span><span class="Punctuation">)</span>
-
- <span class="Comment"># Let's define a couple of concepts, known from Algebra:</span>
- <span class="Identifier">AdditiveMonoid</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">T</span>
- <span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">y</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Identifier">T</span><span class="Operator">.</span><span class="Identifier">zero</span> <span class="Keyword">is</span> <span class="Identifier">T</span> <span class="Comment"># require a proc such as `int.zero` or 'Position.zero'</span>
-
- <span class="Identifier">AdditiveGroup</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">T</span>
- <span class="Identifier">x</span> <span class="Keyword">is</span> <span class="Identifier">AdditiveMonoid</span>
- <span class="Operator">-</span><span class="Identifier">x</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Identifier">x</span> <span class="Operator">-</span> <span class="Identifier">y</span> <span class="Keyword">is</span> <span class="Identifier">T</span></pre></p>
- <p>Please note that the <tt class="docutils literal"><span class="pre"><span class="Keyword">is</span></span></tt> operator allows one to easily verify the precise type signatures of the required operations, but since type inference and default parameters are still applied in the concept body, it's also possible to describe usage protocols that do not reveal implementation details.</p>
- <p>Much like generics, concepts are instantiated exactly once for each tested type and any static code included within the body is executed only once.</p>
- <h2><a class="toc-backref" id="concepts-concept-diagnostics" href="#concepts-concept-diagnostics">Concept diagnostics</a></h2><p>By default, the compiler will report the matching errors in concepts only when no other overload can be selected and a normal compilation error is produced. When you need to understand why the compiler is not matching a particular concept and, as a result, a wrong overload is selected, you can apply the <tt class="docutils literal"><span class="pre"><span class="Identifier">explain</span></span></tt> pragma to either the concept body or a particular call-site.</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">MyConcept</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">explain</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Operator">...</span>
- <span class="Identifier">overloadedProc</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Identifier">z</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">explain</span><span class="Operator">.</span><span class="Punctuation">}</span></pre></p>
- <p>This will provide Hints in the compiler output either every time the concept is not matched or only on the particular call-site.</p>
- <h2><a class="toc-backref" id="concepts-generic-concepts-and-type-binding-rules" href="#concepts-generic-concepts-and-type-binding-rules">Generic concepts and type binding rules</a></h2><p>The concept types can be parametric just like the regular generic types:</p>
- <p><pre class="listing"><span class="Comment">### matrixalgo.nim</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">typetraits</span>
- <span class="Keyword">type</span>
- <span class="Identifier">AnyMatrix</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">R</span><span class="Punctuation">,</span> <span class="Identifier">C</span><span class="Punctuation">:</span> <span class="Keyword">static</span> <span class="Identifier">int</span><span class="Punctuation">;</span> <span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">m</span><span class="Punctuation">,</span> <span class="Keyword">var</span> <span class="Identifier">mvar</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">M</span>
- <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">ValueType</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">Rows</span> <span class="Operator">==</span> <span class="Identifier">R</span>
- <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">Cols</span> <span class="Operator">==</span> <span class="Identifier">C</span>
-
- <span class="Identifier">m</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">]</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Identifier">mvar</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">T</span>
-
- <span class="Keyword">type</span> <span class="Identifier">TransposedType</span> <span class="Operator">=</span> <span class="Identifier">stripGenericParams</span><span class="Punctuation">(</span><span class="Identifier">M</span><span class="Punctuation">)</span><span class="Punctuation">[</span><span class="Identifier">C</span><span class="Punctuation">,</span> <span class="Identifier">R</span><span class="Punctuation">,</span> <span class="Identifier">T</span><span class="Punctuation">]</span>
-
- <span class="Identifier">AnySquareMatrix</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">N</span><span class="Punctuation">:</span> <span class="Keyword">static</span> <span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">AnyMatrix</span><span class="Punctuation">[</span><span class="Identifier">N</span><span class="Punctuation">,</span> <span class="Identifier">N</span><span class="Punctuation">,</span> <span class="Identifier">T</span><span class="Punctuation">]</span>
-
- <span class="Identifier">AnyTransform3D</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Identifier">AnyMatrix</span><span class="Punctuation">[</span><span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="Identifier">float</span><span class="Punctuation">]</span>
- <span class="Keyword">proc</span> <span class="Identifier">transposed</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">m</span><span class="Punctuation">:</span> <span class="Identifier">AnyMatrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">m</span><span class="Operator">.</span><span class="Identifier">TransposedType</span> <span class="Operator">=</span>
- <span class="Keyword">for</span> <span class="Identifier">r</span> <span class="Keyword">in</span> <span class="DecNumber">0</span> <span class="Operator">..<</span> <span class="Identifier">m</span><span class="Operator">.</span><span class="Identifier">R</span><span class="Punctuation">:</span>
- <span class="Keyword">for</span> <span class="Identifier">c</span> <span class="Keyword">in</span> <span class="DecNumber">0</span> <span class="Operator">..<</span> <span class="Identifier">m</span><span class="Operator">.</span><span class="Identifier">C</span><span class="Punctuation">:</span>
- <span class="Identifier">result</span><span class="Punctuation">[</span><span class="Identifier">r</span><span class="Punctuation">,</span> <span class="Identifier">c</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">m</span><span class="Punctuation">[</span><span class="Identifier">c</span><span class="Punctuation">,</span> <span class="Identifier">r</span><span class="Punctuation">]</span>
- <span class="Keyword">proc</span> <span class="Identifier">determinant</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">m</span><span class="Punctuation">:</span> <span class="Identifier">AnySquareMatrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span>
- <span class="Operator">...</span>
- <span class="Keyword">proc</span> <span class="Identifier">setPerspectiveProjection</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">m</span><span class="Punctuation">:</span> <span class="Identifier">AnyTransform3D</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Operator">...</span>
- <span class="Operator">--------------</span>
- <span class="Comment">### matrix.nim</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Matrix</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">M</span><span class="Punctuation">,</span> <span class="Identifier">N</span><span class="Punctuation">:</span> <span class="Keyword">static</span> <span class="Identifier">int</span><span class="Punctuation">;</span> <span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">data</span><span class="Punctuation">:</span> <span class="Identifier">array</span><span class="Punctuation">[</span><span class="Identifier">M</span><span class="Operator">*</span><span class="Identifier">N</span><span class="Punctuation">,</span> <span class="Identifier">T</span><span class="Punctuation">]</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">M</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">;</span> <span class="Identifier">m</span><span class="Punctuation">,</span> <span class="Identifier">n</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">T</span> <span class="Operator">=</span>
- <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">data</span><span class="Punctuation">[</span><span class="Identifier">m</span> <span class="Operator">*</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">N</span> <span class="Operator">+</span> <span class="Identifier">n</span><span class="Punctuation">]</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Operator">=</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">M</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Matrix</span><span class="Punctuation">;</span> <span class="Identifier">m</span><span class="Punctuation">,</span> <span class="Identifier">n</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">;</span> <span class="Identifier">v</span><span class="Punctuation">:</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">T</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">data</span><span class="Punctuation">[</span><span class="Identifier">m</span> <span class="Operator">*</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">N</span> <span class="Operator">+</span> <span class="Identifier">n</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">v</span>
- <span class="Comment"># Adapt the Matrix type to the concept's requirements</span>
- <span class="Keyword">template</span> <span class="Identifier">Rows</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">M</span><span class="Punctuation">:</span> <span class="Identifier">typedesc</span><span class="Punctuation">[</span><span class="Identifier">Matrix</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">M</span>
- <span class="Keyword">template</span> <span class="Identifier">Cols</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">M</span><span class="Punctuation">:</span> <span class="Identifier">typedesc</span><span class="Punctuation">[</span><span class="Identifier">Matrix</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">N</span>
- <span class="Keyword">template</span> <span class="Identifier">ValueType</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">M</span><span class="Punctuation">:</span> <span class="Identifier">typedesc</span><span class="Punctuation">[</span><span class="Identifier">Matrix</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">typedesc</span> <span class="Operator">=</span> <span class="Identifier">M</span><span class="Operator">.</span><span class="Identifier">T</span>
- <span class="Operator">-------------</span>
- <span class="Comment">### usage.nim</span>
- <span class="Keyword">import</span> <span class="Identifier">matrix</span><span class="Punctuation">,</span> <span class="Identifier">matrixalgo</span>
- <span class="Keyword">var</span>
- <span class="Identifier">m</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">[</span><span class="DecNumber">3</span><span class="Punctuation">,</span> <span class="DecNumber">3</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">]</span>
- <span class="Identifier">projectionMatrix</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">[</span><span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="Identifier">float</span><span class="Punctuation">]</span>
- <span class="Identifier">echo</span> <span class="Identifier">m</span><span class="Operator">.</span><span class="Identifier">transposed</span><span class="Operator">.</span><span class="Identifier">determinant</span>
- <span class="Identifier">setPerspectiveProjection</span> <span class="Identifier">projectionMatrix</span></pre></p>
- <p>When the concept type is matched against a concrete type, the unbound type parameters are inferred from the body of the concept in a way that closely resembles the way generic parameters of callable symbols are inferred on call sites.</p>
- <p>Unbound types can appear both as params to calls such as <tt class="docutils literal"><span class="pre"><span class="Identifier">s</span><span class="Operator">.</span><span class="Identifier">push</span><span class="Punctuation">(</span><span class="Identifier">T</span><span class="Punctuation">)</span></span></tt> and on the right-hand side of the <tt class="docutils literal"><span class="pre"><span class="Keyword">is</span></span></tt> operator in cases such as <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">pop</span> <span class="Keyword">is</span> <span class="Identifier">T</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">data</span> <span class="Keyword">is</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt>.</p>
- <p>Unbound static params will be inferred from expressions involving the <tt class="docutils literal"><span class="pre"><span class="Operator">==</span></span></tt> operator and also when types dependent on them are being matched:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">MatrixReducer</span><span class="Punctuation">[</span><span class="Identifier">M</span><span class="Punctuation">,</span> <span class="Identifier">N</span><span class="Punctuation">:</span> <span class="Keyword">static</span> <span class="Identifier">int</span><span class="Punctuation">;</span> <span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">reduce</span><span class="Punctuation">(</span><span class="Identifier">SquareMatrix</span><span class="Punctuation">[</span><span class="Identifier">N</span><span class="Punctuation">,</span> <span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">array</span><span class="Punctuation">[</span><span class="Identifier">M</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">]</span></pre></p>
- <p>The Nim compiler includes a simple linear equation solver, allowing it to infer static params in some situations where integer arithmetic is involved.</p>
- <p>Just like in regular type classes, Nim discriminates between <tt class="docutils literal"><span class="pre"><span class="Keyword">bind</span> <span class="Identifier">once</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Keyword">bind</span> <span class="Identifier">many</span></span></tt> types when matching the concept. You can add the <tt class="docutils literal"><span class="pre"><span class="Keyword">distinct</span></span></tt> modifier to any of the otherwise inferable types to get a type that will be matched without permanently inferring it. This may be useful when you need to match several procs accepting the same wide class of types:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">Enumerable</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">e</span>
- <span class="Keyword">for</span> <span class="Identifier">v</span> <span class="Keyword">in</span> <span class="Identifier">e</span><span class="Punctuation">:</span>
- <span class="Identifier">v</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Keyword">type</span>
- <span class="Identifier">MyConcept</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">o</span>
- <span class="Comment"># this could be inferred to a type such as Enumerable[int]</span>
- <span class="Identifier">o</span><span class="Operator">.</span><span class="Identifier">foo</span> <span class="Keyword">is</span> <span class="Keyword">distinct</span> <span class="Identifier">Enumerable</span>
-
- <span class="Comment"># this could be inferred to a different type such as Enumerable[float]</span>
- <span class="Identifier">o</span><span class="Operator">.</span><span class="Identifier">bar</span> <span class="Keyword">is</span> <span class="Keyword">distinct</span> <span class="Identifier">Enumerable</span>
-
- <span class="Comment"># it's also possible to give an alias name to a `bind many` type class</span>
- <span class="Keyword">type</span> <span class="Keyword">Enum</span> <span class="Operator">=</span> <span class="Keyword">distinct</span> <span class="Identifier">Enumerable</span>
- <span class="Identifier">o</span><span class="Operator">.</span><span class="Identifier">baz</span> <span class="Keyword">is</span> <span class="Keyword">Enum</span></pre></p>
- <p>On the other hand, using <tt class="docutils literal"><span class="pre"><span class="Keyword">bind</span> <span class="Identifier">once</span></span></tt> types allows you to test for equivalent types used in multiple signatures, without actually requiring any concrete types, thus allowing you to encode implementation-defined types:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">MyConcept</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">x</span>
- <span class="Keyword">type</span> <span class="Identifier">T1</span> <span class="Operator">=</span> <span class="Identifier">auto</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">T1</span><span class="Punctuation">)</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">bar</span><span class="Punctuation">(</span><span class="Identifier">T1</span><span class="Punctuation">)</span> <span class="Comment"># both procs must accept the same type</span>
-
- <span class="Keyword">type</span> <span class="Identifier">T2</span> <span class="Operator">=</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">SomeNumber</span><span class="Punctuation">]</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">alpha</span><span class="Punctuation">(</span><span class="Identifier">T2</span><span class="Punctuation">)</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">omega</span><span class="Punctuation">(</span><span class="Identifier">T2</span><span class="Punctuation">)</span> <span class="Comment"># both procs must accept the same type</span>
- <span class="Comment"># and it must be a numeric sequence</span></pre></p>
- <p>As seen in the previous examples, you can refer to generic concepts such as <tt class="docutils literal"><span class="pre"><span class="Identifier">Enumerable</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> just by their short name. Much like the regular generic types, the concept will be automatically instantiated with the bind once auto type in the place of each missing generic param.</p>
- <p>Please note that generic concepts such as <tt class="docutils literal"><span class="pre"><span class="Identifier">Enumerable</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> can be matched against concrete types such as <tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt>. Nim doesn't require the concept type to have the same number of parameters as the type being matched. If you wish to express a requirement towards the generic parameters of the matched type, you can use a type mapping operator such as <tt class="docutils literal"><span class="pre"><span class="Identifier">genericHead</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Identifier">stripGenericParams</span></span></tt> within the body of the concept to obtain the uninstantiated version of the type, which you can then try to instantiate in any required way. For example, here is how one might define the classic <tt class="docutils literal"><span class="pre"><span class="Identifier">Functor</span></span></tt> concept from Haskell and then demonstrate that Nim's <tt class="docutils literal"><span class="pre"><span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> type is an instance of it:</p>
- <p><pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Punctuation">[</span><span class="Identifier">sugar</span><span class="Punctuation">,</span> <span class="Identifier">typetraits</span><span class="Punctuation">]</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Functor</span><span class="Punctuation">[</span><span class="Identifier">A</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">f</span>
- <span class="Keyword">type</span> <span class="Identifier">MatchedGenericType</span> <span class="Operator">=</span> <span class="Identifier">genericHead</span><span class="Punctuation">(</span><span class="Identifier">typeof</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Comment"># `f` will be a value of a type such as `Option[T]`</span>
- <span class="Comment"># `MatchedGenericType` will become the `Option` type</span>
-
- <span class="Identifier">f</span><span class="Operator">.</span><span class="Identifier">val</span> <span class="Keyword">is</span> <span class="Identifier">A</span>
- <span class="Comment"># The Functor should provide a way to obtain</span>
- <span class="Comment"># a value stored inside it</span>
-
- <span class="Keyword">type</span> <span class="Identifier">T</span> <span class="Operator">=</span> <span class="Identifier">auto</span>
- <span class="Identifier">map</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">,</span> <span class="Identifier">A</span> <span class="Operator">-></span> <span class="Identifier">T</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">MatchedGenericType</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span>
- <span class="Comment"># And it should provide a way to map one instance of</span>
- <span class="Comment"># the Functor to a instance of a different type, given</span>
- <span class="Comment"># a suitable `map` operation for the enclosed values</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">options</span>
- <span class="Identifier">echo</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span> <span class="Keyword">is</span> <span class="Identifier">Functor</span> <span class="Comment"># prints true</span></pre></p>
- <h2><a class="toc-backref" id="concepts-concept-derived-values" href="#concepts-concept-derived-values">Concept derived values</a></h2><p>All top level constants or types appearing within the concept body are accessible through the dot operator in procs where the concept was successfully matched to a concrete type:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">DateTime</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">t1</span><span class="Punctuation">,</span> <span class="Identifier">t2</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">T</span>
- <span class="Keyword">const</span> <span class="Identifier">Min</span> <span class="Operator">=</span> <span class="Identifier">T</span><span class="Operator">.</span><span class="Identifier">MinDate</span>
- <span class="Identifier">T</span><span class="Operator">.</span><span class="Identifier">Now</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
-
- <span class="Identifier">t1</span> <span class="Operator"><</span> <span class="Identifier">t2</span> <span class="Keyword">is</span> <span class="Identifier">bool</span>
-
- <span class="Keyword">type</span> <span class="Identifier">TimeSpan</span> <span class="Operator">=</span> <span class="Identifier">typeof</span><span class="Punctuation">(</span><span class="Identifier">t1</span> <span class="Operator">-</span> <span class="Identifier">t2</span><span class="Punctuation">)</span>
- <span class="Identifier">TimeSpan</span> <span class="Operator">*</span> <span class="Identifier">int</span> <span class="Keyword">is</span> <span class="Identifier">TimeSpan</span>
- <span class="Identifier">TimeSpan</span> <span class="Operator">+</span> <span class="Identifier">TimeSpan</span> <span class="Keyword">is</span> <span class="Identifier">TimeSpan</span>
-
- <span class="Identifier">t1</span> <span class="Operator">+</span> <span class="Identifier">TimeSpan</span> <span class="Keyword">is</span> <span class="Identifier">T</span>
- <span class="Keyword">proc</span> <span class="Identifier">eventsJitter</span><span class="Punctuation">(</span><span class="Identifier">events</span><span class="Punctuation">:</span> <span class="Identifier">Enumerable</span><span class="Punctuation">[</span><span class="Identifier">DateTime</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">float</span> <span class="Operator">=</span>
- <span class="Keyword">var</span>
- <span class="Comment"># this variable will have the inferred TimeSpan type for</span>
- <span class="Comment"># the concrete Date-like value the proc was called with:</span>
- <span class="Identifier">averageInterval</span><span class="Punctuation">:</span> <span class="Identifier">DateTime</span><span class="Operator">.</span><span class="Identifier">TimeSpan</span>
-
- <span class="Identifier">deviation</span><span class="Punctuation">:</span> <span class="Identifier">float</span>
- <span class="Operator">...</span></pre></p>
- <h2><a class="toc-backref" id="concepts-concept-refinement" href="#concepts-concept-refinement">Concept refinement</a></h2><p>When the matched type within a concept is directly tested against a different concept, we say that the outer concept is a refinement of the inner concept and thus it is more-specific. When both concepts are matched in a call during overload resolution, Nim will assign a higher precedence to the most specific one. As an alternative way of defining concept refinements, you can use the object inheritance syntax involving the <tt class="docutils literal"><span class="pre"><span class="Keyword">of</span></span></tt> keyword:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">Graph</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">g</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">G</span> <span class="Keyword">of</span> <span class="Identifier">EquallyComparable</span><span class="Punctuation">,</span> <span class="Identifier">Copyable</span>
- <span class="Keyword">type</span>
- <span class="Identifier">VertexType</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Operator">.</span><span class="Identifier">VertexType</span>
- <span class="Identifier">EdgeType</span> <span class="Operator">=</span> <span class="Identifier">G</span><span class="Operator">.</span><span class="Identifier">EdgeType</span>
-
- <span class="Identifier">VertexType</span> <span class="Keyword">is</span> <span class="Identifier">Copyable</span>
- <span class="Identifier">EdgeType</span> <span class="Keyword">is</span> <span class="Identifier">Copyable</span>
-
- <span class="Keyword">var</span>
- <span class="Identifier">v</span><span class="Punctuation">:</span> <span class="Identifier">VertexType</span>
- <span class="Identifier">e</span><span class="Punctuation">:</span> <span class="Identifier">EdgeType</span>
-
- <span class="Identifier">IncidendeGraph</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Keyword">of</span> <span class="Identifier">Graph</span>
- <span class="Comment"># symbols such as variables and types from the refined</span>
- <span class="Comment"># concept are automatically in scope:</span>
-
- <span class="Identifier">g</span><span class="Operator">.</span><span class="Identifier">source</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">VertexType</span>
- <span class="Identifier">g</span><span class="Operator">.</span><span class="Identifier">target</span><span class="Punctuation">(</span><span class="Identifier">e</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">VertexType</span>
-
- <span class="Identifier">g</span><span class="Operator">.</span><span class="Identifier">outgoingEdges</span><span class="Punctuation">(</span><span class="Identifier">v</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">Enumerable</span><span class="Punctuation">[</span><span class="Identifier">EdgeType</span><span class="Punctuation">]</span>
-
- <span class="Identifier">BidirectionalGraph</span> <span class="Operator">=</span> <span class="Keyword">concept</span> <span class="Identifier">g</span><span class="Punctuation">,</span> <span class="Keyword">type</span> <span class="Identifier">G</span>
- <span class="Comment"># The following will also turn the concept into a refinement when it</span>
- <span class="Comment"># comes to overload resolution, but it doesn't provide the convenient</span>
- <span class="Comment"># symbol inheritance</span>
- <span class="Identifier">g</span> <span class="Keyword">is</span> <span class="Identifier">IncidendeGraph</span>
-
- <span class="Identifier">g</span><span class="Operator">.</span><span class="Identifier">incomingEdges</span><span class="Punctuation">(</span><span class="Identifier">G</span><span class="Operator">.</span><span class="Identifier">VertexType</span><span class="Punctuation">)</span> <span class="Keyword">is</span> <span class="Identifier">Enumerable</span><span class="Punctuation">[</span><span class="Identifier">G</span><span class="Operator">.</span><span class="Identifier">EdgeType</span><span class="Punctuation">]</span>
- <span class="Keyword">proc</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">g</span><span class="Punctuation">:</span> <span class="Identifier">IncidendeGraph</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">g</span><span class="Punctuation">:</span> <span class="Identifier">BidirectionalGraph</span><span class="Punctuation">)</span> <span class="Comment"># this one will be preferred if we pass a type</span>
- <span class="Comment"># matching the BidirectionalGraph concept</span></pre></p>
- <h1><a class="toc-backref" id="dynamic-arguments-for-bindsym" href="#dynamic-arguments-for-bindsym">Dynamic arguments for bindSym</a></h1><p>This experimental feature allows the symbol name argument of <tt class="docutils literal"><span class="pre"><span class="Identifier">macros</span><span class="Operator">.</span><span class="Identifier">bindSym</span></span></tt> to be computed dynamically.</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"dynamicBindSym"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">macros</span>
- <span class="Keyword">macro</span> <span class="Identifier">callOp</span><span class="Punctuation">(</span><span class="Identifier">opName</span><span class="Punctuation">,</span> <span class="Identifier">arg1</span><span class="Punctuation">,</span> <span class="Identifier">arg2</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
- <span class="Identifier">result</span> <span class="Operator">=</span> <span class="Identifier">newCall</span><span class="Punctuation">(</span><span class="Identifier">bindSym</span><span class="Punctuation">(</span><span class="Operator">$</span><span class="Identifier">opName</span><span class="Punctuation">)</span><span class="Punctuation">,</span> <span class="Identifier">arg1</span><span class="Punctuation">,</span> <span class="Identifier">arg2</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="Identifier">callOp</span><span class="Punctuation">(</span><span class="StringLit">"+"</span><span class="Punctuation">,</span> <span class="DecNumber">1</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="Identifier">callOp</span><span class="Punctuation">(</span><span class="StringLit">"-"</span><span class="Punctuation">,</span> <span class="DecNumber">5</span><span class="Punctuation">,</span> <span class="DecNumber">4</span><span class="Punctuation">)</span></pre></p>
- <h1><a class="toc-backref" id="term-rewriting-macros" href="#term-rewriting-macros">Term rewriting macros</a></h1><p>Term rewriting macros are macros or templates that have not only a <em>name</em> but also a <em>pattern</em> that is searched for after the semantic checking phase of the compiler: This means they provide an easy way to enhance the compilation pipeline with user defined optimizations:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">optMul</span><span class="Punctuation">{</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">a</span> <span class="Operator">+</span> <span class="Identifier">a</span>
- <span class="Keyword">let</span> <span class="Identifier">x</span> <span class="Operator">=</span> <span class="DecNumber">3</span>
- <span class="Identifier">echo</span> <span class="Identifier">x</span> <span class="Operator">*</span> <span class="DecNumber">2</span></pre></p>
- <p>The compiler now rewrites <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span> <span class="Operator">*</span> <span class="DecNumber">2</span></span></tt> as <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">x</span></span></tt>. The code inside the curly brackets is the pattern to match against. The operators <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">**</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">|</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">~</span></span></tt> have a special meaning in patterns if they are written in infix notation, so to match verbatim against <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> the ordinary function call syntax needs to be used.</p>
- <p>Term rewriting macros are applied recursively, up to a limit. This means that if the result of a term rewriting macro is eligible for another rewriting, the compiler will try to perform it, and so on, until no more optimizations are applicable. To avoid putting the compiler into an infinite loop, there is a hard limit on how many times a single term rewriting macro can be applied. Once this limit has been passed, the term rewriting macro will be ignored.</p>
- <p>Unfortunately optimizations are hard to get right and even this tiny example is <strong>wrong</strong>:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">optMul</span><span class="Punctuation">{</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">a</span> <span class="Operator">+</span> <span class="Identifier">a</span>
- <span class="Keyword">proc</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"side effect!"</span>
- <span class="Identifier">result</span> <span class="Operator">=</span> <span class="DecNumber">55</span>
- <span class="Identifier">echo</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">*</span> <span class="DecNumber">2</span></pre></p>
- <p>We cannot duplicate 'a' if it denotes an expression that has a side effect! Fortunately Nim supports side effect analysis:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">optMul</span><span class="Punctuation">{</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="DecNumber">2</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">{</span><span class="Identifier">noSideEffect</span><span class="Punctuation">}</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">a</span> <span class="Operator">+</span> <span class="Identifier">a</span>
- <span class="Keyword">proc</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"side effect!"</span>
- <span class="Identifier">result</span> <span class="Operator">=</span> <span class="DecNumber">55</span>
- <span class="Identifier">echo</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">*</span> <span class="DecNumber">2</span> <span class="Comment"># not optimized ;-)</span></pre></p>
- <p>You can make one overload matching with a constraint and one without, and the one with a constraint will have precedence, and so you can handle both cases differently.</p>
- <p>So what about <tt class="docutils literal"><span class="pre"><span class="DecNumber">2</span> <span class="Operator">*</span> <span class="Identifier">a</span></span></tt>? We should tell the compiler <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> is commutative. We cannot really do that however as the following code only swaps arguments blindly:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">mulIsCommutative</span><span class="Punctuation">{</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">b</span> <span class="Operator">*</span> <span class="Identifier">a</span></pre></p>
- <p>What optimizers really need to do is a <em>canonicalization</em>:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">canonMul</span><span class="Punctuation">{</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">{</span><span class="Identifier">lit</span><span class="Punctuation">}</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span> <span class="Identifier">b</span> <span class="Operator">*</span> <span class="Identifier">a</span></pre></p>
- <p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">int</span><span class="Punctuation">{</span><span class="Identifier">lit</span><span class="Punctuation">}</span></span></tt> parameter pattern matches against an expression of type <tt class="docutils literal"><span class="pre"><span class="Identifier">int</span></span></tt>, but only if it's a literal.</p>
- <h2><a class="toc-backref" id="term-rewriting-macros-parameter-constraints" href="#term-rewriting-macros-parameter-constraints">Parameter constraints</a></h2><p>The <span id="parameter-constraint_1">parameter constraint</span> expression can use the operators <tt class="docutils literal"><span class="pre"><span class="Operator">|</span></span></tt> (or), <tt class="docutils literal"><span class="pre"><span class="Operator">&</span></span></tt> (and) and <tt class="docutils literal"><span class="pre"><span class="Operator">~</span></span></tt> (not) and the following predicates:</p>
- <table border="1" class="docutils"><tr><th>Predicate</th><th>Meaning</th></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">atom</span></span></tt></td><td>The matching node has no children.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">lit</span></span></tt></td><td>The matching node is a literal like <tt class="docutils literal"><span class="pre"><span class="StringLit">"abc"</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="DecNumber">12</span></span></tt>.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">sym</span></span></tt></td><td>The matching node must be a symbol (a bound identifier).</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">ident</span></span></tt></td><td>The matching node must be an identifier (an unbound identifier).</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">call</span></span></tt></td><td>The matching AST must be a call/apply expression.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">lvalue</span></span></tt></td><td>The matching AST must be an lvalue.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">sideeffect</span></span></tt></td><td>The matching AST must have a side effect.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">nosideeffect</span></span></tt></td><td>The matching AST must have no side effect.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">param</span></span></tt></td><td>A symbol which is a parameter.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">genericparam</span></span></tt></td><td>A symbol which is a generic parameter.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">module</span></span></tt></td><td>A symbol which is a module.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">type</span></span></tt></td><td>A symbol which is a type.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt></td><td>A symbol which is a variable.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt></td><td>A symbol which is a <tt class="docutils literal"><span class="pre"><span class="Keyword">let</span></span></tt> variable.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">const</span></span></tt></td><td>A symbol which is a constant.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">result</span></span></tt></td><td>The special <tt class="docutils literal"><span class="pre"><span class="Identifier">result</span></span></tt> variable.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">proc</span></span></tt></td><td>A symbol which is a proc.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">method</span></span></tt></td><td>A symbol which is a method.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">iterator</span></span></tt></td><td>A symbol which is an iterator.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">converter</span></span></tt></td><td>A symbol which is a converter.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">macro</span></span></tt></td><td>A symbol which is a macro.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Keyword">template</span></span></tt></td><td>A symbol which is a template.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">field</span></span></tt></td><td>A symbol which is a field in a tuple or an object.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">enumfield</span></span></tt></td><td>A symbol which is a field in an enumeration.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">forvar</span></span></tt></td><td>A for loop variable.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">label</span></span></tt></td><td>A label (used in <tt class="docutils literal"><span class="pre"><span class="Keyword">block</span></span></tt> statements).</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">nk</span><span class="Operator">*</span></span></tt></td><td>The matching AST must have the specified kind. (Example: <tt class="docutils literal"><span class="pre"><span class="Identifier">nkIfStmt</span></span></tt> denotes an <tt class="docutils literal"><span class="pre"><span class="Keyword">if</span></span></tt> statement.)</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">alias</span></span></tt></td><td>States that the marked parameter needs to alias with <em>some</em> other parameter.</td></tr>
- <tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">noalias</span></span></tt></td><td>States that <em>every</em> other parameter must not alias with the marked parameter.</td></tr>
- </table><p>Predicates that share their name with a keyword have to be escaped with backticks. The <tt class="docutils literal"><span class="pre"><span class="Identifier">alias</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">noalias</span></span></tt> predicates refer not only to the matching AST, but also to every other bound parameter; syntactically they need to occur after the ordinary AST predicates:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">ex</span><span class="Punctuation">{</span><span class="Identifier">a</span> <span class="Operator">=</span> <span class="Identifier">b</span> <span class="Operator">+</span> <span class="Identifier">c</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">{</span><span class="Identifier">noalias</span><span class="Punctuation">}</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">,</span> <span class="Identifier">c</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Comment"># this transformation is only valid if 'b' and 'c' do not alias 'a':</span>
- <span class="Identifier">a</span> <span class="Operator">=</span> <span class="Identifier">b</span>
- <span class="Identifier">inc</span> <span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">c</span></pre></p>
- <p>Another example:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">assert</span> <span class="Identifier">s</span> <span class="Operator">==</span> <span class="StringLit">"variable"</span>
- <span class="Keyword">proc</span> <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">{</span><span class="Identifier">nkStrLit</span><span class="Punctuation">}</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">assert</span> <span class="Identifier">s</span> <span class="Operator">==</span> <span class="StringLit">"literal"</span>
- <span class="Keyword">proc</span> <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">{</span><span class="Identifier">nkRStrLit</span><span class="Punctuation">}</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">assert</span> <span class="Identifier">s</span> <span class="Operator">==</span> <span class="RawData">r"raw"</span>
- <span class="Keyword">proc</span> <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">{</span><span class="Identifier">nkTripleStrLit</span><span class="Punctuation">}</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">assert</span> <span class="Identifier">s</span> <span class="Operator">==</span> <span class="LongStringLit">"""triple"""</span>
- <span class="Keyword">proc</span> <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Keyword">static</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">assert</span> <span class="Identifier">s</span> <span class="Operator">==</span> <span class="StringLit">"constant"</span>
- <span class="Comment"># Use parameter constraints to provide overloads based on both the input parameter type and form.</span>
- <span class="Keyword">var</span> <span class="Identifier">variable</span> <span class="Operator">=</span> <span class="StringLit">"variable"</span>
- <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">variable</span><span class="Punctuation">)</span>
- <span class="Keyword">const</span> <span class="Identifier">constant</span> <span class="Operator">=</span> <span class="StringLit">"constant"</span>
- <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="Identifier">constant</span><span class="Punctuation">)</span>
- <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="StringLit">"literal"</span><span class="Punctuation">)</span>
- <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="RawData">r"raw"</span><span class="Punctuation">)</span>
- <span class="Identifier">somefunc</span><span class="Punctuation">(</span><span class="LongStringLit">"""triple"""</span><span class="Punctuation">)</span></pre></p>
- <h2><a class="toc-backref" id="term-rewriting-macros-pattern-operators" href="#term-rewriting-macros-pattern-operators">Pattern operators</a></h2><p>The operators <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">**</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">|</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Operator">~</span></span></tt> have a special meaning in patterns if they are written in infix notation.</p>
- <h3><a class="toc-backref" id="pattern-operators-the-nimbar-operator" href="#pattern-operators-the-nimbar-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">|</span></span></tt> operator</a></h3><p>The <tt class="docutils literal"><span class="pre"><span class="Operator">|</span></span></tt> operator if used as infix operator creates an ordered choice:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">t</span><span class="Punctuation">{</span><span class="DecNumber">0</span><span class="Operator">|</span><span class="DecNumber">1</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="DecNumber">3</span>
- <span class="Keyword">let</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="DecNumber">1</span>
- <span class="Comment"># outputs 3:</span>
- <span class="Identifier">echo</span> <span class="Identifier">a</span></pre></p>
- <p>The matching is performed after the compiler performed some optimizations like constant folding, so the following does not work:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">t</span><span class="Punctuation">{</span><span class="DecNumber">0</span><span class="Operator">|</span><span class="DecNumber">1</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="DecNumber">3</span>
- <span class="Comment"># outputs 1:</span>
- <span class="Identifier">echo</span> <span class="DecNumber">1</span></pre></p>
- <p>The reason is that the compiler already transformed the 1 into "1" for the <tt class="docutils literal"><span class="pre"><span class="Identifier">echo</span></span></tt> statement. However, a term rewriting macro should not change the semantics anyway. In fact, they can be deactivated with the <tt class="docutils literal"><span class="pre option">--patterns:off</span></tt> command line option or temporarily with the <tt class="docutils literal"><span class="pre"><span class="Identifier">patterns</span></span></tt> pragma.</p>
- <h3><a class="toc-backref" id="pattern-operators-the-nim-operator" href="#pattern-operators-the-nim-operator">The <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Punctuation">}</span></span></tt> operator</a></h3><p>A pattern expression can be bound to a pattern parameter via the <tt class="docutils literal"><span class="pre"><span class="Identifier">expr</span><span class="Punctuation">{</span><span class="Identifier">param</span><span class="Punctuation">}</span></span></tt> notation:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">t</span><span class="Punctuation">{</span><span class="Punctuation">(</span><span class="DecNumber">0</span><span class="Operator">|</span><span class="DecNumber">1</span><span class="Operator">|</span><span class="DecNumber">2</span><span class="Punctuation">)</span><span class="Punctuation">{</span><span class="Identifier">x</span><span class="Punctuation">}</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="Identifier">x</span> <span class="Operator">+</span> <span class="DecNumber">1</span>
- <span class="Keyword">let</span> <span class="Identifier">a</span> <span class="Operator">=</span> <span class="DecNumber">1</span>
- <span class="Comment"># outputs 2:</span>
- <span class="Identifier">echo</span> <span class="Identifier">a</span></pre></p>
- <h3><a class="toc-backref" id="pattern-operators-the-nimtilde-operator" href="#pattern-operators-the-nimtilde-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">~</span></span></tt> operator</a></h3><p>The <tt class="docutils literal"><span class="pre"><span class="Operator">~</span></span></tt> operator is the 'not' operator in patterns:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">t</span><span class="Punctuation">{</span><span class="Identifier">x</span> <span class="Operator">=</span> <span class="Punctuation">(</span><span class="Operator">~</span><span class="Identifier">x</span><span class="Punctuation">)</span><span class="Punctuation">{</span><span class="Identifier">y</span><span class="Punctuation">}</span> <span class="Keyword">and</span> <span class="Punctuation">(</span><span class="Operator">~</span><span class="Identifier">x</span><span class="Punctuation">)</span><span class="Punctuation">{</span><span class="Identifier">z</span><span class="Punctuation">}</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Identifier">z</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">y</span>
- <span class="Keyword">if</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">z</span>
- <span class="Keyword">var</span>
- <span class="Identifier">a</span> <span class="Operator">=</span> <span class="Identifier">false</span>
- <span class="Identifier">b</span> <span class="Operator">=</span> <span class="Identifier">true</span>
- <span class="Identifier">c</span> <span class="Operator">=</span> <span class="Identifier">false</span>
- <span class="Identifier">a</span> <span class="Operator">=</span> <span class="Identifier">b</span> <span class="Keyword">and</span> <span class="Identifier">c</span>
- <span class="Identifier">echo</span> <span class="Identifier">a</span></pre></p>
- <h3><a class="toc-backref" id="pattern-operators-the-nimstar-operator" href="#pattern-operators-the-nimstar-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> operator</a></h3><p>The <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> operator can <em>flatten</em> a nested binary expression like <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span> <span class="Operator">&</span> <span class="Identifier">b</span> <span class="Operator">&</span> <span class="Identifier">c</span></span></tt> to <tt class="docutils literal"><span class="pre"><span class="Operator">&</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">,</span> <span class="Identifier">c</span><span class="Punctuation">)</span></span></tt>:</p>
- <p><pre class="listing"><span class="Keyword">var</span>
- <span class="Identifier">calls</span> <span class="Operator">=</span> <span class="DecNumber">0</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">&&</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Identifier">result</span> <span class="Operator">=</span> <span class="Identifier">s</span><span class="Punctuation">[</span><span class="DecNumber">0</span><span class="Punctuation">]</span>
- <span class="Keyword">for</span> <span class="Identifier">i</span> <span class="Keyword">in</span> <span class="FloatNumber">1.</span><span class="Operator">.</span><span class="Identifier">len</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">)</span><span class="Operator">-</span><span class="DecNumber">1</span><span class="Punctuation">:</span> <span class="Identifier">result</span><span class="Operator">.</span><span class="Identifier">add</span> <span class="Identifier">s</span><span class="Punctuation">[</span><span class="Identifier">i</span><span class="Punctuation">]</span>
- <span class="Identifier">inc</span> <span class="Identifier">calls</span>
- <span class="Keyword">template</span> <span class="Identifier">optConc</span><span class="Punctuation">{</span> <span class="Punctuation">`</span><span class="Operator">&&</span><span class="Punctuation">`</span> <span class="Operator">*</span> <span class="Identifier">a</span> <span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="Operator">&&</span><span class="Identifier">a</span>
- <span class="Keyword">let</span> <span class="Identifier">space</span> <span class="Operator">=</span> <span class="StringLit">" "</span>
- <span class="Identifier">echo</span> <span class="StringLit">"my"</span> <span class="Operator">&&</span> <span class="Punctuation">(</span><span class="Identifier">space</span> <span class="Operator">&</span> <span class="StringLit">"awe"</span> <span class="Operator">&&</span> <span class="StringLit">"some "</span> <span class="Punctuation">)</span> <span class="Operator">&&</span> <span class="StringLit">"concat"</span>
- <span class="Comment"># check that it's been optimized properly:</span>
- <span class="Identifier">doAssert</span> <span class="Identifier">calls</span> <span class="Operator">==</span> <span class="DecNumber">1</span></pre></p>
- <p>The second operator of <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> must be a parameter; it is used to gather all the arguments. The expression <tt class="docutils literal"><span class="pre"><span class="StringLit">"my"</span> <span class="Operator">&&</span> <span class="Punctuation">(</span><span class="Identifier">space</span> <span class="Operator">&</span> <span class="StringLit">"awe"</span> <span class="Operator">&&</span> <span class="StringLit">"some "</span> <span class="Punctuation">)</span> <span class="Operator">&&</span> <span class="StringLit">"concat"</span></span></tt> is passed to <tt class="docutils literal"><span class="pre"><span class="Identifier">optConc</span></span></tt> in <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span></span></tt> as a special list (of kind <tt class="docutils literal"><span class="pre"><span class="Identifier">nkArgList</span></span></tt>) which is flattened into a call expression; thus the invocation of <tt class="docutils literal"><span class="pre"><span class="Identifier">optConc</span></span></tt> produces:</p>
- <p><pre class="listing"><span class="Punctuation">`</span><span class="Operator">&&</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="StringLit">"my"</span><span class="Punctuation">,</span> <span class="Identifier">space</span> <span class="Operator">&</span> <span class="StringLit">"awe"</span><span class="Punctuation">,</span> <span class="StringLit">"some "</span><span class="Punctuation">,</span> <span class="StringLit">"concat"</span><span class="Punctuation">)</span></pre></p>
- <h3><a class="toc-backref" id="pattern-operators-the-nimstarstar-operator" href="#pattern-operators-the-nimstarstar-operator">The <tt class="docutils literal"><span class="pre"><span class="Operator">**</span></span></tt> operator</a></h3><p>The <tt class="docutils literal"><span class="pre"><span class="Operator">**</span></span></tt> is much like the <tt class="docutils literal"><span class="pre"><span class="Operator">*</span></span></tt> operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation:</p>
- <p><pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">macros</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Matrix</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">dummy</span><span class="Punctuation">:</span> <span class="Identifier">int</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span> <span class="Operator">=</span> <span class="Keyword">discard</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">+</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span> <span class="Operator">=</span> <span class="Keyword">discard</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">-</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span> <span class="Operator">=</span> <span class="Keyword">discard</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">$</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span> <span class="Identifier">result</span> <span class="Operator">=</span> <span class="Operator">$</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">dummy</span>
- <span class="Keyword">proc</span> <span class="Identifier">mat21</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span> <span class="Operator">=</span>
- <span class="Identifier">result</span><span class="Operator">.</span><span class="Identifier">dummy</span> <span class="Operator">=</span> <span class="DecNumber">21</span>
- <span class="Keyword">macro</span> <span class="Identifier">optM</span><span class="Punctuation">{</span> <span class="Punctuation">(</span><span class="Punctuation">`</span><span class="Operator">+</span><span class="Punctuation">`</span><span class="Operator">|</span><span class="Punctuation">`</span><span class="Operator">-</span><span class="Punctuation">`</span><span class="Operator">|</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">`</span><span class="Punctuation">)</span> <span class="Operator">**</span> <span class="Identifier">a</span> <span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="Identifier">treeRepr</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">)</span>
- <span class="Identifier">result</span> <span class="Operator">=</span> <span class="Identifier">newCall</span><span class="Punctuation">(</span><span class="RawData">bindSym"mat21"</span><span class="Punctuation">)</span>
- <span class="Keyword">var</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Identifier">z</span><span class="Punctuation">:</span> <span class="Identifier">Matrix</span>
- <span class="Identifier">echo</span> <span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">y</span> <span class="Operator">*</span> <span class="Identifier">z</span> <span class="Operator">-</span> <span class="Identifier">x</span></pre></p>
- <p>This passes the expression <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">y</span> <span class="Operator">*</span> <span class="Identifier">z</span> <span class="Operator">-</span> <span class="Identifier">x</span></span></tt> to the <tt class="docutils literal"><span class="pre"><span class="Identifier">optM</span></span></tt> macro as an <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkArgList</span></span></tt> node containing:</p>
- <pre>Arglist
- Sym "x"
- Sym "y"
- Sym "z"
- Sym "*"
- Sym "+"
- Sym "x"
- Sym "-"</pre>
- <p>(This is the reverse polish notation of <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">y</span> <span class="Operator">*</span> <span class="Identifier">z</span> <span class="Operator">-</span> <span class="Identifier">x</span></span></tt>.)</p>
- <h2><a class="toc-backref" id="term-rewriting-macros-parameters" href="#term-rewriting-macros-parameters">Parameters</a></h2><p>Parameters in a pattern are type checked in the matching process. If a parameter is of the type <tt class="docutils literal"><span class="pre"><span class="Identifier">varargs</span></span></tt>, it is treated specially and can match 0 or more arguments in the AST to be matched against:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">optWrite</span><span class="Punctuation">{</span>
- <span class="Identifier">write</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">,</span> <span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Punctuation">(</span><span class="Punctuation">(</span><span class="Identifier">write</span><span class="Operator">|</span><span class="Identifier">writeLine</span><span class="Punctuation">)</span><span class="Punctuation">{</span><span class="Identifier">w</span><span class="Punctuation">}</span><span class="Punctuation">)</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">)</span>
- <span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">untyped</span><span class="Punctuation">]</span><span class="Punctuation">,</span> <span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">File</span><span class="Punctuation">,</span> <span class="Identifier">w</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">w</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">,</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">)</span></pre></p>
- <h2><a class="toc-backref" id="term-rewriting-macros-norewrite-pragma" href="#term-rewriting-macros-norewrite-pragma">noRewrite pragma</a></h2><p>Term rewriting macros and templates are currently greedy and they will rewrite as long as there is a match. There was no way to ensure some rewrite happens only once, e.g. when rewriting term to same term plus extra content.</p>
- <p><tt class="docutils literal"><span class="pre"><span class="Identifier">noRewrite</span></span></tt> pragma can actually prevent further rewriting on marked code, e.g. with given example <tt class="docutils literal"><span class="pre"><span class="Identifier">echo</span><span class="Punctuation">(</span><span class="StringLit">"ab"</span><span class="Punctuation">)</span></span></tt> will be rewritten just once:</p>
- <p><pre class="listing"><span class="Keyword">template</span> <span class="Identifier">pwnEcho</span><span class="Punctuation">{</span><span class="Identifier">echo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">noRewrite</span><span class="Operator">.</span><span class="Punctuation">}</span><span class="Punctuation">:</span> <span class="Identifier">echo</span><span class="Punctuation">(</span><span class="StringLit">"pwned!"</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="StringLit">"ab"</span></pre></p>
- <p><tt class="docutils literal"><span class="pre"><span class="Identifier">noRewrite</span></span></tt> pragma can be useful to control term-rewriting macros recursion.</p>
- <h2><a class="toc-backref" id="term-rewriting-macros-examplecolon-partial-evaluation" href="#term-rewriting-macros-examplecolon-partial-evaluation">Example: Partial evaluation</a></h2><p>The following example shows how some simple partial evaluation can be implemented with term rewriting:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">;</span> <span class="Identifier">cond</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">int</span> <span class="Operator">=</span>
- <span class="Identifier">result</span> <span class="Operator">=</span> <span class="Keyword">if</span> <span class="Identifier">cond</span><span class="Punctuation">:</span> <span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">y</span> <span class="Keyword">else</span><span class="Punctuation">:</span> <span class="Identifier">x</span> <span class="Operator">-</span> <span class="Identifier">y</span>
- <span class="Keyword">template</span> <span class="Identifier">optP1</span><span class="Punctuation">{</span><span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Identifier">true</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="Identifier">x</span> <span class="Operator">+</span> <span class="Identifier">y</span>
- <span class="Keyword">template</span> <span class="Identifier">optP2</span><span class="Punctuation">{</span><span class="Identifier">p</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">,</span> <span class="Identifier">false</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span> <span class="Identifier">x</span> <span class="Operator">-</span> <span class="Identifier">y</span></pre></p>
- <h2><a class="toc-backref" id="term-rewriting-macros-examplecolon-hoisting" href="#term-rewriting-macros-examplecolon-hoisting">Example: Hoisting</a></h2><p>The following example shows how some form of hoisting can be implemented:</p>
- <p><pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">pegs</span>
- <span class="Keyword">template</span> <span class="Identifier">optPeg</span><span class="Punctuation">{</span><span class="Identifier">peg</span><span class="Punctuation">(</span><span class="Identifier">pattern</span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">(</span><span class="Identifier">pattern</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">{</span><span class="Identifier">lit</span><span class="Punctuation">}</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Peg</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">gl</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">global</span><span class="Punctuation">,</span> <span class="Identifier">gensym</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Identifier">peg</span><span class="Punctuation">(</span><span class="Identifier">pattern</span><span class="Punctuation">)</span>
- <span class="Identifier">gl</span>
- <span class="Keyword">for</span> <span class="Identifier">i</span> <span class="Keyword">in</span> <span class="DecNumber">0</span> <span class="Operator">..</span> <span class="DecNumber">3</span><span class="Punctuation">:</span>
- <span class="Identifier">echo</span> <span class="Identifier">match</span><span class="Punctuation">(</span><span class="StringLit">"(a b c)"</span><span class="Punctuation">,</span> <span class="RawData">peg"'(' @ ')'"</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="Identifier">match</span><span class="Punctuation">(</span><span class="StringLit">"W_HI_Le"</span><span class="Punctuation">,</span> <span class="RawData">peg"\y 'while'"</span><span class="Punctuation">)</span></pre></p>
- <p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">optPeg</span></span></tt> template optimizes the case of a peg constructor with a string literal, so that the pattern will only be parsed once at program startup and stored in a global <tt class="docutils literal"><span class="pre"><span class="Identifier">gl</span></span></tt> which is then re-used. This optimization is called hoisting because it is comparable to classical loop hoisting.</p>
- <h1><a class="toc-backref" id="ast-based-overloading" href="#ast-based-overloading">AST based overloading</a></h1><p>Parameter constraints can also be used for ordinary routine parameters; these constraints then affect ordinary overloading resolution:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">optLit</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">{</span><span class="Identifier">lit</span><span class="Operator">|</span><span class="Punctuation">`</span><span class="Keyword">const</span><span class="Punctuation">`</span><span class="Punctuation">}</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"string literal"</span>
- <span class="Keyword">proc</span> <span class="Identifier">optLit</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"no string literal"</span>
- <span class="Keyword">const</span>
- <span class="Identifier">constant</span> <span class="Operator">=</span> <span class="StringLit">"abc"</span>
- <span class="Keyword">var</span>
- <span class="Identifier">variable</span> <span class="Operator">=</span> <span class="StringLit">"xyz"</span>
- <span class="Identifier">optLit</span><span class="Punctuation">(</span><span class="StringLit">"literal"</span><span class="Punctuation">)</span>
- <span class="Identifier">optLit</span><span class="Punctuation">(</span><span class="Identifier">constant</span><span class="Punctuation">)</span>
- <span class="Identifier">optLit</span><span class="Punctuation">(</span><span class="Identifier">variable</span><span class="Punctuation">)</span></pre></p>
- <p>However, the constraints <tt class="docutils literal"><span class="pre"><span class="Identifier">alias</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">noalias</span></span></tt> are not available in ordinary routines.</p>
- <h1><a class="toc-backref" id="parallel-amp-spawn" href="#parallel-amp-spawn">Parallel & Spawn</a></h1><p>Nim has two flavors of parallelism:</p>
- <ol class="simple"><li><span id="structured_1">Structured</span> parallelism via the <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> statement.</li>
- <li><span id="unstructured_1">Unstructured</span> parallelism via the standalone <tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt> statement.</li>
- </ol>
- <p>Nim has a builtin thread pool that can be used for CPU intensive tasks. For IO intensive tasks the <tt class="docutils literal"><span class="pre"><span class="Identifier">async</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">await</span></span></tt> features should be used instead. Both parallel and spawn need the <a class="reference external" href="threadpool.html">threadpool</a> module to work.</p>
- <p>Somewhat confusingly, <tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt> is also used in the <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> statement with slightly different semantics. <tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt> always takes a call expression of the form <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span></span></tt>. Let <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> be <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt>'s return type. If <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt>, then <tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt>'s return type is also <tt class="docutils literal"><span class="pre"><span class="Identifier">void</span></span></tt>, otherwise it is <tt class="docutils literal"><span class="pre"><span class="Identifier">FlowVar</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt>.</p>
- <p>Within a <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> section, the <tt class="docutils literal"><span class="pre"><span class="Identifier">FlowVar</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> is sometimes eliminated to <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>. This happens when <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> does not contain any GC'ed memory. The compiler can ensure the location in <tt class="docutils literal"><span class="pre"><span class="Identifier">location</span> <span class="Operator">=</span> <span class="Identifier">spawn</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Operator">...</span><span class="Punctuation">)</span></span></tt> is not read prematurely within a <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> section and so there is no need for the overhead of an indirection via <tt class="docutils literal"><span class="pre"><span class="Identifier">FlowVar</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> to ensure correctness.</p>
- <div class="admonition admonition-info"><span class="admonition-info-text"><b>Note:</b></span>
- Currently exceptions are not propagated between <tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt>'ed tasks!</div>
- <p>This feature is likely to be removed in the future as external packages can have better solutions.</p>
- <h2><a class="toc-backref" id="parallel-amp-spawn-spawn-statement" href="#parallel-amp-spawn-spawn-statement">Spawn statement</a></h2><p>The <span id="spawn_1">spawn</span> statement can be used to pass a task to the thread pool:</p>
- <p><pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">threadpool</span>
- <span class="Keyword">proc</span> <span class="Identifier">processLine</span><span class="Punctuation">(</span><span class="Identifier">line</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">discard</span> <span class="StringLit">"do some heavy lifting here"</span>
- <span class="Keyword">for</span> <span class="Identifier">x</span> <span class="Keyword">in</span> <span class="Identifier">lines</span><span class="Punctuation">(</span><span class="StringLit">"myinput.txt"</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Identifier">spawn</span> <span class="Identifier">processLine</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span>
- <span class="Identifier">sync</span><span class="Punctuation">(</span><span class="Punctuation">)</span></pre></p>
- <p>For reasons of type safety and implementation simplicity the expression that <tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt> takes is restricted:</p>
- <ul class="simple"><li>It must be a call expression <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span></span></tt>.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt> must be <tt class="docutils literal"><span class="pre"><span class="Identifier">gcsafe</span></span></tt>.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt> must not have the calling convention <tt class="docutils literal"><span class="pre"><span class="Identifier">closure</span></span></tt>.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt>'s parameters may not be of type <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt>. This means one has to use raw <tt class="docutils literal"><span class="pre"><span class="Keyword">ptr</span></span></tt>'s for data passing reminding the programmer to be careful.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt> parameters are deeply copied, which is a subtle semantic change and can cause performance problems, but ensures memory safety. This deep copy is performed via <tt class="docutils literal"><span class="pre"><span class="Identifier">system</span><span class="Operator">.</span><span class="Identifier">deepCopy</span></span></tt>, so it can be overridden.</li>
- <li>For <em>safe</em> data exchange between <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt> and the caller, a global <tt class="docutils literal"><span class="pre"><span class="Identifier">Channel</span></span></tt> needs to be used. However, since spawn can return a result, often no further communication is required.</li>
- </ul>
- <p><tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt> executes the passed expression on the thread pool and returns a <span id="data-flow-variable_1">data flow variable</span> <tt class="docutils literal"><span class="pre"><span class="Identifier">FlowVar</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> that can be read from. The reading with the <tt class="docutils literal"><span class="pre"><span class="Operator">^</span></span></tt> operator is <strong>blocking</strong>. However, one can use <tt class="docutils literal"><span class="pre"><span class="Identifier">blockUntilAny</span></span></tt> to wait on multiple flow variables at the same time:</p>
- <p><pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">threadpool</span><span class="Punctuation">,</span> <span class="Operator">...</span>
- <span class="Comment"># wait until 2 out of 3 servers received the update:</span>
- <span class="Keyword">proc</span> <span class="Identifier">main</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">responses</span> <span class="Operator">=</span> <span class="Identifier">newSeq</span><span class="Punctuation">[</span><span class="Identifier">FlowVarBase</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="DecNumber">3</span><span class="Punctuation">)</span>
- <span class="Keyword">for</span> <span class="Identifier">i</span> <span class="Keyword">in</span> <span class="FloatNumber">0.</span><span class="Operator">.</span><span class="DecNumber">2</span><span class="Punctuation">:</span>
- <span class="Identifier">responses</span><span class="Punctuation">[</span><span class="Identifier">i</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">spawn</span> <span class="Identifier">tellServer</span><span class="Punctuation">(</span><span class="Identifier">Update</span><span class="Punctuation">,</span> <span class="StringLit">"key"</span><span class="Punctuation">,</span> <span class="StringLit">"value"</span><span class="Punctuation">)</span>
- <span class="Keyword">var</span> <span class="Identifier">index</span> <span class="Operator">=</span> <span class="Identifier">blockUntilAny</span><span class="Punctuation">(</span><span class="Identifier">responses</span><span class="Punctuation">)</span>
- <span class="Identifier">assert</span> <span class="Identifier">index</span> <span class="Operator">>=</span> <span class="DecNumber">0</span>
- <span class="Identifier">responses</span><span class="Operator">.</span><span class="Identifier">del</span><span class="Punctuation">(</span><span class="Identifier">index</span><span class="Punctuation">)</span>
- <span class="Keyword">discard</span> <span class="Identifier">blockUntilAny</span><span class="Punctuation">(</span><span class="Identifier">responses</span><span class="Punctuation">)</span></pre></p>
- <p>Data flow variables ensure that no data races are possible. Due to technical limitations, not every type <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> can be used in a data flow variable: <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> has to be a <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">seq</span></span></tt> or of a type that doesn't contain any GC'd type. This restriction is not hard to work-around in practice.</p>
- <h2><a class="toc-backref" id="parallel-amp-spawn-parallel-statement" href="#parallel-amp-spawn-parallel-statement">Parallel statement</a></h2><p>Example:</p>
- <p><pre class="listing"><span class="Comment"># Compute pi in an inefficient way</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Punctuation">[</span><span class="Identifier">strutils</span><span class="Punctuation">,</span> <span class="Identifier">math</span><span class="Punctuation">,</span> <span class="Identifier">threadpool</span><span class="Punctuation">]</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"parallel"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">term</span><span class="Punctuation">(</span><span class="Identifier">k</span><span class="Punctuation">:</span> <span class="Identifier">float</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">float</span> <span class="Operator">=</span> <span class="DecNumber">4</span> <span class="Operator">*</span> <span class="Identifier">math</span><span class="Operator">.</span><span class="Identifier">pow</span><span class="Punctuation">(</span><span class="Operator">-</span><span class="DecNumber">1</span><span class="Punctuation">,</span> <span class="Identifier">k</span><span class="Punctuation">)</span> <span class="Operator">/</span> <span class="Punctuation">(</span><span class="DecNumber">2</span><span class="Operator">*</span><span class="Identifier">k</span> <span class="Operator">+</span> <span class="DecNumber">1</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">pi</span><span class="Punctuation">(</span><span class="Identifier">n</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">float</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">ch</span> <span class="Operator">=</span> <span class="Identifier">newSeq</span><span class="Punctuation">[</span><span class="Identifier">float</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">n</span> <span class="Operator">+</span> <span class="DecNumber">1</span><span class="Punctuation">)</span>
- <span class="Identifier">parallel</span><span class="Punctuation">:</span>
- <span class="Keyword">for</span> <span class="Identifier">k</span> <span class="Keyword">in</span> <span class="FloatNumber">0.</span><span class="Operator">.</span><span class="Identifier">ch</span><span class="Operator">.</span><span class="Identifier">high</span><span class="Punctuation">:</span>
- <span class="Identifier">ch</span><span class="Punctuation">[</span><span class="Identifier">k</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="Identifier">spawn</span> <span class="Identifier">term</span><span class="Punctuation">(</span><span class="Identifier">float</span><span class="Punctuation">(</span><span class="Identifier">k</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Keyword">for</span> <span class="Identifier">k</span> <span class="Keyword">in</span> <span class="FloatNumber">0.</span><span class="Operator">.</span><span class="Identifier">ch</span><span class="Operator">.</span><span class="Identifier">high</span><span class="Punctuation">:</span>
- <span class="Identifier">result</span> <span class="Operator">+=</span> <span class="Identifier">ch</span><span class="Punctuation">[</span><span class="Identifier">k</span><span class="Punctuation">]</span>
- <span class="Identifier">echo</span> <span class="Identifier">formatFloat</span><span class="Punctuation">(</span><span class="Identifier">pi</span><span class="Punctuation">(</span><span class="DecNumber">5000</span><span class="Punctuation">)</span><span class="Punctuation">)</span></pre></p>
- <p>The parallel statement is the preferred mechanism to introduce parallelism in a Nim program. Only a subset of the Nim language is valid within a <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> section. This subset is checked during semantic analysis to be free of data races. A sophisticated <span id="disjoint-checker_1">disjoint checker</span> ensures that no data races are possible, even though shared memory is extensively supported!</p>
- <p>The subset is in fact the full language with the following restrictions / changes:</p>
- <ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span></span></tt> within a <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> section has special semantics.</li>
- <li>Every location of the form <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="Identifier">i</span><span class="Punctuation">]</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">a</span><span class="Punctuation">[</span><span class="Identifier">i</span><span class="Operator">..</span><span class="Identifier">j</span><span class="Punctuation">]</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">dest</span></span></tt> where <tt class="docutils literal"><span class="pre"><span class="Identifier">dest</span></span></tt> is part of the pattern <tt class="docutils literal"><span class="pre"><span class="Identifier">dest</span> <span class="Operator">=</span> <span class="Identifier">spawn</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Operator">...</span><span class="Punctuation">)</span></span></tt> has to be provably disjoint. This is called the <em>disjoint check</em>.</li>
- <li>Every other complex location <tt class="docutils literal"><span class="pre"><span class="Identifier">loc</span></span></tt> that is used in a spawned proc (<tt class="docutils literal"><span class="pre"><span class="Identifier">spawn</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">loc</span><span class="Punctuation">)</span></span></tt>) has to be immutable for the duration of the <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> section. This is called the <em>immutability check</em>. Currently it is not specified what exactly "complex location" means. We need to make this an optimization!</li>
- <li>Every array access has to be provably within bounds. This is called the <em>bounds check</em>.</li>
- <li>Slices are optimized so that no copy is performed. This optimization is not yet performed for ordinary slices outside of a <tt class="docutils literal"><span class="pre"><span class="Identifier">parallel</span></span></tt> section.</li>
- </ul>
- <h1><a class="toc-backref" id="strict-case-objects" href="#strict-case-objects">Strict case objects</a></h1><p>With <tt class="docutils literal"><span class="pre"><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"strictCaseObjects"</span></span></tt> <em>every</em> field access is checked to be valid at compile-time. The field is within a <tt class="docutils literal"><span class="pre"><span class="Keyword">case</span></span></tt> section of an <tt class="docutils literal"><span class="pre"><span class="Keyword">object</span></span></tt>.</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"strictCaseObjects"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Foo</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Keyword">case</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">bool</span>
- <span class="Keyword">of</span> <span class="Identifier">false</span><span class="Punctuation">:</span>
- <span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
- <span class="Keyword">of</span> <span class="Identifier">true</span><span class="Punctuation">:</span>
- <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span>
- <span class="Keyword">var</span> <span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">Foo</span><span class="Punctuation">(</span><span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">true</span><span class="Punctuation">,</span> <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="DecNumber">4</span><span class="Punctuation">)</span>
- <span class="Keyword">case</span> <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">b</span>
- <span class="Keyword">of</span> <span class="Identifier">true</span><span class="Punctuation">:</span>
- <span class="Identifier">echo</span> <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Comment"># valid</span>
- <span class="Keyword">of</span> <span class="Identifier">false</span><span class="Punctuation">:</span>
- <span class="Identifier">echo</span> <span class="StringLit">"no"</span>
- <span class="Keyword">case</span> <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">b</span>
- <span class="Keyword">of</span> <span class="Identifier">false</span><span class="Punctuation">:</span>
- <span class="Identifier">echo</span> <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Comment"># error: field access outside of valid case branch: x.x</span>
- <span class="Keyword">of</span> <span class="Identifier">true</span><span class="Punctuation">:</span>
- <span class="Identifier">echo</span> <span class="StringLit">"no"</span>
- </pre></p>
- <p><strong>Note</strong>: The implementation of "strict case objects" is experimental but the concept is solid and it is expected that eventually this mode becomes the default in later versions.</p>
- <h1><a class="toc-backref" id="quirky-routines" href="#quirky-routines">Quirky routines</a></h1><p>The default code generation strategy of exceptions under the ARC/ORC model is the so called <tt class="docutils literal"><span class="pre"><span class="Operator">--</span><span class="Identifier">exceptions</span><span class="Punctuation">:</span><span class="Identifier">goto</span></span></tt> implementation. This implementation inserts a check after every call that can potentially raise an exception. A typical instruction sequence for this on for a x86 64 bit machine looks like:</p>
- <p><pre class="listing">cmp DWORD PTR [rbx], 0
- je .L1</pre></p>
- <p>This is a memory fetch followed by jump. (An ideal implementation would use the carry flag and a single instruction like <tt class="docutils literal"><span class="pre">jc .L1</span></tt>.)</p>
- <p>This overhead might not be desired and depending on the semantics of the routine may not be required either. So it can be disabled via a <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">quirky</span></span></tt> annotation:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">wontRaise</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">quirky</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Keyword">if</span> <span class="Identifier">x</span> <span class="Operator">!=</span> <span class="DecNumber">0</span><span class="Punctuation">:</span>
- <span class="Comment"># because of `quirky` this will continue even if `write` raised an IO exception:</span>
- <span class="Identifier">write</span> <span class="Identifier">x</span>
- <span class="Identifier">wontRaise</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Operator">-</span><span class="DecNumber">1</span><span class="Punctuation">)</span>
- <span class="Identifier">wontRaise</span> <span class="DecNumber">10</span>
- </pre></p>
- <p>If the used exception model is not <tt class="docutils literal"><span class="pre"><span class="Operator">--</span><span class="Identifier">exceptions</span><span class="Punctuation">:</span><span class="Identifier">goto</span></span></tt> then the <tt class="docutils literal"><span class="pre"><span class="Identifier">quirky</span></span></tt> pragma has no effect and is ignored.</p>
- <p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">quirky</span></span></tt> pragma can also be be pushed in order to affect a group of routines and whether the compiler supports the pragma can be checked with <tt class="docutils literal"><span class="pre"><span class="Identifier">defined</span><span class="Punctuation">(</span><span class="Identifier">nimHasQuirky</span><span class="Punctuation">)</span></span></tt>:</p>
- <p><pre class="listing"><span class="Keyword">when</span> <span class="Identifier">defined</span><span class="Punctuation">(</span><span class="Identifier">nimHasQuirky</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">push</span> <span class="Identifier">quirky</span><span class="Punctuation">:</span> <span class="Identifier">on</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">doRaise</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Keyword">raise</span> <span class="Identifier">newException</span><span class="Punctuation">(</span><span class="Identifier">ValueError</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span> <span class="StringLit">"abc"</span>
- <span class="Keyword">proc</span> <span class="Identifier">q</span><span class="Punctuation">(</span><span class="Identifier">cond</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">if</span> <span class="Identifier">cond</span><span class="Punctuation">:</span>
- <span class="Identifier">doRaise</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="Identifier">f</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Identifier">q</span><span class="Punctuation">(</span><span class="Identifier">true</span><span class="Punctuation">)</span>
- <span class="Keyword">when</span> <span class="Identifier">defined</span><span class="Punctuation">(</span><span class="Identifier">nimHasQuirky</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">pop</span><span class="Operator">.</span><span class="Punctuation">}</span></pre></p>
- <p><strong>Warning</strong>: The <tt class="docutils literal"><span class="pre"><span class="Identifier">quirky</span></span></tt> pragma only affects code generation, no check for validity is performed!</p>
- <h1><a class="toc-backref" id="threading-under-arcslashorc" href="#threading-under-arcslashorc">Threading under ARC/ORC</a></h1><p>ARC/ORC supports a shared heap out of the box. This means that messages can be sent between threads without copies. However, without copying the data there is an inherent danger of data races. Data races are prevented at compile-time if it is enforced that only <strong>isolated</strong> subgraphs can be sent around.</p>
- <h2><a class="toc-backref" id="threading-under-arcslashorc-isolation" href="#threading-under-arcslashorc-isolation">Isolation</a></h2><p>The standard library module <tt class="docutils literal"><span class="pre"><span class="Identifier">isolation</span><span class="Operator">.</span><span class="Identifier">nim</span></span></tt> provides a generic type <tt class="docutils literal"><span class="pre"><span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> that captures the important notion that nothing else can reference the graph that is wrapped inside <tt class="docutils literal"><span class="pre"><span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt>. It is what a channel implementation should use in order to enforce the freedom of data races:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">send</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">c</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Channel</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">;</span> <span class="Identifier">msg</span><span class="Punctuation">:</span> <span class="Identifier">sink</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">recv</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">c</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Channel</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">T</span>
- <span class="Comment">## Note: Returns T, not Isolated[T] for convenience.</span>
- <span class="Keyword">proc</span> <span class="Identifier">recvIso</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">c</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Channel</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span>
- <span class="Comment">## remembers the data is Isolated[T].</span></pre></p>
- <p>In order to create an <tt class="docutils literal"><span class="pre"><span class="Identifier">Isolated</span></span></tt> graph one has to use either <tt class="docutils literal"><span class="pre"><span class="Identifier">isolate</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Identifier">unsafeIsolate</span></span></tt>. <tt class="docutils literal"><span class="pre"><span class="Identifier">unsafeIsolate</span></span></tt> is as its name says unsafe and no checking is performed. It should be considered to be as dangerous as a <tt class="docutils literal"><span class="pre"><span class="Keyword">cast</span></span></tt> operation.</p>
- <p>Construction must ensure that the invariant holds, namely that the wrapped <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is free of external aliases into it. <tt class="docutils literal"><span class="pre"><span class="Identifier">isolate</span></span></tt> ensures this invariant. It is inspired by Pony's <tt class="docutils literal"><span class="pre"><span class="Identifier">recover</span></span></tt> construct:</p>
- <p><pre class="listing"><span class="Keyword">func</span> <span class="Identifier">isolate</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">sink</span> <span class="Identifier">T</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">magic</span><span class="Punctuation">:</span> <span class="StringLit">"Isolate"</span><span class="Operator">.</span><span class="Punctuation">}</span></pre></p>
- <p>As you can see, this is a new builtin because the check it performs on <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> is non-trivial:</p>
- <p>If <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> does not contain a <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Identifier">closure</span></span></tt> type, it is isolated. Else the syntactic structure of <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> is analyzed:</p>
- <ul class="simple"><li>Literals like <tt class="docutils literal"><span class="pre"><span class="Keyword">nil</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="DecNumber">4</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="StringLit">"abc"</span></span></tt> are isolated.</li>
- <li>A local variable or a routine parameter is isolated if either of these conditions is true:<ol class="simple"><li>Its type is annotated with the <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">sendable</span></span></tt> pragma. Note <tt class="docutils literal"><span class="pre"><span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt> is annotated as <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">sendable</span></span></tt>.</li>
- <li>Its type contains the potentially dangerous <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Keyword">proc</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">closure</span><span class="Punctuation">}</span></span></tt> types only in places that are protected via a <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">sendable</span></span></tt> container.</li>
- </ol>
- </li>
- <li>An array constructor <tt class="docutils literal"><span class="pre"><span class="Punctuation">[</span><span class="Identifier">x</span><span class="Operator">...</span><span class="Punctuation">]</span></span></tt> is isolated if every element <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> is isolated.</li>
- <li>An object constructor <tt class="docutils literal"><span class="pre"><span class="Identifier">Obj</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Operator">...</span><span class="Punctuation">)</span></span></tt> is isolated if every element <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> is isolated.</li>
- <li>An <tt class="docutils literal"><span class="pre"><span class="Keyword">if</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Keyword">case</span></span></tt> expression is isolated if all possible values the expression may return are isolated.</li>
- <li>A type conversion <tt class="docutils literal"><span class="pre"><span class="Identifier">C</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">)</span></span></tt> is isolated if <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> is isolated. Analogous for <tt class="docutils literal"><span class="pre"><span class="Keyword">cast</span></span></tt> expressions.</li>
- <li>A function call <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Operator">...</span><span class="Punctuation">)</span></span></tt> is isolated if <tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt> is <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">noSideEffect</span></span></tt> and for every argument <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt>:<ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> is isolated <strong>or</strong></li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">f</span></span></tt>'s return type cannot <em>alias</em> <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt>'s type. This is checked via a form of alias analysis as explained in the next paragraph.</li>
- </ul>
- </li>
- </ul>
- <h2><a class="toc-backref" id="threading-under-arcslashorc-alias-analysis" href="#threading-under-arcslashorc-alias-analysis">Alias analysis</a></h2><p>We start with an important, simple case that must be valid: Sending the result of <tt class="docutils literal"><span class="pre"><span class="Identifier">parseJson</span></span></tt> to a channel. Since the signature is <tt class="docutils literal"><span class="pre"><span class="Keyword">func</span> <span class="Identifier">parseJson</span><span class="Punctuation">(</span><span class="Identifier">input</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">JsonNode</span></span></tt> it is easy to see that JsonNode can never simply be a view into <tt class="docutils literal"><span class="pre"><span class="Identifier">input</span></span></tt> which is a <tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt>.</p>
- <p>A different case is the identity function <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">send</span> <span class="Identifier">id</span><span class="Punctuation">(</span><span class="Identifier">myJsonGraph</span><span class="Punctuation">)</span></span></tt> must be invalid because we do not know how many aliases into <tt class="docutils literal"><span class="pre"><span class="Identifier">myJsonGraph</span></span></tt> exist elsewhere.</p>
- <p>In general type <tt class="docutils literal"><span class="pre"><span class="Identifier">A</span></span></tt> can alias type <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> if:</p>
- <ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">A</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> are the same types.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">A</span></span></tt> is a distinct type derived from <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">A</span></span></tt> is a field inside <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> if <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is a final object type.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is an inheritable object type. (An inherited type could always contain a <tt class="docutils literal"><span class="pre"><span class="Identifier">field</span><span class="Punctuation">:</span> <span class="Identifier">A</span></span></tt>).</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is a closure type. Reason: <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt>'s environment can contain a field of type <tt class="docutils literal"><span class="pre"><span class="Identifier">A</span></span></tt>.</li>
- <li><tt class="docutils literal"><span class="pre"><span class="Identifier">A</span></span></tt> is the element type of <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> if <tt class="docutils literal"><span class="pre"><span class="Identifier">T</span></span></tt> is an array, sequence or pointer type.</li>
- </ul>
- <h2><a class="toc-backref" id="threading-under-arcslashorc-sendable-pragma" href="#threading-under-arcslashorc-sendable-pragma">Sendable pragma</a></h2><p>A container type can be marked as <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">sendable</span></span></tt>. <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">sendable</span></span></tt> declares that the type encapsulates a <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span></span></tt> type effectively so that a variable of this container type can be used in an <tt class="docutils literal"><span class="pre"><span class="Identifier">isolate</span></span></tt> context:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">Isolated</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">sendable</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Comment">## Isolated data can only be moved, not copied.</span>
- <span class="Identifier">value</span><span class="Punctuation">:</span> <span class="Identifier">T</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">=</span><span class="Identifier">copy</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">dest</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">;</span> <span class="Identifier">src</span><span class="Punctuation">:</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">error</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">=</span><span class="Identifier">sink</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">dest</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">;</span> <span class="Identifier">src</span><span class="Punctuation">:</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inline</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Comment"># delegate to value's sink operation</span>
- <span class="Punctuation">`</span><span class="Operator">=</span><span class="Identifier">sink</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">dest</span><span class="Operator">.</span><span class="Identifier">value</span><span class="Punctuation">,</span> <span class="Identifier">src</span><span class="Operator">.</span><span class="Identifier">value</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">=</span><span class="Identifier">destroy</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">dest</span><span class="Punctuation">:</span> <span class="Keyword">var</span> <span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inline</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Comment"># delegate to value's destroy operation</span>
- <span class="Punctuation">`</span><span class="Operator">=</span><span class="Identifier">destroy</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">dest</span><span class="Operator">.</span><span class="Identifier">value</span><span class="Punctuation">)</span></pre></p>
- <p>The <tt class="docutils literal"><span class="pre"><span class="Operator">.</span><span class="Identifier">sendable</span></span></tt> pragma itself is an experimenal, unchecked, unsafe annotation. It is currently only used by <tt class="docutils literal"><span class="pre"><span class="Identifier">Isolated</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span></span></tt>.</p>
- <h1><a class="toc-backref" id="virtual-pragma" href="#virtual-pragma">Virtual pragma</a></h1><p><tt class="docutils literal"><span class="pre"><span class="Identifier">virtual</span></span></tt> is designed to extend or create virtual functions when targeting the cpp backend. When a proc is marked with virtual, it forward declares the proc header within the type's body.</p>
- <p>Here's an example of how to use the virtual pragma:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">newCpp</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Keyword">ptr</span> <span class="Identifier">T</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">:</span> <span class="StringLit">"new '*0()"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Foo</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Keyword">of</span> <span class="Identifier">RootObj</span>
- <span class="Identifier">FooPtr</span> <span class="Operator">=</span> <span class="Keyword">ptr</span> <span class="Identifier">Foo</span>
- <span class="Identifier">Boo</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Keyword">of</span> <span class="Identifier">Foo</span>
- <span class="Identifier">BooPtr</span> <span class="Operator">=</span> <span class="Keyword">ptr</span> <span class="Identifier">Boo</span>
- <span class="Keyword">proc</span> <span class="Identifier">salute</span><span class="Punctuation">(</span><span class="Identifier">self</span><span class="Punctuation">:</span> <span class="Identifier">FooPtr</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">virtual</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"hello foo"</span>
- <span class="Keyword">proc</span> <span class="Identifier">salute</span><span class="Punctuation">(</span><span class="Identifier">self</span><span class="Punctuation">:</span> <span class="Identifier">BooPtr</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">virtual</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"hello boo"</span>
- <span class="Keyword">let</span> <span class="Identifier">foo</span> <span class="Operator">=</span> <span class="Identifier">newCpp</span><span class="Punctuation">[</span><span class="Identifier">Foo</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Keyword">let</span> <span class="Identifier">boo</span> <span class="Operator">=</span> <span class="Identifier">newCpp</span><span class="Punctuation">[</span><span class="Identifier">Boo</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Keyword">let</span> <span class="Identifier">booAsFoo</span> <span class="Operator">=</span> <span class="Keyword">cast</span><span class="Punctuation">[</span><span class="Identifier">FooPtr</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">newCpp</span><span class="Punctuation">[</span><span class="Identifier">Boo</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Identifier">foo</span><span class="Operator">.</span><span class="Identifier">salute</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># prints hello foo</span>
- <span class="Identifier">boo</span><span class="Operator">.</span><span class="Identifier">salute</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># prints hello boo</span>
- <span class="Identifier">booAsFoo</span><span class="Operator">.</span><span class="Identifier">salute</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># prints hello boo</span></pre> In this example, the <tt class="docutils literal"><span class="pre"><span class="Identifier">salute</span></span></tt> function is virtual in both Foo and Boo types. This allows for polymorphism.</p>
- <p>The virtual pragma also supports a special syntax to express Cpp constraints. Here's how it works:</p>
- <p><tt class="docutils literal"><span class="pre"><span class="Operator">$</span><span class="DecNumber">1</span></span></tt> refers to the function name <tt class="docutils literal"><span class="pre"><span class="CharLit">'idx</span></span></tt> refers to the type of the argument at the position idx. Where idx = 1 is the <tt class="docutils literal"><span class="pre"><span class="Identifier">this</span></span></tt> argument. <tt class="docutils literal"><span class="pre"><span class="Comment">#idx</span></span></tt> refers to the argument name.</p>
- <p>The return type can be referred to as <tt class="docutils literal"><span class="pre"><span class="Operator">-></span> <span class="CharLit">'0</span></span></tt>, but this is optional and often not needed.</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">emit</span><span class="Punctuation">:</span><span class="LongStringLit">"""/*TYPESECTION*/
- #include <iostream>
- class CppPrinter {
- public:
-
- virtual void printConst(char* message) const {
- std::cout << "Const Message: " << message << std::endl;
- }
- virtual void printConstRef(char* message, const int& flag) const {
- std::cout << "Const Ref Message: " << message << std::endl;
- }
- };
- """</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">CppPrinter</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">,</span> <span class="Identifier">inheritable</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">NimPrinter</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">exportc</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Keyword">of</span> <span class="Identifier">CppPrinter</span>
- <span class="Keyword">proc</span> <span class="Identifier">printConst</span><span class="Punctuation">(</span><span class="Identifier">self</span><span class="Punctuation">:</span> <span class="Identifier">CppPrinter</span><span class="Punctuation">;</span> <span class="Identifier">message</span><span class="Punctuation">:</span><span class="Identifier">cstring</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Identifier">CppPrinter</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Operator">.</span><span class="Identifier">printConst</span><span class="Punctuation">(</span><span class="Identifier">message</span><span class="Punctuation">)</span>
- <span class="Comment"># override is optional.</span>
- <span class="Keyword">proc</span> <span class="Identifier">printConst</span><span class="Punctuation">(</span><span class="Identifier">self</span><span class="Punctuation">:</span> <span class="Identifier">NimPrinter</span><span class="Punctuation">;</span> <span class="Identifier">message</span><span class="Punctuation">:</span> <span class="Identifier">cstring</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">virtual</span><span class="Punctuation">:</span> <span class="StringLit">"$1('2 #2) const override"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"NimPrinter: "</span> <span class="Operator">&</span> <span class="Operator">$</span><span class="Identifier">message</span>
- <span class="Keyword">proc</span> <span class="Identifier">printConstRef</span><span class="Punctuation">(</span><span class="Identifier">self</span><span class="Punctuation">:</span> <span class="Identifier">NimPrinter</span><span class="Punctuation">;</span> <span class="Identifier">message</span><span class="Punctuation">:</span> <span class="Identifier">cstring</span><span class="Punctuation">;</span> <span class="Identifier">flag</span><span class="Punctuation">:</span><span class="Identifier">int32</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">virtual</span><span class="Punctuation">:</span> <span class="StringLit">"$1('2 #2, const '3& #3 ) const override"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"NimPrinterConstRef: "</span> <span class="Operator">&</span> <span class="Operator">$</span><span class="Identifier">message</span>
- <span class="Identifier">NimPrinter</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Operator">.</span><span class="Identifier">printConst</span><span class="Punctuation">(</span><span class="Identifier">message</span><span class="Punctuation">)</span>
- <span class="Keyword">var</span> <span class="Identifier">val</span><span class="Punctuation">:</span> <span class="Identifier">int32</span> <span class="Operator">=</span> <span class="DecNumber">10</span>
- <span class="Identifier">NimPrinter</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Operator">.</span><span class="Identifier">printConstRef</span><span class="Punctuation">(</span><span class="Identifier">message</span><span class="Punctuation">,</span> <span class="Identifier">val</span><span class="Punctuation">)</span>
- </pre></p>
- <h1><a class="toc-backref" id="constructor-pragma" href="#constructor-pragma">Constructor pragma</a></h1><p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">constructor</span></span></tt> pragma can be used in two ways: in conjunction with <tt class="docutils literal"><span class="pre"><span class="Identifier">importcpp</span></span></tt> to import a C++ constructor, and to declare constructors that operate similarly to <tt class="docutils literal"><span class="pre"><span class="Identifier">virtual</span></span></tt>.</p>
- <p>Consider:</p>
- <p><pre class="listing"><span class="Keyword">type</span> <span class="Identifier">Foo</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int32</span>
- <span class="Keyword">proc</span> <span class="Identifier">makeFoo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int32</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Foo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">constructor</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">result</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">x</span></pre></p>
- <p>It forward declares the constructor in the type definition. When the constructor has parameters, it also generates a default constructor. One can avoid this behaviour by using <tt class="docutils literal"><span class="pre"><span class="Identifier">noDecl</span></span></tt> in a default constructor.</p>
- <p>Like <tt class="docutils literal"><span class="pre"><span class="Identifier">virtual</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">constructor</span></span></tt> also supports a syntax that allows to express C++ constraints.</p>
- <p>For example:</p>
- <p><pre class="listing"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">emit</span><span class="Punctuation">:</span><span class="LongStringLit">"""/*TYPESECTION*/
- struct CppClass {
- int x;
- int y;
- CppClass(int inX, int inY) {
- this->x = inX;
- this->y = inY;
- }
- //CppClass() = default;
- };
- """</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">CppClass</span><span class="Operator">*</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">,</span> <span class="Identifier">inheritable</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int32</span>
- <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">int32</span>
- <span class="Identifier">NimClass</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span> <span class="Keyword">of</span> <span class="Identifier">CppClass</span>
- <span class="Keyword">proc</span> <span class="Identifier">makeNimClass</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int32</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">NimClass</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">constructor</span><span class="Punctuation">:</span><span class="StringLit">"NimClass('1 #1) : CppClass(0, #1)"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">result</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Operator">=</span> <span class="Identifier">x</span>
- <span class="Comment"># Optional: define the default constructor explicitly</span>
- <span class="Keyword">proc</span> <span class="Identifier">makeCppClass</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">NimClass</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">constructor</span><span class="Punctuation">:</span> <span class="StringLit">"NimClass() : CppClass(0, 0)"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">result</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Operator">=</span> <span class="DecNumber">1</span></pre></p>
- <p>In the example above <tt class="docutils literal"><span class="pre"><span class="Identifier">CppClass</span></span></tt> has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropriate constructor.</p>
- <p>Notice when calling a constructor in the section of a global variable initialization, it will be called before <tt class="docutils literal"><span class="pre"><span class="Identifier">NimMain</span></span></tt> meaning Nim is not fully initialized.</p>
- <h1><a class="toc-backref" id="constructor-initializer" href="#constructor-initializer">Constructor Initializer</a></h1><p>By default Nim initializes <tt class="docutils literal"><span class="pre"><span class="Identifier">importcpp</span></span></tt> types with <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Punctuation">}</span></span></tt>. This can be problematic when importing types with a deleted default constructor. In order to avoid this, one can specify default values for a constructor by specifying default values for the proc params in the <tt class="docutils literal"><span class="pre"><span class="Identifier">constructor</span></span></tt> proc.</p>
- <p>For example:</p>
- <p><pre class="listing">
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">emit</span><span class="Punctuation">:</span> <span class="LongStringLit">"""/*TYPESECTION*/
- struct CppStruct {
- CppStruct(int x, char* y): x(x), y(y){}
- int x;
- char* y;
- };
- """</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">CppStruct</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">,</span> <span class="Identifier">inheritable</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Keyword">proc</span> <span class="Identifier">makeCppStruct</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">cint</span> <span class="Operator">=</span> <span class="DecNumber">5</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span><span class="Identifier">cstring</span> <span class="Operator">=</span> <span class="StringLit">"hello"</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">CppStruct</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">:</span> <span class="StringLit">"CppStruct(@)"</span><span class="Punctuation">,</span> <span class="Identifier">constructor</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Punctuation">(</span><span class="Keyword">proc</span> <span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">CppStruct</span><span class="Punctuation">)</span> <span class="Operator">=</span> <span class="Identifier">echo</span> <span class="StringLit">"hello"</span><span class="Punctuation">)</span><span class="Punctuation">(</span><span class="Identifier">makeCppStruct</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Comment"># If one removes a default value from the constructor and passes it to the call explicitly, the C++ compiler will complain.</span>
- </pre> Skip initializers in fields members</p>
- <hr />
- <p>By using <tt class="docutils literal"><span class="pre"><span class="Identifier">noInit</span></span></tt> in a type or field declaration, the compiler will skip the initializer. By doing so one can explicitly initialize those values in the constructor of the type owner.</p>
- <p>For example:</p>
- <p><pre class="listing">
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">emit</span><span class="Punctuation">:</span> <span class="LongStringLit">"""/*TYPESECTION*/
- struct Foo {
- Foo(int a){};
- };
- struct Boo {
- Boo(int a){};
- };
-
- """</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Foo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">Boo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">,</span> <span class="Identifier">noInit</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">Test</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">exportc</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">foo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">noInit</span><span class="Operator">.</span><span class="Punctuation">}</span><span class="Punctuation">:</span> <span class="Identifier">Foo</span>
- <span class="Identifier">boo</span><span class="Punctuation">:</span> <span class="Identifier">Boo</span>
- <span class="Keyword">proc</span> <span class="Identifier">makeTest</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Test</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">constructor</span><span class="Punctuation">:</span> <span class="StringLit">"Test() : foo(10), boo(1)"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Keyword">discard</span>
- <span class="Keyword">proc</span> <span class="Identifier">main</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">var</span> <span class="Identifier">t</span> <span class="Operator">=</span> <span class="Identifier">makeTest</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Identifier">main</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- </pre></p>
- <p>Will produce:</p>
- <p><pre class="listing">
- <span class="Keyword">struct</span> <span class="Identifier">Test</span> <span class="Punctuation">{</span>
- <span class="Identifier">Foo</span> <span class="Identifier">foo</span><span class="Punctuation">;</span>
- <span class="Identifier">Boo</span> <span class="Identifier">boo</span><span class="Punctuation">;</span>
- <span class="Identifier">N_LIB_PRIVATE</span> <span class="Identifier">N_NOCONV</span><span class="Punctuation">(</span><span class="Punctuation">,</span> <span class="Identifier">Test</span><span class="Punctuation">)</span><span class="Punctuation">(</span><span class="Keyword">void</span><span class="Punctuation">)</span><span class="Punctuation">;</span>
- <span class="Punctuation">}</span><span class="Punctuation">;</span>
- </pre></p>
- <p>Notice that without <tt class="docutils literal"><span class="pre"><span class="Identifier">noInit</span></span></tt> it would produce <tt class="docutils literal"><span class="pre"><span class="Identifier">Foo</span> <span class="Identifier">foo</span> <span class="Punctuation">{</span><span class="Punctuation">}</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">Boo</span> <span class="Identifier">boo</span> <span class="Punctuation">{</span><span class="Punctuation">}</span></span></tt></p>
- <h1><a class="toc-backref" id="member-pragma" href="#member-pragma">Member pragma</a></h1><p>Like the <tt class="docutils literal"><span class="pre"><span class="Identifier">constructor</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">virtual</span></span></tt> pragmas, the <tt class="docutils literal"><span class="pre"><span class="Identifier">member</span></span></tt> pragma can be used to attach a procedure to a C++ type. It's more flexible than the <tt class="docutils literal"><span class="pre"><span class="Identifier">virtual</span></span></tt> pragma in the sense that it accepts not only names but also operators and destructors.</p>
- <p>For example:</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">print</span><span class="Punctuation">(</span><span class="Identifier">s</span><span class="Punctuation">:</span> <span class="Identifier">cstring</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">:</span> <span class="StringLit">"printf(@)"</span><span class="Punctuation">,</span> <span class="Identifier">header</span><span class="Punctuation">:</span> <span class="StringLit">"<stdio.h>"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Doo</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">exportc</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">test</span><span class="Punctuation">:</span> <span class="Identifier">int</span>
- <span class="Keyword">proc</span> <span class="Identifier">memberProc</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">Doo</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">member</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="Operator">$</span><span class="Identifier">f</span><span class="Operator">.</span><span class="Identifier">test</span>
- <span class="Keyword">proc</span> <span class="Identifier">destructor</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">Doo</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">member</span><span class="Punctuation">:</span> <span class="StringLit">"~'1()"</span><span class="Punctuation">,</span> <span class="Identifier">used</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">print</span> <span class="StringLit">"destructing</span><span class="EscapeSequence">\n</span><span class="StringLit">"</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">==</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">self</span><span class="Punctuation">,</span> <span class="Identifier">other</span><span class="Punctuation">:</span> <span class="Identifier">Doo</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">member</span><span class="Punctuation">:</span> <span class="StringLit">"operator==('2 const & #2) const -> '0"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">self</span><span class="Operator">.</span><span class="Identifier">test</span> <span class="Operator">==</span> <span class="Identifier">other</span><span class="Operator">.</span><span class="Identifier">test</span>
- <span class="Keyword">let</span> <span class="Identifier">doo</span> <span class="Operator">=</span> <span class="Identifier">Doo</span><span class="Punctuation">(</span><span class="Identifier">test</span><span class="Punctuation">:</span> <span class="DecNumber">2</span><span class="Punctuation">)</span>
- <span class="Identifier">doo</span><span class="Operator">.</span><span class="Identifier">memberProc</span><span class="Punctuation">(</span><span class="Punctuation">)</span>
- <span class="Identifier">echo</span> <span class="Identifier">doo</span> <span class="Operator">==</span> <span class="Identifier">Doo</span><span class="Punctuation">(</span><span class="Identifier">test</span><span class="Punctuation">:</span> <span class="DecNumber">1</span><span class="Punctuation">)</span>
- </pre></p>
- <p>Will print:</p>
- <p><pre class="listing">2
- false
- destructing
- destructing</pre></p>
- <p>Notice how the C++ destructor is called automatically. Also notice the double implementation of <tt class="docutils literal"><span class="pre"><span class="Operator">==</span></span></tt> as an operator in Nim but also in C++. This is useful if you need the type to match some C++ <tt class="docutils literal"><span class="pre"><span class="Keyword">concept</span></span></tt> or <tt class="docutils literal"><span class="pre"><span class="Identifier">trait</span></span></tt> when interoping.</p>
- <p>A side effect of being able to declare C++ operators, is that you can now also create a C++ functor to have seamless interop with C++ lambdas (syntactic sugar for functors).</p>
- <p>For example:</p>
- <p><pre class="listing"><span class="Keyword">type</span>
- <span class="Identifier">NimFunctor</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Keyword">discard</span>
- <span class="Keyword">proc</span> <span class="Identifier">invoke</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">NimFunctor</span><span class="Punctuation">;</span> <span class="Identifier">n</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">member</span><span class="Punctuation">:</span> <span class="StringLit">"operator ()('2 #2)"</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"FunctorSupport!"</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"callOperator"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">`</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">NimFunctor</span><span class="Punctuation">;</span> <span class="Identifier">n</span><span class="Punctuation">:</span><span class="Identifier">int</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">importcpp</span><span class="Punctuation">:</span> <span class="StringLit">"#(@)"</span> <span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Identifier">NimFunctor</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">(</span><span class="DecNumber">1</span><span class="Punctuation">)</span></pre> Notice we use the overload of <tt class="docutils literal"><span class="pre"><span class="Punctuation">(</span><span class="Punctuation">)</span></span></tt> to have the same semantics in Nim, but on the <tt class="docutils literal"><span class="pre"><span class="Identifier">importcpp</span></span></tt> we import the functor as a function. This allows to easy interop with functions that accepts for example a <tt class="docutils literal"><span class="pre"><span class="Keyword">const</span></span></tt> operator in its signature.</p>
- <h1><a class="toc-backref" id="injected-symbols-in-generic-procs-and-templates" href="#injected-symbols-in-generic-procs-and-templates">Injected symbols in generic procs and templates</a></h1><p>With the experimental option <tt class="docutils literal"><span class="pre"><span class="Identifier">openSym</span></span></tt>, captured symbols in generic routine and template bodies may be replaced by symbols injected locally by templates/macros at instantiation time. <tt class="docutils literal"><span class="pre"><span class="Keyword">bind</span></span></tt> may be used to keep the captured symbols over the injected ones regardless of enabling the options, but other methods like renaming the captured symbols should be used instead so that the code is not affected by context changes.</p>
- <p>Since this change may affect runtime behavior, the experimental switch <tt class="docutils literal"><span class="pre"><span class="Identifier">openSym</span></span></tt> needs to be enabled; and a warning is given in the case where an injected symbol would replace a captured symbol not bound by <tt class="docutils literal"><span class="pre"><span class="Keyword">bind</span></span></tt> and the experimental switch isn't enabled.</p>
- <p><pre class="listing"><span class="Keyword">const</span> <span class="Identifier">value</span> <span class="Operator">=</span> <span class="StringLit">"captured"</span>
- <span class="Keyword">template</span> <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">body</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
- <span class="Keyword">let</span> <span class="Identifier">value</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inject</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="StringLit">"injected"</span>
- <span class="Identifier">body</span>
- <span class="Keyword">proc</span> <span class="Identifier">old</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Keyword">return</span> <span class="Identifier">value</span> <span class="Comment"># warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`</span>
- <span class="Identifier">echo</span> <span class="Identifier">old</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># "captured"</span>
- <span class="Keyword">template</span> <span class="Identifier">oldTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Identifier">value</span> <span class="Comment"># warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`</span>
- <span class="Identifier">echo</span> <span class="Identifier">oldTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># "captured"</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"openSym"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">bar</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Keyword">return</span> <span class="Identifier">value</span>
- <span class="Identifier">assert</span> <span class="Identifier">bar</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="StringLit">"injected"</span> <span class="Comment"># previously it would be "captured"</span>
- <span class="Keyword">proc</span> <span class="Identifier">baz</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Keyword">bind</span> <span class="Identifier">value</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Keyword">return</span> <span class="Identifier">value</span>
- <span class="Identifier">assert</span> <span class="Identifier">baz</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="StringLit">"captured"</span>
- <span class="Keyword">template</span> <span class="Identifier">barTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Identifier">value</span>
- <span class="Identifier">assert</span> <span class="Identifier">barTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="StringLit">"injected"</span> <span class="Comment"># previously it would be "captured"</span>
- <span class="Keyword">template</span> <span class="Identifier">bazTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Keyword">bind</span> <span class="Identifier">value</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Identifier">value</span>
- <span class="Identifier">assert</span> <span class="Identifier">bazTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="StringLit">"captured"</span></pre></p>
- <p>This option also generates a new node kind <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkOpenSym</span></span></tt> which contains exactly 1 <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkSym</span></span></tt> node. In the future this might be merged with a slightly modified <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkOpenSymChoice</span></span></tt> node but macros that want to support the experimental feature should still handle <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkOpenSym</span></span></tt>, as the node kind would simply not be generated as opposed to being removed.</p>
- <p>Another experimental switch <tt class="docutils literal"><span class="pre"><span class="Identifier">genericsOpenSym</span></span></tt> exists that enables this behavior at instantiation time, meaning templates etc can enable it specifically when they are being called. However this does not generate <tt class="docutils literal"><span class="pre"><span class="Identifier">nnkOpenSym</span></span></tt> nodes (unless the other switch is enabled) and so doesn't reflect the regular behavior of the switch.</p>
- <p><pre class="listing"><span class="Keyword">const</span> <span class="Identifier">value</span> <span class="Operator">=</span> <span class="StringLit">"captured"</span>
- <span class="Keyword">template</span> <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">,</span> <span class="Identifier">body</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
- <span class="Keyword">let</span> <span class="Identifier">value</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inject</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="StringLit">"injected"</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">push</span> <span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"genericsOpenSym"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Identifier">body</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">pop</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">proc</span> <span class="Identifier">bar</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Keyword">return</span> <span class="Identifier">value</span>
- <span class="Identifier">echo</span> <span class="Identifier">bar</span><span class="Punctuation">[</span><span class="Identifier">int</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Comment"># "injected"</span>
- <span class="Keyword">template</span> <span class="Identifier">barTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="Keyword">block</span><span class="Punctuation">:</span>
- <span class="Keyword">var</span> <span class="Identifier">res</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
- <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
- <span class="Identifier">res</span> <span class="Operator">=</span> <span class="Identifier">value</span>
- <span class="Identifier">res</span>
- <span class="Identifier">assert</span> <span class="Identifier">barTempl</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">==</span> <span class="StringLit">"injected"</span></pre></p>
- <h1><a class="toc-backref" id="vtable-for-methods" href="#vtable-for-methods">VTable for methods</a></h1><p>Methods now support implementations based on a VTable by using <tt class="docutils literal"><span class="pre"><span class="Operator">--</span><span class="Identifier">experimental</span><span class="Punctuation">:</span><span class="Identifier">vtables</span></span></tt>. Note that the option needs to enabled globally. The virtual method table is stored in the type info of an object, which is an array of function pointers.</p>
- <p><pre class="listing"><span class="Keyword">method</span> <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">Base</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">base</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">method</span> <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">Derived</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">base</span><span class="Operator">.</span><span class="Punctuation">}</span></pre></p>
- <p>It roughly generates a dispatcher like</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">foo_dispatch</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">Base</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">x</span><span class="Operator">.</span><span class="Identifier">typeinfo</span><span class="Operator">.</span><span class="Identifier">vtable</span><span class="Punctuation">[</span><span class="Identifier">method_index</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Operator">...</span><span class="Punctuation">)</span> <span class="Comment"># method_index is the index of the sorted order of a method</span></pre></p>
- <p>Methods are required to be in the same module where their type has been defined.</p>
- <p><pre class="listing"><span class="Comment"># types.nim</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Base</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">ref</span> <span class="Keyword">object</span></pre></p>
- <p><pre class="listing"><span class="Keyword">import</span> <span class="Identifier">types</span>
- <span class="Keyword">method</span> <span class="Identifier">foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">Base</span><span class="Punctuation">)</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">base</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Keyword">discard</span></pre></p>
- <p>It gives an error: method <tt class="docutils literal"><span class="pre"><span class="Identifier">foo</span></span></tt> can be defined only in the same module with its type (Base).</p>
- <h1><a class="toc-backref" id="asmsyntax-pragma" href="#asmsyntax-pragma">asmSyntax pragma</a></h1><p>The <tt class="docutils literal"><span class="pre"><span class="Identifier">asmSyntax</span></span></tt> pragma is used to specify target inline assembler syntax in an <tt class="docutils literal"><span class="pre"><span class="Keyword">asm</span></span></tt> statement.</p>
- <p>It prevents compiling code with different of the target CC inline asm syntax, i.e. it will not allow gcc inline asm code to be compiled with vcc.</p>
- <p><pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">nothing</span><span class="Punctuation">(</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Keyword">asm</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">asmSyntax</span><span class="Punctuation">:</span> <span class="StringLit">"gcc"</span><span class="Operator">.</span><span class="Punctuation">}</span><span class="LongStringLit">"""
- nop
- """</span></pre></p>
- <p>The current C(C++) backend implementation cannot generate code for gcc and for vcc at the same time. For example, <tt class="docutils literal"><span class="pre"><span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">asmSyntax</span><span class="Punctuation">:</span> <span class="StringLit">"vcc"</span><span class="Operator">.</span><span class="Punctuation">}</span></span></tt> with the ICC compiler will not generate code with intel asm syntax, even though ICC can use both gcc-like and vcc-like asm.</p>
- <h1><a class="toc-backref" id="typeminusbound-overloads" href="#typeminusbound-overloads">Type-bound overloads</a></h1><p>With the experimental option <tt class="docutils literal"><span class="pre"><span class="Operator">--</span><span class="Identifier">experimental</span><span class="Punctuation">:</span><span class="Identifier">typeBoundOps</span></span></tt>, each "root" nominal type (namely <tt class="docutils literal"><span class="pre"><span class="Keyword">object</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">enum</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Keyword">distinct</span></span></tt>, direct <tt class="docutils literal"><span class="pre"><span class="Identifier">Foo</span> <span class="Operator">=</span> <span class="Keyword">ref</span> <span class="Keyword">object</span></span></tt> types as well as their generic versions) can have operations attached to it. Exported top-level routines declared in the same scope as a nominal type with a parameter having a type directly deriving from that nominal type (i.e. with <tt class="docutils literal"><span class="pre"><span class="Keyword">var</span></span></tt>/<tt class="docutils literal"><span class="pre"><span class="Identifier">sink</span></span></tt>/<tt class="docutils literal"><span class="pre"><span class="Identifier">typedesc</span></span></tt> modifiers or being in a generic constraint) are considered "attached" to the respective nominal type. This applies to every parameter regardless of placement.</p>
- <p>When a call to a symbol is openly overloaded and overload matching starts, for all arguments in the call that have already undergone type checking, routines with the same name attached to the root nominal type (if it exists) of each given argument are added as a candidate to the overload match. This also happens as arguments gradually get typed after every match to an overload. This is so that the only overloads considered out of scope are attached to the types of the given arguments, and that matches to <tt class="docutils literal"><span class="pre"><span class="Identifier">untyped</span></span></tt> or missing parameters are not influenced by outside overloads.</p>
- <p>If no overloads with a given name are in scope, then overload matching will not begin, and so type-bound overloads are not considered for that name. Similarly, if the only overloads with a given name require a parameter to be <tt class="docutils literal"><span class="pre"><span class="Identifier">untyped</span></span></tt> or missing, then type-bound overloads will not be considered for the argument in that position. Generally this means that a "base" overload with a compliant signature should be in scope so that type-bound overloads can be used.</p>
- <p>In the case of ambiguity between distinct local/imported and type-bound symbols in overload matching, type-bound symbols are considered as a less specific scope than imports.</p>
- <p>An example with the <tt class="docutils literal"><span class="pre"><span class="Identifier">hash</span></span></tt> interface in the standard library is as follows:</p>
- <p><pre class="listing"><span class="Comment"># objs.nim</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">hashes</span>
- <span class="Keyword">type</span>
- <span class="Identifier">Obj</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">x</span><span class="Operator">*</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Operator">*:</span> <span class="Identifier">int</span>
- <span class="Identifier">z</span><span class="Operator">*:</span> <span class="Identifier">string</span> <span class="Comment"># to be ignored for equality</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">==</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">,</span> <span class="Identifier">b</span><span class="Punctuation">:</span> <span class="Identifier">Obj</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span> <span class="Operator">=</span>
- <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Operator">==</span> <span class="Identifier">b</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Keyword">and</span> <span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">y</span> <span class="Operator">==</span> <span class="Identifier">b</span><span class="Operator">.</span><span class="Identifier">y</span>
- <span class="Keyword">proc</span> <span class="Identifier">hash</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Punctuation">:</span> <span class="Identifier">Obj</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Hash</span> <span class="Operator">=</span>
- <span class="Operator">$!</span><span class="Punctuation">(</span><span class="Identifier">hash</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">x</span><span class="Punctuation">)</span> <span class="Operator">&!</span> <span class="Identifier">hash</span><span class="Punctuation">(</span><span class="Identifier">a</span><span class="Operator">.</span><span class="Identifier">y</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
- <span class="Comment"># here both `==` and `hash` are attached to Obj</span>
- <span class="Comment"># 1. they are both exported</span>
- <span class="Comment"># 2. they are in the same scope as Obj</span>
- <span class="Comment"># 3. they have parameters with types directly deriving from Obj</span>
- <span class="Comment"># 4. Obj is nominal</span></pre></p>
- <p><pre class="listing"><span class="Comment"># main.nim</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"typeBoundOps"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">from</span> <span class="Identifier">objs</span> <span class="Keyword">import</span> <span class="Identifier">Obj</span> <span class="Comment"># objs.hash, objs.`==` not imported</span>
- <span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">tables</span>
- <span class="Comment"># tables use `hash`, only using the overloads in `std/hashes` and</span>
- <span class="Comment"># the ones in instantiation scope (in this case, there are none)</span>
- <span class="Keyword">var</span> <span class="Identifier">t</span><span class="Punctuation">:</span> <span class="Identifier">Table</span><span class="Punctuation">[</span><span class="Identifier">Obj</span><span class="Punctuation">,</span> <span class="Identifier">int</span><span class="Punctuation">]</span>
- <span class="Comment"># because tables use `hash` and `==` in a compliant way,</span>
- <span class="Comment"># the overloads bound to Obj are also considered, and in this case match best</span>
- <span class="Identifier">t</span><span class="Punctuation">[</span><span class="Identifier">Obj</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="DecNumber">3</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="Identifier">z</span><span class="Punctuation">:</span> <span class="StringLit">"debug"</span><span class="Punctuation">)</span><span class="Punctuation">]</span> <span class="Operator">=</span> <span class="DecNumber">34</span>
- <span class="Comment"># if `hash` for all objects as in `std/hashes` was used, this would error:</span>
- <span class="Identifier">echo</span> <span class="Identifier">t</span><span class="Punctuation">[</span><span class="Identifier">Obj</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="DecNumber">3</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="DecNumber">4</span><span class="Punctuation">,</span> <span class="Identifier">z</span><span class="Punctuation">:</span> <span class="StringLit">"ignored"</span><span class="Punctuation">)</span><span class="Punctuation">]</span> <span class="Comment"># 34</span></pre></p>
- <p>Another example, this time with <tt class="docutils literal"><span class="pre"><span class="Operator">$</span></span></tt> and indirect imports:</p>
- <p><pre class="listing"><span class="Comment"># foo.nim</span>
- <span class="Keyword">type</span> <span class="Identifier">Foo</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
- <span class="Identifier">x</span><span class="Operator">*</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Operator">*:</span> <span class="Identifier">int</span>
- <span class="Keyword">proc</span> <span class="Punctuation">`</span><span class="Operator">$</span><span class="Punctuation">`</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">Foo</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">string</span> <span class="Operator">=</span>
- <span class="StringLit">"Foo("</span> <span class="Operator">&</span> <span class="Operator">$</span><span class="Identifier">f</span><span class="Operator">.</span><span class="Identifier">x</span> <span class="Operator">&</span> <span class="StringLit">", "</span> <span class="Operator">&</span> <span class="Operator">$</span><span class="Identifier">f</span><span class="Operator">.</span><span class="Identifier">y</span> <span class="Operator">&</span> <span class="StringLit">")"</span></pre></p>
- <p><pre class="listing"><span class="Comment"># bar.nim</span>
- <span class="Keyword">import</span> <span class="Identifier">foo</span>
- <span class="Keyword">proc</span> <span class="Identifier">makeFoo</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">Foo</span> <span class="Operator">=</span>
- <span class="Identifier">Foo</span><span class="Punctuation">(</span><span class="Identifier">x</span><span class="Punctuation">:</span> <span class="Identifier">x</span><span class="Punctuation">,</span> <span class="Identifier">y</span><span class="Punctuation">:</span> <span class="Identifier">y</span><span class="Punctuation">)</span>
- <span class="Keyword">proc</span> <span class="Identifier">useFoo</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">:</span> <span class="Identifier">Foo</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"used: "</span><span class="Punctuation">,</span> <span class="Identifier">f</span> <span class="Comment"># directly calls `foo.$` from scope</span></pre></p>
- <p><pre class="listing"><span class="Comment"># debugger.nim</span>
- <span class="Keyword">proc</span> <span class="Identifier">debug</span><span class="Operator">*</span><span class="Punctuation">[</span><span class="Identifier">T</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Identifier">obj</span><span class="Punctuation">:</span> <span class="Identifier">T</span><span class="Punctuation">)</span> <span class="Operator">=</span>
- <span class="Identifier">echo</span> <span class="StringLit">"debugging: "</span><span class="Punctuation">,</span> <span class="Identifier">obj</span> <span class="Comment"># calls generic `$`</span></pre></p>
- <p><pre class="listing"><span class="Comment"># main.nim</span>
- <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">experimental</span><span class="Punctuation">:</span> <span class="StringLit">"typeBoundOps"</span><span class="Operator">.</span><span class="Punctuation">}</span>
- <span class="Keyword">import</span> <span class="Identifier">bar</span><span class="Punctuation">,</span> <span class="Identifier">debugger</span> <span class="Comment"># `foo` not imported, so `foo.$` not in scope</span>
- <span class="Keyword">let</span> <span class="Identifier">f</span> <span class="Operator">=</span> <span class="Identifier">makeFoo</span><span class="Punctuation">(</span><span class="DecNumber">123</span><span class="Punctuation">,</span> <span class="DecNumber">456</span><span class="Punctuation">)</span>
- <span class="Identifier">useFoo</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">)</span> <span class="Comment"># used: Foo(123, 456)</span>
- <span class="Identifier">debug</span><span class="Punctuation">(</span><span class="Identifier">f</span><span class="Punctuation">)</span> <span class="Comment"># debugging: Foo(123, 456)</span></pre> </p>
- </p>
-
- </div>
- </div>
- <div class="twelve-columns footer">
- <span class="nim-sprite"></span>
- <br>
- <small style="color: var(--hint);">Made with Nim. Generated: 2024-12-25 13:27:33 UTC</small>
- </div>
- </div>
- </div>
- <script defer data-domain="nim-lang.org" src="https://plausible.io/js/plausible.js"></script>
-
- </body>
- </html>
|