Sami Nopanen wrote:
1. Why is the lifetime name sometimes before a type and sometimes
after the type.
There are two kinds of types which can be annotated with lifetime
names. The first is a borrowed pointer:
</T
In this case, the lifetime `lt` is the lifetime of this pointer. The
second is a struct, enum, or type alias:
StringReader/<
In this case, the lifetime `lt` is the lifetime of any borrowed pointers
contained within the struct, enum, or type alias. So, in the case of
the `StringReader` example you gave, the definition of `StringReader` was:
struct StringReader { value: &str, count: uint }
Therefore, `StringReader/<` means "a StringReader where the lifetime
of the `value` field is `lt`". The definition of StringReader is really
a kind of generic type definition parameterized over a lifetime, kind of
like:
struct StringReader<<> {
value: </str,
count: uint
}
Right now the compiler hides this declaration from you to make things
more pleasant and easy to type. However, we have all agreed on changing
this so that lifetime parameters on structs, enums, etc will become
explicit. But there are some niggling details remaining as to the
precise syntax.
2. In the 'new' method, is the 'self' in the parameter 'value:
&self/str' just a random name for
the lifetime parameter or does this refer somehow to the 'self'
type (in which case I'd be ever
more confused, I guess :-):
The `self` is a lifetime in that instance. I mentioned before that
(today) the compiler implicitly decides when a type is parameterized by
a lifetime. When it does, it uses the name `self` as the name of the
lifetime parameter. So the `self` lifetime here refers to the lifetime
of the borrowed pointers contained within the `self` struct.
As far as I understand, this would mean that the type instance would
have to be
built in the same stack frame as where the variable binding
defining the lifetime parameter precides.
This is close but not quite right. It's not actually important where
the newly constructed struct is stored. It's only important when it
gets used. So if the struct is built with a string with lifetime X,
then we must make sure that the struct is not used outside of that
lifetime X.
But how about if the string has a lifetime beyond the calling
function, such as:
fn foo(s : &str) {
let sr = StringReader::new(s);
...
sr
}
fn bar() {
let s = ~"foobar";
let sr = foo(s);
}
This example can be typed, but it requires some annotations. In
particular, `foo` should look like:
fn foo(s : &v/str) -> StringReader/&v {
let sr = StringReader::new(s);
...
sr
}
Here, the return type `StringReader/&v` tells the caller of `foo()`: "I
am going to be returning a StringReader that is valid for the same
lifetime as the string `s` that you gave me."
If you did not supply the explicit lifetime annotation, you will get a
compile-time error, because the caller does not know that there is a
link between the lifetime of `s` and the lifetime of the returned
value. In general, whenever you return a borrowed pointer, or a value
that contains borrowed pointers, you will need an explicit lifetime
annotation so that you can link the lifetime of that return value to the
lifetime of a parameter.
Now, for the lifetime of StringReader to match the lifetime of the
string, it AFAIK would need to be
stored in the stack frame of 'bar' instead of the stackframe of
'foo'. Does this actually happen (e.g. the
compiler is able to preallocate the correct slots in the stack), is
there some other magic going on or
would this just be a compile error?
As I wrote above, there is less magic going on then you think. The
`StringReader` will initially be stored in the stack frame of `foo` and
then copied into the stack frame of `bar()` when `foo()` returns. It's
not required that it only be stored in `bar()`, so long as it is never
used after `bar()` returns.
Hope this helps.
regards,
Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev