PageSourceSearch

https://noir-lang.org/docs/assets/js/69e988ce.bcef8dcc.js

js noir-lang.org collected 2026-10-03 22:54:12 UTC 11,632 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[3430],{14158(e,n,s){s.r(n),s.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"language/functions","title":"Functions","description":"Learn how to declare functions and methods in Noir, a programming language with Rust semantics. This guide covers parameter declaration, return types, call expressions, and more.","source":"@site/versioned_docs/version-v1.0.0-beta.26/language/functions.md","sourceDirName":"language","slug":"/language/functions","permalink":"/docs/v1.0.0-beta.26/language/functions","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/versioned_docs/version-v1.0.0-beta.26/language/functions.md","tags":[],"version":"v1.0.0-beta.26","frontMatter":{"title":"Functions","description":"Learn how to declare functions and methods in Noir, a programming language with Rust semantics. This guide covers parameter declaration, return types, call expressions, and more.","keywords":["Noir","Rust","functions","methods","parameter declaration","return types","call expressions"]},"sidebar":"sidebar","previous":{"title":"Type Casting and Coercions","permalink":"/docs/v1.0.0-beta.26/language/data_types/coercions"},"next":{"title":"Control Flow","permalink":"/docs/v1.0.0-beta.26/language/control_flow"}}');var t=s(74848),a=s(28453);const o={title:"Functions",description:"Learn how to declare functions and methods in Noir, a programming language with Rust semantics. This guide covers parameter declaration, return types, call expressions, and more.",keywords:["Noir","Rust","functions","methods","parameter declaration","return types","call expressions"]},r=void 0,l={},c=[{value:"Main function",id:"main-function",level:2},{value:"Call Expressions",id:"call-expressions",level:2},{value:"Methods",id:"methods",level:2},{value:"Lambdas",id:"lambdas",level:2},{value:"Attributes",id:"attributes",level:2}];function d(e){const n={a:"a",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.p,{children:"Functions in Noir follow the same semantics of Rust, though Noir does not support early returns."}),"\n",(0,t.jsxs)(n.p,{children:["To declare a function the ",(0,t.jsx)(n.code,{children:"fn"})," keyword is used."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn foo() {}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["By default, functions are visible only within the package they are defined. To make them visible outside of that package (for example, as part of a ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-beta.26/project_structure/crates_and_packages#libraries",children:"library"}),"), you should mark them as ",(0,t.jsx)(n.code,{children:"pub"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"pub fn foo() {}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["You can also restrict the visibility of the function to only the crate it was defined in, by specifying ",(0,t.jsx)(n.code,{children:"pub(crate)"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"pub(crate) fn foo() {}  //foo can only be called within its crate\n"})}),"\n",(0,t.jsx)(n.p,{children:"All parameters in a function must have a type and all types are known at compile time. The parameter\nis prepended with a colon and the parameter type. Multiple parameters are separated using a comma."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn foo(x : Field, y : Field){}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["You can use an underscore ",(0,t.jsx)(n.code,{children:"_"})," as a parameter name when you don't need to use the parameter in the function body. This is useful when you need to satisfy a function signature but don't need to use all the parameters:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn foo(_ : Field, y : Field) {\n    // Only using y parameter\n}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Alternatively, you can prefix a parameter name with an underscore (e.g. ",(0,t.jsx)(n.code,{children:"_x"}),"), which also indicates that the parameter is unused. This approach is often preferred as it preserves the parameter name for documentation purposes:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn foo(_x : Field, y : Field) -> Field {\n    // Only using y parameter\n    y\n}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["The return type of a function can be stated by using the ",(0,t.jsx)(n.code,{children:"->"})," arrow notation. The function below\nstates that the foo function must return a ",(0,t.jsx)(n.code,{children:"Field"}),". If the function returns no value, then the arrow\nis omitted."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn foo(x : Field, y : Field) -> Field {\n    x + y\n}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Note that a ",(0,t.jsx)(n.code,{children:"return"})," keyword is unneeded in this case - the last expression in a function's body is\nreturned."]}),"\n",(0,t.jsx)(n.h2,{id:"main-function",children:"Main function"}),"\n",(0,t.jsxs)(n.p,{children:["If you're writing a binary, the ",(0,t.jsx)(n.code,{children:"main"})," function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time:"]}),"\n",(0,t.jsx)(n.p,{children:"Valid signatures (fixed-size types):"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"fn main(x: Field)"})," - a single ",(0,t.jsx)(n.code,{children:"Field"}),"."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"fn main(x: [Field; 2])"})," - a fixed-size array whose length is known at compile time."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"fn main(x: (Field, bool))"})," - a tuple of two fixed-size elements."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"fn main(x: str<5>)"})," - a string whose length is known at compile time."]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Invalid signatures (variable-size types):"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"fn main(x: [Field])"})," - can't compile, has variable size."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Keep in mind ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-beta.26/tooling/tests",children:"tests"})," don't differentiate between ",(0,t.jsx)(n.code,{children:"main"})," and any other function. The following snippet passes tests, but won't compile or prove:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn main(x : [Field]) {\n    assert(x[0] == 1);\n}\n\n#[test]\nfn test_one() {\n    main(@[1, 2]);\n}\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"$ nargo test\n[testing] Running 1 test functions\n[testing] Testing test_one... ok\n[testing] All tests passed\n\n$ nargo check\nThe application panicked (crashed).\nMessage:  Cannot have variable sized arrays as a parameter to main\n"})}),"\n",(0,t.jsx)(n.h2,{id:"call-expressions",children:"Call Expressions"}),"\n",(0,t.jsx)(n.p,{children:"Calling a function in Noir is executed by using the function name and passing in the necessary\narguments."}),"\n",(0,t.jsxs)(n.p,{children:["Below we show how to call the ",(0,t.jsx)(n.code,{children:"foo"})," function from the ",(0,t.jsx)(n.code,{children:"main"})," function using a call expression:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"fn main(x : Field, y : Field) {\
1n    let z = foo(x);\n}\n\nfn foo(x : Field) -> Field {\n    x + x\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"methods",children:"Methods"}),"\n",(0,t.jsx)(n.p,{children:"You can define methods in Noir on any struct type in scope."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"struct MyStruct {\n    foo: Field,\n    bar: Field,\n}\n\nimpl MyStruct {\n    fn new(foo: Field) -> MyStruct {\n        MyStruct {\n            foo,\n            bar: 2,\n        }\n    }\n\n    fn sum(self) -> Field {\n        self.foo + self.bar\n    }\n}\n\nfn main() {\n    let s = MyStruct::new(40);\n    assert(s.sum() == 42);\n}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Methods are just syntactic sugar for functions, so if we wanted to we could also call ",(0,t.jsx)(n.code,{children:"sum"})," as\nfollows:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"assert(MyStruct::sum(s) == 42);\n"})}),"\n",(0,t.jsxs)(n.p,{children:["It is also possible to specialize which method is chosen depending on the ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-beta.26/language/generics",children:"generic"})," type that is used. In this example, the ",(0,t.jsx)(n.code,{children:"foo"})," function returns different values depending on its type:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"struct Foo<T> {}\n\nimpl Foo<u32> {\n    fn foo(self) -> Field { 1 }\n}\n\nimpl Foo<u64> {\n    fn foo(self) -> Field { 2 }\n}\n\nfn main() {\n    let f1: Foo<u32> = Foo{};\n    let f2: Foo<u64> = Foo{};\n    assert(f1.foo() + f2.foo() == 3);\n}\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Also note that impls with the same method name defined in them cannot overlap. For example, if we already have ",(0,t.jsx)(n.code,{children:"foo"})," defined for ",(0,t.jsx)(n.code,{children:"Foo<u32>"})," and ",(0,t.jsx)(n.code,{children:"Foo<u64>"})," like we do above, we cannot also define ",(0,t.jsx)(n.code,{children:"foo"})," in an ",(0,t.jsx)(n.code,{children:"impl<T> Foo<T>"})," since it would be ambiguous which version of ",(0,t.jsx)(n.code,{children:"foo"})," to choose."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"// Including this impl in the same project as the above snippet would\n// cause an overlapping impls error\nimpl<T> Foo<T> {\n    fn foo(self) -> Field { 3 }\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"lambdas",children:"Lambdas"}),"\n",(0,t.jsxs)(n.p,{children:["Lambdas are anonymous functions. They follow the syntax of Rust - ",(0,t.jsx)(n.code,{children:"|arg1, arg2, ..., argN| return_expression"}),"."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:"let add_50 = |val| val + 50;\nassert(add_50(100) == 150);\n"})}),"\n",(0,t.jsxs)(n.p,{children:["See ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-beta.26/language/lambdas",children:"Lambdas"})," for more details."]}),"\n",(0,t.jsx)(n.h2,{id:"attributes",children:"Attributes"}),"\n",(0,t.jsxs)(n.p,{children:["Attributes are metadata that can be applied to a function, using the following syntax: ",(0,t.jsx)(n.code,{children:"#[attribute(value)]"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["See ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-beta.26/language/attributes",children:"Attributes"})," for more details."]})]})}function u(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},28453(e,n,s){s.d(n,{R:()=>o,x:()=>r});var i=s(96540);const t={},a=i.createContext(t);function o(e){const n=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(a.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.