Summary

The Fn traits should be modified to make the return type an associated type.

Motivation

The strongest reason is because it would permit

許す
impls like the following (example from @alexcrichton):

#![allow(unused)] fn main() { impl<R,F> Foo for F : FnMut() -> R { ... } }

This impl is currently illegal

文法違反
because the parameter
仮引数
R is not constrained. (This also has an impact on my attempts to add variance, which would require a "phantom data" annotation for R for the same reason; but that RFC is not quite ready yet.)

Another related reason is that it often permits

許す
fewer type parameters.
仮引数
Rather than having a distinct
区別された/独立した
type parameter
仮引数
for the return type, the associated type projection F::Output can be used. Consider
考える、みなす
the standard library Map type:

#![allow(unused)] fn main() { struct Map<A,B,I,F> where I : Iterator<Item=A>, F : FnMut(A) -> B, { ... } impl<A,B,I,F> Iterator for Map<A,B,I,F> where I : Iterator<Item=A>, F : FnMut(A) -> B, { type Item = B; ... } }

This type could be equivalently written:

#![allow(unused)] fn main() { struct Map<I,F> where I : Iterator, F : FnMut<(I::Item,)> { ... } impl<I,F> Iterator for Map<I,F>, where I : Iterator, F : FnMut<(I::Item,)>, { type Item = F::Output; ... } }

This example highlights one subtle point about the () notation,

記法
which is covered below.

Detailed design
設計(する)

The design

設計(する)
has been implemented.
実装する
You can see it in this pull request. The Fn trait is modified to read as follows:
下記の、次に続く、追従する

#![allow(unused)] fn main() { trait Fn<A> { type Output; fn call(&self, args: A) -> Self::Output; } }

The other traits are modified in an analogous fashion.

Parentheses
丸かっこ(で囲う)
notation
記法

The shorthand

簡略表現
Foo(...) expands to Foo<(...), Output=()>. The shorthand
簡略表現
Foo(..) -> B expands to Foo<(...), Output=B>. This implies
暗黙の
that if you use the parenthetical notation,
記法
you must supply a return type (which could be a new type parameter). If you would prefer to leave the return type unspecified,
特定されていない
you must use angle-bracket notation.
記法
(Note that using angle-bracket notation
記法
with the Fn traits is currently feature-gated, as described
記述する
here
.)

This can be seen in the In the Map example from the introduction.

はじめに、導入
There the <> notation
記法
was used so that F::Output is left unbound:

#![allow(unused)] fn main() { struct Map<I,F> where I : Iterator, F : FnMut<(I::Item,)> }

An alternative

代わりのもの、選択肢
would be to retain the type parameter
仮引数
B:

#![allow(unused)] fn main() { struct Map<B,I,F> where I : Iterator, F : FnMut(I::Item) -> B }

Or to remove the bound

制限する、結び付けられて
on F from the type definition
定義
and use it only in the impl:

#![allow(unused)] fn main() { struct Map<I,F> where I : Iterator { ... } impl<B,I,F> Iterator for Map<I,F>, where I : Iterator, F : FnMut(I::Item) -> B { type Item = F::Output; ... } }

Note that this final option is not legal

(文法的に)適格
without this change, because the type parameter
仮引数
B on the impl would be unconstrained.

Drawbacks

Cannot overload based
基となる、基底(の)
on return type alone

This change means that you cannot overload indexing to "model" a trait like Default:

#![allow(unused)] fn main() { trait Default { fn default() -> Self; } }

That is, I can't do something like the following:

#![allow(unused)] fn main() { struct Defaulty; impl<T:Default> Fn<()> for Defaulty { type Output = T; fn call(&self) -> T { Default::default() } } }

This is not possible because the impl type parameter

仮引数
T is not constrained.

This does not seem like a particularly strong limitation. Overloaded call

呼び出し
notation
記法
is already less general
一般
than full traits in various
さまざまな
ways (for example, it lacks the ability to define
定義する
a closure that always panics; that is, the ! notation
記法
is not a type and hence something like FnMut() -> ! is not legal). The ability to overload based
基となる、基底(の)
on return type is not removed, it is simply not something you can model using overloaded operators.
演算子

Alternatives

Special syntax
文法
to represent the lack of an Output binding

Rather than having people use angle-brackets to omit

省略する
the Output binding, we could introduce
導入する
some special syntax
文法
for this purpose. For example, FnMut() -> ? could desugar to FnMut<()> (whereas FnMut() alone desugars to FnMut<(), Output=()>). The first suggestion that is commonly made is FnMut() -> _, but that has an existing meaning in a function context
文脈、背景
(where _ represents
表現する
a fresh type variable).

Change meaning of FnMut() to not bind
束ねる/くっつける
the output

We could make FnMut() desugar to FnMut<()>, and hence require an explicit

明示的な
FnMut() -> () to bind
束ねる/くっつける
the return type to unit. This feels suprising and inconsistent.