First off, sorry for the delayed response. Busy.

I think it would be great to have a trait that means "something
callable". This is basically overriding the "call operator".  The
biggest hurdle to such a thing is the fact that lifetimes can only be
bound on `fn` types right now.

To achieve parity, we'd have to allow lifetime binders on trait refs
(meaning objcets and type parameter bounds).  I haven't thought a lot
about this except to say that it we did permit it, it would address
some other issues that arise elsewhere, for example in conditions
(which basically are trying to emulate fn types using closures).

The main thing is that there would be no way using the current trait
system to encode a type like `fn<'a>(&'a uint) -> &'a uint`. Imagine
we had a trait like

    trait Fn<A,R> {
        fn call(&mut self, arg: A) -> R;
    }

To be the equivalent of the fn type `fn<'a>(&'a uint) -> &'a uint`,
we'd need some way to say "the argument and return type can be
references with any lifetime so long 'a as it's the same". We don't
currently have a way to express that.

Note that a type like `Fn<&'a uint, &'a uint>` doesn't mean quite the
same thing: it does say that both the argument and return type have
the same lifetime (`'a`), but here `'a` is referring to some lifetime
that is in scope, rather than referring to a lifetime that vary from
call to call. It's precisely the distinction between `fn foo<T>(x: T)
-> T` vs `fn foo(x: T) -> T`.

To address this, perhaps we might permit one to write `<'a> Fn<&'a
uint, &'a uint>` to express the equivalent of that fn type. Here the
leading `<'a>` binds the lifetime name `'a` so that this type means
"takes an argument and return type with some lifetime 'a" rather than
"...with *the* lifetime 'a". In theoretical terms, this is a kind of
`forall` type (we could also write `forall 'a. Fn<...>`).

I haven't thought especially hard about this. We have to be careful
not to violate soundness, naturally. I imagine if we limited lifetime
binders to trait references, we could still have the conversion from
bound lifetimes to concrete names be implicit, for example upon access
to a trait member (e.g., when you write `f.call(...)`, much like the
bound lifetimes on a closure are instantiated when you call it with
`f(...)`).

All in all, I think it'd be worthwhile to do something like this, but
I had hoped to defer it until later, since there are still some number
of implementation issues to address with the current type rules.


Niko

On Wed, Jun 12, 2013 at 07:11:25PM +0100, Amanieu d'Antras wrote:
> Hi,
> 
> I've been working on a proposal to unify Rust's closure type with
> traits. The idea is based on C++ function objects, which allow any
> object which implements the function call operator to be callable.
> 
> The full proposal is at:
> https://github.com/mozilla/rust/wiki/Proposal-for-function-objects
> 
> I would appreciate any feedback you may have.
> 
> Amanieu
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to