@@ -76,18 +76,18 @@ invocation of one of the following traits:
76
76
}
77
77
78
78
trait FnShare<A,R> {
79
- fn call (&self, args: A) -> R;
79
+ fn call_share (&self, args: A) -> R;
80
80
}
81
81
82
82
trait FnOnce<A,R> {
83
- fn call (&self, args: A) -> R;
83
+ fn call_once (&self, args: A) -> R;
84
84
}
85
85
86
86
Essentially, ` a(b, c, d) ` becomes sugar for one of the following:
87
87
88
88
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))
91
91
92
92
To integrate with this, closure expressions are then translated into a
93
93
fresh struct that implements one of those three traits. The precise
@@ -97,19 +97,19 @@ be inferred.
97
97
This change gives user control over virtual vs static dispatch. This
98
98
works in the same way as generic types today:
99
99
100
- fn foo(x: &mut Fn<int,int>) -> int {
100
+ fn foo(x: &mut Fn<( int,) ,int>) -> int {
101
101
x(2) // virtual dispatch
102
102
}
103
103
104
- fn foo<F:Fn<int,int>>(x: &mut F) -> int {
104
+ fn foo<F:Fn<( int,) ,int>>(x: &mut F) -> int {
105
105
x(2) // static dispatch
106
106
}
107
107
108
108
The change also permits returning closures, which is not currently
109
109
possible (the example relies on the proposed ` impl ` syntax from
110
110
rust-lang/rfcs #105 ):
111
111
112
- fn foo(x: impl Fn<int,int>) -> impl Fn<int,int> {
112
+ fn foo(x: impl Fn<( int,), int>) -> impl Fn<( int,) ,int> {
113
113
|v| x(v * 2)
114
114
}
115
115
@@ -349,7 +349,7 @@ simpler model overall. Moreover, native ABIs on platforms of interest
349
349
treat a structure passed by value identically to distinct
350
350
arguments. Finally, given that trait calls have the "Rust" ABI, which
351
351
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
353
353
native ABI).
354
354
355
355
** 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.
368
368
369
369
# Unresolved questions
370
370
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
+
371
422
## Closures that are quantified over lifetimes
372
423
373
424
A separate RFC is needed to describe bound lifetimes in trait
0 commit comments