Skip to content

start_fn ​

Applies to: structs functions methods

Overrides name, visibility and docs for the starting function.

TIP

Don't confuse this with the member-level #[builder(start_fn)] attribute.

When this attribute is used with fn syntax, it additionally exposes the original function under the macro.

Short syntax configures just the name.

attr
#[builder(start_fn = custom_name)]

Long syntax provides more flexibility. All keys are optional.

attr
#[builder(
    start_fn(
        name = custom_name,
        vis = "pub(crate)",
        doc {
            /// Custom docs
        }
    )
)]

name ​

The default name for the starting function is chosen according to the following rules:

SyntaxDefault
struct Tbuilder
Associated fn T::new()builder
Associated fn T::fn_name(){fn_name}
Free fn fn_name(){fn_name}

vis ​

The visibility must be enclosed with quotes. Use "" or "pub(self)" for private visibility.

The default visibility is the same as the visibility of the builder_type, which in turn, defaults to the visibility of the underlying struct or fn.

doc ​

Simple documentation is generated by default. The syntax of this attribute expects a block with doc comments.

attr
doc {
    /// Doc comments
}

Examples ​

rust
use bon::Builder;

#[derive(Builder)]
#[builder(start_fn = init)] 
struct User {
    id: u32
}

User::init() 
    .id(42)
    .build();
rust
use bon::Builder;

// `User::init()` method will have `pub(crate)` visibility
// Use `vis = ""` to make it fully private instead
#[derive(Builder)]
#[builder(start_fn(name = init, vis = "pub(crate)"))]      
pub struct User {
    id: u32
}

User::init() 
    .id(42)
    .build();

See examples with fn syntax in the section below.

Exposing original function ​

By default, when you place #[builder] on a function, that original function is modified by the macro to make it hidden, so that only builder syntax remains available. Specifically, the macro does the following by default:

  • Prepends the prefix __orig_ to the original function's name.
  • Changes the visibility of the original function to private.
  • Adds #[doc(hidden)] to the function.

If you specify the start_fn attribute on a function, the macro skips hiding the original function. It means the starting function no longer replaces the original function. This way both the original positional function and the starting function with the builder syntax are exposed.

This can be used to preserve backwards compatibility for code that uses the original function directly.

NOTE

The name parameter is required when start_fn is used with fn syntax.

Example:

rust
use bon::builder;

#[builder(start_fn = example_builder)] 
fn example(x: u32, y: u32) {}

// The original positional function is still available
example(1, 2);

// The builder syntax is also available under the given name
example_builder()
    .x(1)
    .y(2)
    .call();
rust
use bon::bon;

struct Example;

#[bon]
impl Example {
    #[builder(start_fn = builder)]
    fn new(x: u32, y: u32) -> Self {
        Example
    }

    #[builder(start_fn = method_builder)]
    fn method(&self, x: u32, y: u32) {}
}

// The original method `new` is still available
Example::new(1, 2);

// The builder syntax is also available under the given name
let example = Example::builder()
    .x(1)
    .y(2)
    .build();

// The original `method` is still available
example.method(1, 2);

// The builder syntax for the `method` is also available under the given name
example.method_builder()
    .x(1)
    .y(2)
    .call();

One interesting quirk is that by default the associated method named new already generates a starting function under the name builder. However, by default, the original method new also becomes hidden. By specifying the #[builder(start_fn = builder)] explicitly the original method new remains exposed.


Given that #[builder(start_fn)] on a function behaves additively, you can provide builder syntax as an opt-in cargo feature of your crate.

Example:

rust
#[cfg_attr(feature = "bon", bon::builder(start_fn = function_builder))]
fn function() {}

If you use this syntax, the function() always remains available with or without the bon feature enabled.