Skip to content

Commit c3cf523

Browse files
committed
Correct typos and describe @eddyb and @anasazi proposals
1 parent 620a173 commit c3cf523

File tree

1 file changed

+59
-8
lines changed

1 file changed

+59
-8
lines changed

active/0000-closures.md

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,18 @@ invocation of one of the following traits:
7676
}
7777

7878
trait FnShare<A,R> {
79-
fn call(&self, args: A) -> R;
79+
fn call_share(&self, args: A) -> R;
8080
}
8181

8282
trait FnOnce<A,R> {
83-
fn call(&self, args: A) -> R;
83+
fn call_once(&self, args: A) -> R;
8484
}
8585

8686
Essentially, `a(b, c, d)` becomes sugar for one of the following:
8787

8888
Fn::call(&mut a, (b, c, d))
89-
FnShare::call(&a, (b, c, d))
90-
FnOnce::call(a, (b, c, d))
89+
FnShare::call_share(&a, (b, c, d))
90+
FnOnce::call_once(a, (b, c, d))
9191

9292
To integrate with this, closure expressions are then translated into a
9393
fresh struct that implements one of those three traits. The precise
@@ -97,19 +97,19 @@ be inferred.
9797
This change gives user control over virtual vs static dispatch. This
9898
works in the same way as generic types today:
9999

100-
fn foo(x: &mut Fn<int,int>) -> int {
100+
fn foo(x: &mut Fn<(int,),int>) -> int {
101101
x(2) // virtual dispatch
102102
}
103103

104-
fn foo<F:Fn<int,int>>(x: &mut F) -> int {
104+
fn foo<F:Fn<(int,),int>>(x: &mut F) -> int {
105105
x(2) // static dispatch
106106
}
107107

108108
The change also permits returning closures, which is not currently
109109
possible (the example relies on the proposed `impl` syntax from
110110
rust-lang/rfcs#105):
111111

112-
fn foo(x: impl Fn<int,int>) -> impl Fn<int,int> {
112+
fn foo(x: impl Fn<(int,),int>) -> impl Fn<(int,),int> {
113113
|v| x(v * 2)
114114
}
115115

@@ -349,7 +349,7 @@ simpler model overall. Moreover, native ABIs on platforms of interest
349349
treat a structure passed by value identically to distinct
350350
arguments. Finally, given that trait calls have the "Rust" ABI, which
351351
is not specified, we can always tweak the rules if necessary (though
352-
their advantages for tooling when the Rust ABI closely matches the
352+
there are advantages for tooling when the Rust ABI closely matches the
353353
native ABI).
354354

355355
**Use inference to determine the self type of a closure rather than an
@@ -368,6 +368,57 @@ TBD. pcwalton is working furiously as we speak.
368368

369369
# Unresolved questions
370370

371+
**What if any relationship should there be between the closure
372+
traits?** On the one hand, there is clearly a relationship between the
373+
traits. For example, given a `FnShare`, one can easily implement
374+
`Fn`:
375+
376+
impl<A,R,T:FnShare<A,R>> Fn<A,R> for T {
377+
fn call(&mut self, args: A) -> R {
378+
(&*self).call_share(args)
379+
}
380+
}
381+
382+
Similarly, given a `Fn` or `FnShare`, you can implement `FnOnce`. From
383+
this, one might derive a subtrait relationship:
384+
385+
trait FnOnce { ... }
386+
trait Fn : FnOnce { ... }
387+
trait FnShare : Fn { ... }
388+
389+
Employing this relationship, however, would require that any manual
390+
implement of `FnShare` or `Fn` must implement adapters for the other
391+
two traits, since a subtrait cannot provide a specialized default of
392+
supertrait methods (yet?). On the other hand, having no relationship
393+
between the traits limits reuse, at least without employing explicit
394+
adapters.
395+
396+
Other alternatives that have been proposed to address the problem:
397+
398+
- Use impls to implement the fn traits in terms of one another,
399+
similar to what is shown above. The problem is that we would need to
400+
implement `FnOnce` both for all `T` where `T:Fn` and for all `T`
401+
where `T:FnShare`. This will yield coherence errors unless we extend
402+
the language with a means to declare traits as mutually exclusive
403+
(which might be valuable, but no such system has currently been
404+
proposed nor agreed upon).
405+
406+
- Have the compiler implement multiple traits for a single closure.
407+
As with supertraits, this would require manual implements to
408+
implement multiple traits. It would also require generic users to
409+
write `T:Fn+FnMut` or else employ an explicit adapter. On the other
410+
hand, it preserves the "one method per trait" rule described below.
411+
412+
**Can we optimize away the trait vtable?** The runtime representation
413+
of a reference `&Trait` to a trait object (and hence, under this
414+
proposal, closures as well) is a pair of pointers `(data, vtable)`. It
415+
has been proposed that we might be able to optimize this
416+
representation to `(data, fnptr)` so long as `Trait` has a single
417+
function. This slightly improves the performance of invoking the
418+
function as one need not indirect through the vtable. The actual
419+
implications of this on performance are unclear, but it might be a
420+
reason to keep the closure traits to a single method.
421+
371422
## Closures that are quantified over lifetimes
372423

373424
A separate RFC is needed to describe bound lifetimes in trait

0 commit comments

Comments
 (0)