Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unsized return values. #977

Closed
wants to merge 2 commits into from
Closed

Add unsized return values. #977

wants to merge 2 commits into from

Conversation

mahkoh
Copy link
Contributor

@mahkoh mahkoh commented Mar 14, 2015

Add the concept of unsized return values, e.g.,

fn f() -> [u8];

Rendered

@Manishearth
Copy link
Member

+1. I was going to say we should wait for placement new to be accepted, but that already happened, so... :)

allocation or return a reference to an already deallocated slice.

(For similar reasons it's not possible to implement the trait on
`&mut Box<[T]>`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm convinced of L144-L145, but not of this. Can't we impl<'a, T> IntoSlice<'a, T> for &'a mut? Box<[T]>?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For posterity: discussion on IRC lead to clarification that IntoSlice is for translating into a slice which owns its contents, so it certainly cannot be implemented for non-owning references of Box<[T]>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it can be implemented with &mut Box<[T]> with mem::replace.

Let me explain why that does not work. Let's assume again the following signature:

fn into_slice(self) -> &'a [T];

Since the return value doesn't own the memory the slice is stored in (the heap), we cannot replace the whole Box<[T]> by an empty box:

// does not work
mem::replace(self, box []);

Next we might try to just set the length of the slice in the box to zero and return the real slice:

let slice = &**self;
// transmute *self to raw;:Slice, set length to zero, transmute back
return slice

The reason that this doesn't work is that when the Box<[T]> is eventually dropped, it sees that the length is zero, which is what we wanted because now the box doesn't drop its elements. However, jemalloc uses sized deallocation which means that Box must know its real size in order to deallocate itself.

@arielb1
Copy link
Contributor

arielb1 commented Mar 16, 2015

How is this supposed to work? The size of an unsized type is not known until the function returns. Do functions returning unsized values take an implicit allocator argument? When is the allocator called?

@mahkoh
Copy link
Contributor Author

mahkoh commented Mar 16, 2015

@arielb1 All of your questions are answered in the RFC.

@arielb1
Copy link
Contributor

arielb1 commented Mar 17, 2015

What allocator API are you using?

@Ericson2314
Copy link
Contributor

On one hand, this allows us to abstract over box patterns, which is currently not possible, and that is a huge plus. On the other there is a fair amount of magic going on. And I'm sort of disposed to not thinking about this or box placement until we have to tools (&own, &undef, allocator API, etc) to specify both concretely. Otherwise the conversation seems a bit vague and I frankly get confused.

It's a bit ironic that this is somewhat reminiscent to the comments proposing taking unboxed unsized types as an alternative to &own in your other RFC. Going off that, what if instead of interpreting unsized function parameters as implicitly boxed (as was proposed in those comments), we allow a analogous construct to this, where the callee somehow prepares a lvalue "slot" for the unsized rvalue to be deposited in. This would seems to be wholly more powerful than placement new in that you can do it for multiple args, at the expense of being yet more crazy magic.

Don't want to derail, just want to point out that the stuff proposed here isn't only applicable to returning, assuming I understand the situation correctly. And if we add the magic to one, why doesn't the other deserve it too?

@mahkoh
Copy link
Contributor Author

mahkoh commented Mar 19, 2015

we allow a analogous construct to this, where the callee somehow prepares a lvalue "slot" for the unsized rvalue to be deposited in

The point of the placement box RFC is that it's not possible to do this efficiently and safely. In the case of unsafe types it's even less possible.

@nikomatsakis
Copy link
Contributor

I think this is a reasonably good idea, but we should postpone it for now, for two reasons:

  1. I would like to do this as part of a larger initiative for passing ownership of DST instances. In particular I want to be able to pass ownership into a fn as well as returning out.
  2. The box protocol is unstable and I think it's too early to go building new designs on it.

Therefore, I am going to close this as postponed under issue #990.

UPDATE: Sorry, I should have said that this was also the decision reached at the triage meeting.

@mahkoh
Copy link
Contributor Author

mahkoh commented Mar 19, 2015

I would like to do this as part of a larger initiative for passing ownership of DST instances. In particular I want to be able to pass ownership into a fn as well as returning out.

That's what the &own RFC does. This RFC was opened after we realized in the &own RFC that passing unsized types into functions can only reach its full potential when functions can also return unsized types. So I think this part is already fulfilled.

@bombless
Copy link

We may use fn f()->&box [u8] instead of fn f() -> [u8]; to represent pointer for boxing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants