# Implicit Parameters

**URL:** <https://internals.rust-lang.org/t/implicit-parameters/14514>\
**Category:** language design\
**Created:** [April 17, 2021, 11:27pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514 "2021-04-17T23:27:13Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![2e71828](https://avatars.discourse-cdn.com/v4/letter/2/3e96dc/32.png) [@2e71828](https://internals.rust-lang.org/u/2e71828)\
**Post date:** [April 28, 2021, 1:41pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/21 "2021-04-28T13:41:12Z")

</div>

If Rust ever gets keyword arguments, a mechanism to pass the same value to all applicable function calls in a block might serve this use case reasonably:

```rust
fn from_context(idx: usize, keyword ctx: &Context)->i32 { ... }

fn example1(ctx: &Context) {
     let keyword ctx = ctx;

     dbg!(from_context(3));
     dbg!(from_context(7));
}

// Equivalent to:

fn example2(ctx: &Context) {
    dbg!(from_context(3, ctx = ctx));
    dbg!(from_context(7, ctx = ctx));
}

```

(NB: This isn't a real proposal; the syntax here is probably terrible in many ways)

---

<div class="post-metadata">

**Author:** ![jgarvin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jgarvin/32/5329_2.png) [@jgarvin](https://internals.rust-lang.org/u/jgarvin)\
**Post date:** [April 30, 2021, 3:51pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/22 "2021-04-30T15:51:46Z")

</div>

> [@CAD97](#):
>
> One drawback you didn't mention is that to make allocator parameters work as a zero-cost abstraction, they need to be generic and monomorphized

Surely this is only true if the implicit parameter is a `impl T` parameter or otherwise generic? If the implicit parameter is just an integer I don't see why this would be necessary?

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 30, 2021, 5:22pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/23 "2021-04-30T17:22:24Z")

</div>

Yes, an implicit `i32` would not require monomorphization. But given a key motivating use case is implicit allocators, my point still stands.

---

<div class="post-metadata">

**Author:** ![Jon-Davis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jon-davis/32/5453_2.png) [@Jon-Davis](https://internals.rust-lang.org/u/Jon-Davis)\
**Post date:** [April 30, 2021, 7:12pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/24 "2021-04-30T19:12:57Z")

</div>

I presented the idea as if it was a generic feature, but local allocators were the primary motivation.

* * *

> [@kornel](#):
>
> before Rust gets implicit arguments, I think it should decide whether it wants optional/default

This is where I currently stand on the issue, I think a concept of implicit arguments should be conditional on default arguments. And if these features do ever manifest I think implicit paramaters could just simply wire new default arguments.

```rust
// Assume Box::new takes optional arg allocator that defaults to the global alloc
fn foo(){
   let implicit allocator = Bump::new()
   Box::new(Foo) // implicitly passes bump allocator to optional arg
}

```

This wouldn't solve the fragmentation issue, but it could make it simpler for library authors to add support. I could see a macro like `#[implicit_allocator]` that libarary authors could manually add to their functions to add support. This also ensures no API/ABI are changed implicitly.

```rust
#[implicit_allocator]
fn foo() { ... }
// becomes (I'm not sure what the default syntax looks like)
fn foo<A:Allocator>(allocator : implicit &A default GlobalAlloc) { ... }

```

* * *

> [@CAD97](#):
>
> every bin compile now is effectively a clean build that monomorphizes the entire world

Maybe by being opt-in like above this wouldn't be such an issue. I suspect that most Allocators will actually be passed by reference, maybe for debug builds the `#[implicit_allocator]` macro could get away with just using a &dyn Allocator and only compile using a `<A : Allocator>(&A)` functions on release.

---

<div class="post-metadata">

**Author:** ![felix.s](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/felix.s/32/8073_2.png) [@felix.s](https://internals.rust-lang.org/u/felix.s)\
**Post date:** [April 30, 2021, 7:13pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/25 "2021-04-30T19:13:54Z")

</div>

I sketched something similar in my head at one point.

The way I imagined it, modules could declare a new kind of item, a _symbol_ (name up to change; associations with symbols in Lisp or JavaScript may or may not be helpful). A symbol would associate a type with a name, kind of like a static; unlike a static, it would not create any storage.

```rust
mod foo {
    pub sym bar: u32;
}

```

Now, any code in which the symbol is visible would be able name an existing symbol when creating a binding instead of creating a new identifier:

```rust
let sym foo::bar = 1;

```

The presence of such a binding would allow you to refer to the symbol path as if it were a variable, and would refer to the symbol binding in the innermost scope. Shadowing of symbol bindings would of course be possible as usual.

It would also be possible to declare symbol bindings in argument lists:

```rust
fn quux(sym foo::bar) -> u32 {
    foo::bar + 1
}

```

Such a function would be callable only in scopes in which there is a binding pointing to the symbol, and would pass the value so bound.

```rust
println!("{}", quux()); // error: no symbol binding for foo::bar in scope
let sym foo::bar = 5;
println!("{}", quux()); // OK: prints 6

```

The presence of a symbol in a parameter list would of course create a symbol binding available to any callee:

```rust
fn xyzzy(sym foo::bar) -> u32 {
    quux() * quux() // OK
}

```

In effect, this would create a kind of quasi-dynamic scoping, but checked statically. Namespacing symbols in modules would avert the homograph problem that might otherwise result (what happens when two functions want symbol bindings with the same name but disagreeing types).

I did not pursue this idea further though, as I wasn’t sure if it pulled its weight and could be made ergonomic enough.

---

<div class="post-metadata">

**Author:** ![infogulch](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infogulch/32/4912_2.png) [@infogulch](https://internals.rust-lang.org/u/infogulch)\
**Post date:** [May 11, 2021, 7:05pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/26 "2021-05-11T19:05:31Z")

</div>

Please forgive this post for being a bit tangential. To me, this whole idea of implicit parameters bears a strong resemblance to 'algebraic effects' (Haskell) or 'monadic effects' (Scala) or 'abilities' (Unison). Though Unison is the most 'upstart' of these languages, I like its conception of this idea the best. I'll try to summarize Unison's take here, but to be honest I only have a shallow understanding.

**Edit** : I forgot to mention that the Unison creators attribute their implementation of effect handlers to ideas that came from the [Frank language](https://github.com/frank-lang/frank), which is explored in more clinical detail in the Frank language authors' paper titled [Do Be Do Be Do](https://arxiv.org/pdf/1611.09259.pdf) (yes, actually).

* * *

Unison is a pure functional language, so they also run into the classic "but how to IO?" problem. Unison's solution repackages monadic effects into "abilities" and "ability handlers". Practically, this looks like a second set of parameters ("abilities") declared on functions and has some slightly different rules for how the parameters propagate up to definitions implicitly and how such functions compose. Abilities themselves are declared like interfaces/traits, but they have more access to the control flow during execution. Here's an expanded excerpt of [Unison's docs on abilities](https://www.unisonweb.org/docs/abilities):

Here's a simple pure function that doesn't use abilities / do any fancy IO:

```rust
// impl of `msg` concatenates the Text arg name to construct another Text value
msg name = "Hello there " ++ name ++ "!"

```

Its definition would be:

```rust
// `msg` is a function that takes a Text and returns a Text
msg : Text -> Text

```

This function uses `msg` defined above to do some IO (print to stdout):

```rust
greet name = printLine (msg name)

```

It's definition would be:

```rust
// greet is a function that takes a Text and returns Unit (nothing), but also requires the IO ability (the `{IO}` part)
greet : Text ->{IO} ()

```

`msg` could also be declared as `msg : Text ->{} Text` which is identical to the previous definition except it explicitly declares that it accepts no abilities.

Abilities 'propagate up' definitions in a call chain. E.g. a function `greetMs name = greet ("Ms " ++ name)` would inherit the IO ability in its definition implicitly despite not using IO directly: `greetMs : Text ->{IO} ()`.

A function can require more than one ability, e.g. in `someFn : Text ->{IO, Abort} ()`, `someFn` is like `greet` but also requires the Abort ability.

A function can "handle" an ability in a function that it calls, which enables it to avoid requiring that ability in callers.

```rust
(Imagine I put an example here that calls `greet` with a handler for IO that puts calls to printLine 
in a buffer and returns the buffer, and thus its definition doesn't have to include `{IO}` in its list
of abilities.)
(sorry I don't know how to do that, and I suspect it would get a bit too far into the weeds for this post)

```

* * *

Now I think that Abilities are pretty neat and seems to be related to the "Implicit Parameters" being discussed here, but I have no idea how they would relate to a real Rust implementation and I'm not making any specific recommendations, I just wanted to connect this thing to that other thing just in case we can learn something from other work in this space.

Here are (probably too many) resources I found that discuss abilities in Unison:

- The [Unison docs on Abilities](https://www.unisonweb.org/docs/abilities) covers it pretty well, and the [FAQ](https://www.unisonweb.org/docs/faq/#language) mentions the similarity to haskell's algebraic effects
- In [What's cool about Unison?](https://jaredforsyth.com/posts/whats-cool-about-unison/), Jared (who wrote an experimental [implementation of the Unison runtime in rust](https://github.com/jaredly/unison.rs)) mentions algebraic effects / abilities right at the top.
- Slideshare [From Scala Monadic Effects to Unison Algebraic Effects](https://www.slideshare.net/pjschwarz/from-scala-monadic-effects-to-unison-algebraic-effects) describes abilities from the perspective of Scala using Option re-imagined as the Abort ability as a case study
- This [univalence blog post](https://univalence.io/blog/articles/unison-langage/#abilities) discusses abilities in Unison
- The short gist [Converting between algebraic effects and monads](https://gist.github.com/pchiusano/2e804c2aa81894c854a6b7f27c06fe28) describes how abilities are a nicer syntax for monads
- This gist [Unison abilities - unofficial alternative tutorial](https://gist.github.com/atacratic/7a91901d5535391910a2d34a2636a93c) is a slower more methodical introduction to abilities

Video content:

- The 2019 strangeloop talk ["Unison: a new distributed programming language" by Paul Chiusano](https://www.youtube.com/watch?v=gCWtkvDQ2ZI)
- 2021 [Philly Area Scala Enthusiasts talk by Rúnar Bjarnason on Unison](https://www.youtube.com/watch?v=TZZlt6-bKW8)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [August 9, 2021, 7:06pm UTC](https://internals.rust-lang.org/t/implicit-parameters/14514/27 "2021-08-09T19:06:15Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

[Previous page](https://internals.rust-lang.org/t/implicit-parameters/14514.md?page=1)
