On Sat, Feb 1, 2014 at 4:57 AM, Niko Matsakis <[email protected]> wrote:

> Regarding the marker types, they are somewhat awkward, and are not the
> approach I originally favored. But they have some real advantages:
>
> - Easily extensible as we add new requirements, unlike syntax.
> - Easily documented.
> - These bounds are only used for unsafe code, so it's not something
>   ordinary users should have to stumble over.
>
> What concerns me more is that marker types are "opt in" -- so if you
> don't know that you need them, and you build a datatype founded on
> unsafe code, you can get incorrect behavior. There may be some steps
> we can take to mitigate that in some cases.
>
> In any case, the use of marker types are also quite orthogonal to your
> other concerns:


I meant that marker types seem like more of the same approach that was
taken with lifetimes in iterators (i.e. declaring a dummy field).  I don't
have a firm opinion about what syntax I'd prefer for markers in general,
but I do have some ideas about lifetimes, which are probably the most
commonly used type bound in Rust.



> > This also makes the intent much more clear.   Currently, one would have
> to
> > dig into the definition of MutItems<'a,T> to figure out that the lifetime
> > parameter 'a is used to create a dummy borrow field into the vector, so
> > that the whole iterator is then treated as a mutable borrow.   This feels
> > very convoluted, if you ask me.
>
> I disagree -- I think treating lifetime and type parameters uniformly
> feels cleaner than permitting lifetime bounds to appear in random
> places. Presumably `'a Foo<T>` would be syntactic sugar for `Foo<'a, T>`?
> There's an obvious ambiguity here with `&'a T`.
>

Since &'a Foo<T> currently means "the return value is a reference into
something that has lifetime 'a",  'a Foo<T> feels like a natural extension
for saying "the return value is a reference-like thing whose safety depends
on something that has lifetime 'a still being around".
Foo<'a,T>, of the other hand... it is not obvious to me why would it
necessarily mean that.   Is this because the only way to use a lifetime
parameter in a type is to create a reference field into something with that
lifetime?  If so, it feels like one logical deduction too many for the
reader of the code to make.

And what if the lifetime parameter isn't used at all?   After all, I can do
that with regular type parameters (i.e. declare, but not use).  Then
Foo<'a,T> would only appear as having lifetime 'a, without actually being
so?


> On a slightly different note, is there a strong reason for having to name
> > lifetime parameters explicitly?   Could we simply re-use actual parameter
> > names prefixed with ' as their lifetimes?
>
> It is plausible we could say that a lifetime parameter name that is
> the same as a local variable binding whose type is a borrowed pointer
> refers to the lifetime of that borrowed pointer. To me, it feels like
> a rather ad hoc rule, though I can see it would sometimes be convenient.
>
> The current rules are intended to showcase how lifetime parameters work
> precisely like type parameters. In other words, we write:
>
>     fn copy<T>(t: T) -> T;
>
> we do not write:
>
>     fn copy(t) -> t;
>
> In the same way, we identify and declare lifetime parameters.
>
> Note that lifetime parameters do not have a natural one-to-one
> relationship with variables. It's certainly possible (and reasonable)
> to declare a function like:
>
>     fn foo<'a, 'b, 'c>(x: &'a Foo<'b, 'c>)
>
> In which case, the meaning of `'x` is pretty unclear to me.
>

I'd like it to mean "the lifetime of whatever x points to", i.e. 'x == 'a.
I realize that this is somewhat problematic, because x itself is the
reference, not something it points to, but... you know, because
auto-dereferencing...  :-)


> > The above could then be reduced to this:
> >
> >     pub trait MutableVector<T> {
> >         fn mut_iter(self) -> 'self MutItems<T>;
> >         ...
> >     }
> >
> > This used to be valid syntax, btw, though it worked because 'self
> lifetime
> > was special, IIRC.
>
> Writing `'self` was valid syntax, but it didn't have the meaning you
> are proposing. Which is one of the reasons we removed it.
>

I've been around Rust for almost a year now,  and certainly since the time
the current lifetime notation has been introduced, and I *still *could not
explain to somebody, why a lifetime parameter appearing among the type
parameters of a trait or a struct refers to the lifetime of that trait or
struct.  It isn't used to declare any reference fields...  (and traits
can't have fields, of course).

I'd understand if the above example had to be written as:

    pub trait MutableVector<T> {
         fn mut_iter<'a>(&'a mut self) -> 'a MutItems<T>;
         ...
      }
But the current notation completely evades me.


Regarding 'self:  Ok, say what you want about reusing parameter names for
lifetimes in general, but having syntax sugar for the lifetime of the
current struct was totally worth it, IMHO.
We already have sugar for "self", or else we'd be writing "trait Foo<T> {
fn method(self:&Foo<T>) ... }", so why not for its' lifetime?  In my
estimation, referencing the current struct constitutes like 90% of all
lifetime parameter usage.  Back when we had 'self, Rust sources looked way
less noisy.


Vadim
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to