Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions text/1522-conservative-impl-trait.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,47 @@ But basically, without this feature certain things remain hard or impossible to
in Rust, like returning a efficiently usable type parameterized by
types private to a function body, for example an iterator adapter containing a closure.

## Alternative to returnning unboxed closures

Theoratically, if we are defining a function need to return an unboxed closure, it can always
rewritten to a function that takes more parameters.

For example, a fix point function takes a `Fn(T) -> R` and returns a `Fn(T) -> R` like this
with the proposed `impl Trait` feature:

```rust
fn fix<T, R, F>(f: &F) -> impl Fn(T) -> R
where F: Fn(T) -> R
{
f(|t| fix(f)(t))
}
...
let closure = fix(func);
```

can be re-written as

```rust
fn fix<T, R, F>(f: F, t:T) -> R
where F: Fn(T) -> R
{
f(|t|fix(f, t), t)
}
...
let closure = |t|fix(func, t);
```

@cramertj cramertj Jun 29, 2017 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't equivalent. In the first function, you're returning a closure which can be evaluated with another argument at a later time. In the second, you're delaying running the function at all until it has been called with the last argument.

Consider, for example, the case where you add a println!("Hello!"); to the beginning of each fix function:

let func = |_| {};

// With `fix` version 1:
let closure = fix(func); // prints "Hello!"
closure(1); // Runs the closure, prints nothing
closure(1); // Runs the closure again, prints nothing

// With `fix` version 2:
let closure = |t| fix(func, t); // prints nothing
closure(1); // prints "Hello!"
closure(1); // prints "Hello!"


We can see in the calling site it is slightly different, but with some clever macros this can be
made more like the former.

If we improve the code generator such that it can generate target code for the later when the source code
is written in the former, we will achieve the same outcome without any further change on the other parts
of the language.

This technology can also be used for traits other than the `FnXXX` ones. What we need is a grammar
to construct a trait implementation on the fly, like the closure grammar above. Once we have that,
a translater can adjust the function signature and add the trait constructor in the calling site.

# Unresolved questions
[unresolved]: #unresolved-questions

Expand Down