kvark/copyless

Turn a Box into a BoxAllocation

Opened this issue · 5 comments

It might be useful to be able to take an existing Box and turn it back into a BoxAllocation.
For example, you might want to use the same allocation twice like in this contrived example:

fn make_big_thing(box_alloc: BoxAllocation<Thing>) -> Box<Thing> {
    box_alloc.init(...)
}

fn main() {
    let box_alloc = BoxAllocation::init();
    let thing = make_big_thing(box_alloc);
    do_something_with_thing(&thing);

    let box_alloc = BoxAllocation::from_box(thing);
    let thing2 = make_big_thing(box_alloc);
    do_something_with_thing(&thing2);
}
kvark commented

How would this be different from just overwriting the contents of the box you have, i.e.

let box_alloc = BoxAllocation::init();
    let mut thing = make_big_thing(box_alloc);
    do_something_with_thing(&thing);

    *thing = <something>;
    do_something_with_thing(&thing);

That example code doesn't call make_big_thing twice while mine does, so it misses the point. make_big_thing takes a BoxAllocation<Thing> because it wants an uninitialised space to put an instance of Thing. If you can't turn a Box back into a BoxAllocation, you would be required to make a brand new allocation each time that make_big_thing is called.

kvark commented

Could you make an example of what make_big_thing does that can't be expressed with my code sample?

Say I have some function that parses data about an animal from a file:

struct Animal {
	age: u32,
	weight: f32,
	height: f32,
	number_of_legs: u32,
	a lot of other fields, making this a huge struct...
}

fn parse_animal_from_file(filename: String) -> Box<Animal> {
	let file = open(filename);
	let age = file.parse_age();
	let weight = file.parse_weight();
	...
	BoxAllocation<Animal>::alloc().init(Animal {age, weight, height, etc.})
}

let dog_data = parse_animal_from_file("dog.txt");
print("{:?}", dog_data);
// Note that dog_data is no longer used past this point.
let cat_data = parse_animal_from_file("cat.txt");
print("{:?}", cat_data);

Then I decide I want to be able to reuse an allocation if possible if I already have one. Why not?
So I rewrite it like so:

fn parse_animal_from_file(filename: String, box_alloc: BoxAllocation<Animal>) -> Box<Animal> {
	let file = open(filename);
	let age = file.parse_age();
	let weight = file.parse_weight();
	...
	box_alloc.init(Animal {age, weight, height, etc.})
}

let box_alloc = BoxAllocation<Thing>::alloc();
let dog_data = parse_animal_from_file("dog.txt", box_alloc);
print("{:?}", dog_data);
let box_alloc = dog_data.turn_back_into_alloc();
let cat_data = parse_animal_from_file("cat.txt", box_alloc);
print("{:?}", cat_data);

But unfortunately this doesn't work because no such turn_back_into_alloc function exists.

kvark commented

It sounds like you could do this instead:

fn parse_animal_from_file(filename: String) -> Animal {
...
}
let dog_data = Box::alloc().init(parse_animal_from_file("dog.txt"));
print("{:?}", dog_data);
let mut cat_data = dog_data;
*cat_data = parse_animal_from_file("cat.txt");
print("{:?}", cat_data);

That would equally preserve the allocation, without the need to go back to BoxAllocation