I think you are right for not requiring PhantomData
and there are better solutions, as I am not expert as well so I will have blind spots.
I have experiences on almost all main stream languages, and I observed a lot of evaluation on languages.
Java introduced anonymous class first, as part of their solution for UI event handling mechanism. Just a few years ago they introduced closures. But their closures are just short hands for anonymous classes. Anonymous classes, by itself was proved to be really useful for Java programmers as they helped them to simplify the abstractions.
Rust on the other hand, introduced closure first. And now in this thread I realized only slightly modify its grammar we can support anonymous type on top of it.
In Rust, I believe anonymous type can also help encouraging the use of light weight traits, which will help programmers to build programs on top of abstractions, not on concrete behaviors.
So we now have two alternatives:
-
Anonymous type. Require new grammar like
fn take<T>(mut i: impl NewIterator<Item=T>, mut n:usize)
-> impl NewIterator<Item=T>
{
move impl NewIterator {
type Item=T;
fn next(&mut self) -> Option<T> {
...
}
})
}
(the move
keyword is needed as impl NewIterator
is not Copy
nor Clone
, so i
have to be moved to the anonymous object)
Then we will have self referencing closures for free (similar to what Java currently allows):
let mut password = gen_password();
accept_client(listen_socket, move impl FnOnce(Client) {
extern "rust-call" fn call_once(self, args:(Client,)) {
let (client,) = args;
handle(client, &self.password);
next_password(&mut self.password);
accept_client(self.listen_socket, self)
}
});
A macro can be introduced for this:
let mut password = gen_password();
accept_client(listen_socket, move self_closure!((Client,), {
handle(client, &self.password);
next_password(&mut self.password);
accept_client(self.listen_socket, self)
});
-
Self referencing closure. Then we have anonymous types for free.
fn take<T>(mut i: impl NewIterator<Item=T>, mut n:usize)
-> impl NewIterator<Item=T>
{
move |self| {
impl NewIterator for Self {
type Item=T;
fn next(&mut self) -> Option<R> {
...
}
}
}
}
(I originaly thought we need to call the closure but actually this is not necessary. The compiler knows the type of the closure, so it can pickup the trait implementation).
Again, a macro can simplify this:
fn take<T>(mut i: impl NewIterator<Item=T>, mut n:usize)
-> impl NewIterator<Item=T>
{
trait_impl!(NewIterator, {
type Item=T;
fn next(&mut self) -> Option<R> {
...
}
})
}
In either solution, one concern is how to handle the code generation if the trait contains a generic method. If there is no generic methods, the compiler can generate the type and methods after monomorphization, as all types are known. So initially, I would suggest a restriction on traits that only contains non-generic methods. We can always fallback to use named types so this will not restrict anything.