[rust-dev] Inheritance / delegation

Ben Foppa benjamin.foppa at gmail.com
Fri Oct 17 12:49:39 PDT 2014


Also, re: the lifetimes. I'm not sure what the current status is, but I
know there are some RFCs to make "obvious" lifetimes more inferred.

On Fri, Oct 17, 2014 at 12:48 PM, Clark Gaebel <cg.wowus.cg at gmail.com>
wrote:

> Oooh fun you’ve hit your first rustc bug! Great!
>
> https://github.com/rust-lang/rust/issues/17178
>
> Niko is already working on this, so a fix is coming soon. Both of those
> constructions should have failed. The correct way to fix this is:
>
> ```
> let weights = [ 3,5,7 ];
> let b = InBag(Bag { price: 10, weights: weights.as_slice() });
> ```
>
>
>
> On Fri, Oct 17, 2014 at 12:30 PM, David Henningsson <diwic at ubuntu.com>
> wrote:
>
>> First, big thanks to both of you, Ben and Clark, for helping out. :-)
>>
>> Thanks for the hint on the lifetime syntax - it's a bit hard to grasp,
>> sometimes it's "Foo<'a>", sometimes it's "& 'a [Foo]", and I've seen
>> examples with "Foo+'a" too. But maybe this all makes sense when I'm more
>> used to the language.
>>
>> As for how long the pointed-to data is alive for, I think it makes sense
>> to default to "the same lifetime as parent struct or enum", if the lifetime
>> is not explicitly specified.
>>
>> Btw, for some reason this does not work:
>>
>> let s = InBag(Bag { price: 10, weights: &[3, 5, 7] }); /* fails with
>> "borrowed value does not live long enough" and "consider using a `let`
>> binding to increase its lifetime" */
>>
>> But the below does, and can be used as a workaround:
>>
>>    let b = Bag { price: 10, weights: &[3, 5, 7] };
>>    let s = InBag(b);
>>
>> I'm sure there's an explanation to why, but if it can be fixed so that
>> the compiler interprets the first as being equivalent to the second it
>> would be nice.
>>
>> On 2014-10-17 21:01, Ben Foppa wrote:
>>
>> Your struct has a fixed size - a reference is a pointer. Which is why it
>> requires a lifetime - how long is the pointed-to data alive for? And so you
>> need to tell it - in your enum example, you need to say Bag<'a> (for some
>> defined 'a). For example, Bag<'static> means the pointed-to data lives as
>> long as the program.
>>
>> On Fri, Oct 17, 2014 at 11:50 AM, David Henningsson <diwic at ubuntu.com>
>> wrote:
>>
>>>  Thanks for the answer. Deref is a new one for me, looks interesting by
>>> means of abstraction.
>>>
>>> I'm also coming from the C camp but I'm not sure how to write the code
>>> that I want in rust. Yet. :-)
>>>
>>> E g, here's one, somewhat related, C example that I'm not sure how to do
>>> in Rust:
>>>
>>> struct bag {
>>>    int price;
>>>    int nitems;
>>>    int []items;
>>> };
>>>
>>> struct cart { /* ... */ };
>>>
>>> struct shopping {
>>>    int kind; /* 0 means bag, 1 means cart */
>>>    union {
>>>       struct bag bag;
>>>       struct cart cart;
>>>    }
>>> }
>>>
>>> struct shopping* make_shopping_bag(int price, int nitems, int *items)
>>> {
>>>     struct shopping* result =
>>> malloc(sizeof(shopping)+nitems*sizeof(int));
>>>     result.kind = 0;
>>>     result.bag.price = price;
>>>     result.bag.nitems = nitems;
>>>     memcpy(result.bag.items, nitems*sizeof(int));
>>> }
>>>
>>>
>>> So, the bag struct would probably look like this in Rust:
>>>
>>> struct Bag <'a> {
>>>   price: int,
>>>   weights: & 'a [int],
>>> }
>>>
>>>  1) It feels like "weights: [int]" would be more like the way I want it,
>>> and the declaration compiles, but i can't initialize the struct or have it
>>> as a local variable because its size is now unkown. Even though a static
>>> initialization like "let b = Bag { price: 10, weights: [3,5,7] }" would be
>>> trivial to calculate the total size of, the compiler seems not to be able
>>> to do this.
>>>
>>>  2) I'm not sure why this lifetime has to be explicit, should default to
>>> "same lifetime as parent struct" IMO.
>>>
>>>  3) And when I try to do like:
>>>
>>> enum Shopping {
>>>   InBag(Bag),
>>>   InCart( /* ... */ ),
>>> }
>>>
>>> I get an error: "error: wrong number of lifetime parameters: expected 1,
>>> found 0". I've tried both "InBag('a Bag)" and "InBag(Bag + 'a)" but that
>>> ends up with other errors instead...so no idea on what to do about that?
>>>
>>>
>>> On 2014-10-17 18:37, Clark Gaebel wrote:
>>>
>>>  Rust is not a replacement for java, it’s a replacement for C and C++.
>>>
>>> To solve little “puzzles” like this, i tend to ask myself “how would I
>>> do this in C”, and then write that code in rust. Building inheritance trees
>>> is generally the wrong way of approaching problems. In cases where it does
>>> apply, you can still do it, but be gentle. Try not to lean on them as your
>>> primary means of abstraction.
>>>
>>> Anyhow, on to your actual problem.
>>>
>>> Something which might be worth trying is implementing `Deref<Circle>`
>>> and `DerefMut<Circle>` for your pancake, then having a
>>> `DList<Box<Deref<Circle>>>` (or just use a normal &, if you want that).
>>>
>>> Then you can call all your circle traits after a quick call to
>>> `.deref()`, AND your `DList` will free everything properly.
>>>
>>> But again, there’s probably a simpler solution that doesn’t involve
>>> “inheritance” that you should consider. Maybe a DList of enums? Maybe just
>>> a Vec<uint> in this case? Think about how you’d do it in C.
>>>
>>> Regards,
>>>   - Clark
>>>
>>>
>>>
>>> On Fri, Oct 17, 2014 at 4:27 AM, David Henningsson <diwic at ubuntu.com>
>>> wrote:
>>>
>>>> Hmm, right. The as_* could probably useful to write a macro for.
>>>>
>>>> Coming from the C/Java side of things I have to figure out how this
>>>> works in a bigger context, e g a DList or other structure owning
>>>> objects
>>>> implementing HasArea. This seems to compile, e g:
>>>>
>>>> impl Pancake {
>>>> fn as_box_circle(&self) -> Box<Circle> { box self.circle }
>>>> }
>>>>
>>>> fn make_pancake(dl: &mut DList<Box<HasArea>>) {
>>>> let p = Pancake { circle: Circle { x: 0f64, y: 0f64, radius: 1f64
>>>> }, is_tasty: true };
>>>> dl.push(p.as_box_circle());
>>>> }
>>>>
>>>> But I'd assume that make_pancake would now make a copy of the pancake's
>>>> circle, rather than taking ownership of the entire pancake, right? The
>>>> pancake then gets dropped at function return.
>>>>
>>>> In this simple example perhaps this does not make that much of a
>>>> difference though, but if you imagine a C struct like:
>>>>
>>>> struct list {
>>>> list *next;
>>>> circle *data;
>>>> }
>>>>
>>>> You can now put a pointer to a pancake as data, use it as a circle, and
>>>> when you finally free the list and the data that goes with it, the
>>>> entire pancake will be freed. This you cannot do in rust...or can you?
>>>>
>>>>
>>>> On 2014-10-17 07:59, Clark Gaebel wrote:
>>>> > impl Pancake {
>>>> > fn as_circle(&self) -> &Circle { &self.circle }
>>>> > fn as_mut_circle(&mut self) -> &mut Circle { &mut self.circle }
>>>> > }
>>>> >
>>>> > The compiler will optimize trivial functions, except cross-crate. In
>>>> > those cases, use an #[inline] annotation.
>>>> >
>>>> >
>>>> >
>>>> > On Thu, Oct 16, 2014 at 10:57 PM, David Henningsson <diwic at ubuntu.com
>>>> > <mailto:diwic at ubuntu.com> <diwic at ubuntu.com>> wrote:
>>>> >
>>>> > This is probably a previously asked question, but I couldn't find
>>>> > it on
>>>> > Google, so...
>>>> >
>>>> > Let's extend the Circle example from the guide a little:
>>>> >
>>>> > struct Circle {
>>>> > x:f64,
>>>> > y:f64,
>>>> > radius:f64,
>>>> > }
>>>> >
>>>> > trait HasArea {
>>>> > fn area(&self)-> f64;
>>>> > }
>>>> >
>>>> > impl HasArea for Circle {
>>>> > fn area(&self)-> f64 {
>>>> > std::f64::consts::PI * (self.radius * self.radius)
>>>> > }
>>>> > }
>>>> >
>>>> > struct Pancake {
>>>> > circle: Circle,
>>>> > is_tasty: bool,
>>>> > }
>>>> >
>>>> >
>>>> > ...now, what is the easiest way I can implement HasArea for
>>>> > Pancake? I
>>>> > could do this:
>>>> >
>>>> > impl HasArea for Pancake {
>>>> > fn area(&self) -> f64 { self.circle.area() }
>>>> > }
>>>> >
>>>> > ...but that means a lot of boiler-plate code, especially if
>>>> > HasArea has
>>>> > many methods. Hopefully rust will just inline/optimise the
>>>> > redirection
>>>> > away in most cases to avoid the runtime cost, but is there a
>>>> > smarter or
>>>> > more idiomatic way of doing this?
>>>> >
>>>> > // David
>>>> >
>>>> > _______________________________________________
>>>> > Rust-dev mailing list
>>>> > Rust-dev at mozilla.org
>>>> > https://mail.mozilla.org/listinfo/rust-dev
>>>> >
>>>> >
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> Rust-dev mailing list
>>> Rust-dev at mozilla.org
>>> https://mail.mozilla.org/listinfo/rust-dev
>>>
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20141017/b1f53ce2/attachment.html>


More information about the Rust-dev mailing list