PageSourceSearch

https://noir-lang.org/docs/assets/js/5f21543a.2228eb4b.js

js noir-lang.org collected 2026-10-03 22:52:41 UTC 8,659 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[2306],{61105(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>c,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"language/data_types/coercions","title":"Type Casting and Coercions","description":"Noir\'s explicit type casts and implicit type coercions","source":"@site/versioned_docs/version-v1.0.0-rc.2/language/data_types/coercions.md","sourceDirName":"language/data_types","slug":"/language/data_types/coercions","permalink":"/docs/language/data_types/coercions","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/versioned_docs/version-v1.0.0-rc.2/language/data_types/coercions.md","tags":[],"version":"v1.0.0-rc.2","frontMatter":{"title":"Type Casting and Coercions","description":"Noir\'s explicit type casts and implicit type coercions","keywords":["noir","types","coercions","casts","as"]},"sidebar":"sidebar","previous":{"title":"Function types","permalink":"/docs/language/data_types/function_types"},"next":{"title":"Functions","permalink":"/docs/language/functions"}}');var s=t(74848),r=t(28453);const c={title:"Type Casting and Coercions",description:"Noir's explicit type casts and implicit type coercions",keywords:["noir","types","coercions","casts","as"]},o=void 0,d={},l=[{value:"Type Casting",id:"type-casting",level:2},{value:"Valid casts",id:"valid-casts",level:3},{value:"Restrictions",id:"restrictions",level:3},{value:"Example",id:"example",level:3},{value:"Performance note",id:"performance-note",level:3},{value:"Type Coercions",id:"type-coercions",level:2}];function a(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h2,{id:"type-casting",children:"Type Casting"}),"\n",(0,s.jsxs)(n.p,{children:["You can explicitly convert between numeric types using the ",(0,s.jsx)(n.code,{children:"as"})," keyword:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:"let x: u32 = 100;\nlet y: u8 = x as u8;       // Cast u32 to u8 (truncates if value exceeds u8 range)\nlet z: Field = x as Field;  // Cast u32 to Field\n"})}),"\n",(0,s.jsx)(n.h3,{id:"valid-casts",children:"Valid casts"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"as"})," keyword can be used to cast between the following types:"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"From"}),(0,s.jsx)(n.th,{children:"To"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Any integer"}),(0,s.jsx)(n.td,{children:"Any other integer"}),(0,s.jsx)(n.td,{children:"Truncates to fit the target bit size"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Any unsigned integer"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Field"})}),(0,s.jsx)(n.td,{children:"Always safe, no truncation"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Field"})}),(0,s.jsx)(n.td,{children:"Any integer"}),(0,s.jsx)(n.td,{children:"Truncates to fit the target bit size"})]})]})]}),"\n",(0,s.jsx)(n.h3,{id:"restrictions",children:"Restrictions"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsxs)(n.strong,{children:["Signed integers cannot be cast to ",(0,s.jsx)(n.code,{children:"Field"})]})," -- this will produce a compiler error. Convert to an unsigned integer first if needed."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Non-numeric types"})," (arrays, strings, structs, tuples, etc.) cannot be cast to or from numeric types."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsxs)(n.strong,{children:["Casting to ",(0,s.jsx)(n.code,{children:"bool"})]})," is not supported. Compare with zero instead: ",(0,s.jsx)(n.code,{children:"value != 0"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"example",children:"Example"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:"fn main() {\n    let big: u32 = 300;\n    let small = big as u8;    // Truncates: 300 does not fit in u8\n    \n    let field_val: Field = 42;\n    let as_u64 = field_val as u64;\n    \n    let unsigned: u32 = 5;\n    let as_field = unsigned as Field;  // Ok: unsigned to Field\n    \n    // let signed: i32 = -1;\n    // let bad = signed as Field;  // Error: cannot cast signed integer to Field\n}\n"})}),"\n",(0,s.jsx)(n.h3,{id:"performance-note",children:"Performance note"}),"\n",(0,s.jsxs)(n.p,{children:["Integer casts generate range check constraints in the compiled circuit. Using ",(0,s.jsx)(n.code,{children:"Field"})," values directly where possible can avoid these extra constraints."]}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/docs/language/data_types/fields#security-considerations-for-field-arithmetic",children:"Security Considerations for Field Arithmetic"})," to determine if the tradeoffs are worth the cheaper casting & arithmetic costs of using field arithmetic directly."]}),"\n",(0,s.jsx)(n.h2,{id:"type-coercions",children:"Type Coercions"}),"\n",(0,s.jsx)(n.p,{children:"When one type is required in Noir code but a different type is given, the compiler will typically issue\na type error. There are a few cases however where the compiler will instead automatically perform a\ntype coercion. These are typically limited to a few type pairs where converting from one to the other\nwill not sacrifice performance or correctness. Currently, Noir will will try to perform the following\ntype coercions:"}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Actual Type"}),(0,s.jsx)(n.th,{children:"Expected Type"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"[T; N]"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"[T]"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"fn(..) -> R"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"unconstrained fn(..) -> R"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"str<N>"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CtString"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"fmtstr<N, T>"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CtString"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"&mut T"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"&T"})})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"Note that:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Conversions are only from the actual type to the expected type, never the other way around."}),"\n",(0,s.jsx)(n.li,{children:"Conversions are only performed on the outermost type, they're never performed within a nested type."}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"CtString"})," is a compile-time only type, so this conversion is only valid in ",(0,s.jsx)(n.a,{href:"/docs/language/comptime",children:"comptime code"}),"."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Examples:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'fn requires_vector(_vector: [Field]) {}\ncomptime fn requires_ct_string(_s: CtString) {}\n\nfn main() {\n    let array: [Field; 4] = [1, 2, 3, 4];\n\n    // Ok - array is converted to a vector\n    requires_vector(array);\n    // equivalent to:\n    requires_vector(array.as_vector());\n\n    // coerce a constrained function to an unconstrained one:\n    let f: unconstrained fn([Field]) = requires_vector;\n\n    comptime {\n        // Passing a str<6> where a CtString is expected\n        requires_ct_string("hello!")\n    }\n}\n'})})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},28453(e,n,t){t.d(n,{R:()=>c,x:()=>o});var i=t(96540);const s={},r=i.createContext(s);function c(e){const n=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.