Skip to content

Commit 7d70d1f

Browse files
authored
add default args example (#68)
1 parent 9c4825c commit 7d70d1f

File tree

4 files changed

+126
-1
lines changed

4 files changed

+126
-1
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ Cargo.lock
1313
*.pdb
1414
# r specific
1515
.Rproj.user/
16-
*.Rproj
16+
*.Rproj
17+
**/*.quarto_ipynb
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"hash": "0e65dcf08a918c5401ff7a49e3a425dc",
3+
"result": {
4+
"engine": "knitr",
5+
"markdown": "---\ntitle: Default function arguments\ndate: \"2025-10-25\"\nfreeze: true\n---\n\n\n\nIn Rust, all function arguments are required—there are no default arguments. However, for R packages, having default arguments is essential for creating ergonomic and user-friendly APIs. The `#[extendr]` macro provides the `default` parameter allowing you to specify default values that will be added to the generated R wrapper functions.\n\n## The `default` attribute\n\nThe `default` attribute is applied to individual function arguments using the syntax `#[extendr(default = \"value\")]`. The value you provide is a string that will be inserted directly into the generated R function signature. This means you can use any valid R expression as a default value.\n\n```rust\n#[extendr]\nfn my_function(#[extendr(default = \"NULL\")] x: Robj) {\n // function body\n}\n```\n\nThis generates an R function with the signature `my_function(x = NULL)`.\n\n## Basic examples\n\nLet's start with a simple function that checks if an argument is `NULL`. By setting the default to `\"NULL\"`, users can call the function without providing any arguments:\n\n\n::: {.cell}\n\n```{.rust .cell-code}\n#[extendr]\nfn check_default(#[extendr(default = \"NULL\")] x: Robj) -> bool {\n x.is_null()\n}\n```\n:::\n\n\nNow you can call this function without any arguments, and it will use the default value:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncheck_default()\n#> [1] TRUE\n```\n:::\n\n\nOr provide an explicit value:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncheck_default(42)\n#> [1] FALSE\n```\n:::\n\n\n## Working with logical defaults\n\nDefault arguments work with any R type. Here's an example with a logical default value:\n\n\n::: {.cell}\n\n```{.rust .cell-code}\n#[extendr]\nfn greet(name: &str, #[extendr(default = \"FALSE\")] loud: bool) -> String {\n let greeting = format!(\"Hello, {}\", name);\n if loud {\n greeting.to_uppercase()\n } else {\n greeting\n }\n}\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Using the default (quiet greeting)\ngreet(\"Alice\")\n#> [1] \"Hello, Alice\"\n\n# Override the default\ngreet(\"Alice\", loud = TRUE)\n#> [1] \"HELLO, ALICE\"\n```\n:::\n\n\n## Multiple defaults\n\nYou can use multiple default arguments in a single function. Just remember that in R, arguments with defaults should typically come after required arguments for best practices:\n\n\n::: {.cell}\n\n```{.rust .cell-code}\n#[extendr]\nfn multiply(\n x: f64,\n #[extendr(default = \"1.0\")] multiplier: f64,\n #[extendr(default = \"FALSE\")] round_result: bool\n) -> f64 {\n let result = x * multiplier;\n if round_result {\n result.round()\n } else {\n result\n }\n}\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# All defaults\nmultiply(5.5)\n#> [1] 5.5\n\n# Custom multiplier\nmultiply(5.5, multiplier = 2.5)\n#> [1] 13.75\n\n# Custom multiplier and rounding\nmultiply(5.5, multiplier = 2.5, round_result = TRUE)\n#> [1] 14\n```\n:::\n\n\n## Important notes\n\n- The value in `default = \"...\"` is inserted directly into the R function signature, so it must be valid R code\n- You can use any R expression, including function calls: `#[extendr(default = \"getOption('my_option')\")]`\n- The default values only affect the R wrapper—your Rust function still receives whatever value the R user provides (or the default if they don't)\n",
6+
"supporting": [],
7+
"filters": [
8+
"rmarkdown/pagebreak.lua"
9+
],
10+
"includes": {},
11+
"engineDependencies": {},
12+
"preserve": {},
13+
"postProcess": true
14+
}
15+
}

_quarto.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ website:
7575
- section: "Error Handling"
7676
contents:
7777
- user-guide/error-handling/basic-error-handling.qmd
78+
- user-guide/default-args.qmd
7879
- user-guide/serde-integration.qmd
7980
- user-guide/tokio.qmd
8081
- user-guide/cran-publishing.qmd

user-guide/default-args.qmd

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
title: Default function arguments
3+
date: "`r Sys.Date()`"
4+
freeze: true
5+
---
6+
7+
```{r, include = FALSE}
8+
library(rextendr)
9+
```
10+
11+
In Rust, all function arguments are required—there are no default arguments. However, for R packages, having default arguments is essential for creating ergonomic and user-friendly APIs. The `#[extendr]` macro provides the `default` parameter allowing you to specify default values that will be added to the generated R wrapper functions.
12+
13+
## The `default` attribute
14+
15+
The `default` attribute is applied to individual function arguments using the syntax `#[extendr(default = "value")]`. The value you provide is a string that will be inserted directly into the generated R function signature. This means you can use any valid R expression as a default value.
16+
17+
```rust
18+
#[extendr]
19+
fn my_function(#[extendr(default = "NULL")] x: Robj) {
20+
// function body
21+
}
22+
```
23+
24+
This generates an R function with the signature `my_function(x = NULL)`.
25+
26+
## Basic examples
27+
28+
Let's start with a simple function that checks if an argument is `NULL`. By setting the default to `"NULL"`, users can call the function without providing any arguments:
29+
30+
```{extendrsrc engine.opts = list(use_dev_extendr=TRUE)}
31+
#[extendr]
32+
fn check_default(#[extendr(default = "NULL")] x: Robj) -> bool {
33+
x.is_null()
34+
}
35+
```
36+
37+
Now you can call this function without any arguments, and it will use the default value:
38+
39+
```{r}
40+
check_default()
41+
```
42+
43+
Or provide an explicit value:
44+
45+
```{r}
46+
check_default(42)
47+
```
48+
49+
## Working with logical defaults
50+
51+
Default arguments work with any R type. Here's an example with a logical default value:
52+
53+
```{extendrsrc engine.opts = list(use_dev_extendr=TRUE)}
54+
#[extendr]
55+
fn greet(name: &str, #[extendr(default = "FALSE")] loud: bool) -> String {
56+
let greeting = format!("Hello, {}", name);
57+
if loud {
58+
greeting.to_uppercase()
59+
} else {
60+
greeting
61+
}
62+
}
63+
```
64+
65+
```{r}
66+
# Using the default (quiet greeting)
67+
greet("Alice")
68+
69+
# Override the default
70+
greet("Alice", loud = TRUE)
71+
```
72+
73+
## Multiple defaults
74+
75+
You can use multiple default arguments in a single function. Just remember that in R, arguments with defaults should typically come after required arguments for best practices:
76+
77+
```{extendrsrc engine.opts = list(use_dev_extendr=TRUE)}
78+
#[extendr]
79+
fn multiply(
80+
x: f64,
81+
#[extendr(default = "1.0")] multiplier: f64,
82+
#[extendr(default = "FALSE")] round_result: bool
83+
) -> f64 {
84+
let result = x * multiplier;
85+
if round_result {
86+
result.round()
87+
} else {
88+
result
89+
}
90+
}
91+
```
92+
93+
```{r}
94+
# All defaults
95+
multiply(5.5)
96+
97+
# Custom multiplier
98+
multiply(5.5, multiplier = 2.5)
99+
100+
# Custom multiplier and rounding
101+
multiply(5.5, multiplier = 2.5, round_result = TRUE)
102+
```
103+
104+
## Important notes
105+
106+
- The value in `default = "..."` is inserted directly into the R function signature, so it must be valid R code
107+
- You can use any R expression, including function calls: `#[extendr(default = "getOption('my_option')")]`
108+
- The default values only affect the R wrapper—your Rust function still receives whatever value the R user provides (or the default if they don't)

0 commit comments

Comments
 (0)