How to call a method that consumes self on a boxed trait object?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have the following sketch of an implementation:
trait Listener {
fn some_action(&mut self);
fn commit(self);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self) {
println!("{:?}", "Commit");
}
}
struct Transaction {
listeners: Vec<Box<Listener>>,
}
impl Transaction {
fn commit(self) {
// How would I consume the listeners and call commit() on each of them?
}
}
fn listener() {
let transaction = Transaction {
listeners: vec![Box::new(FooListener {})],
};
transaction.commit();
}
I can have Transactions with listeners on them that will call the listener when something happens on that transaction. Since Listener is a trait, I store a Vec<Box<Listener>>.
I'm having a hard time implementing commit for Transaction. Somehow I have to consume the boxes by calling commit on each of the stored Listeners, but I can't move stuff out of a box as far as I know.
How would I consume my listeners on commit?
rust ownership-semantics
add a comment |
I have the following sketch of an implementation:
trait Listener {
fn some_action(&mut self);
fn commit(self);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self) {
println!("{:?}", "Commit");
}
}
struct Transaction {
listeners: Vec<Box<Listener>>,
}
impl Transaction {
fn commit(self) {
// How would I consume the listeners and call commit() on each of them?
}
}
fn listener() {
let transaction = Transaction {
listeners: vec![Box::new(FooListener {})],
};
transaction.commit();
}
I can have Transactions with listeners on them that will call the listener when something happens on that transaction. Since Listener is a trait, I store a Vec<Box<Listener>>.
I'm having a hard time implementing commit for Transaction. Somehow I have to consume the boxes by calling commit on each of the stored Listeners, but I can't move stuff out of a box as far as I know.
How would I consume my listeners on commit?
rust ownership-semantics
Moving "stuff" out of a box is easy; you just dereference it. Your case is more complicated because you no longer know how big the value stored inside the box was. This means you get an error: cannot move a value of type Listener: the size of Listener cannot be statically determined.
– Shepmaster
Oct 7 '17 at 13:44
add a comment |
I have the following sketch of an implementation:
trait Listener {
fn some_action(&mut self);
fn commit(self);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self) {
println!("{:?}", "Commit");
}
}
struct Transaction {
listeners: Vec<Box<Listener>>,
}
impl Transaction {
fn commit(self) {
// How would I consume the listeners and call commit() on each of them?
}
}
fn listener() {
let transaction = Transaction {
listeners: vec![Box::new(FooListener {})],
};
transaction.commit();
}
I can have Transactions with listeners on them that will call the listener when something happens on that transaction. Since Listener is a trait, I store a Vec<Box<Listener>>.
I'm having a hard time implementing commit for Transaction. Somehow I have to consume the boxes by calling commit on each of the stored Listeners, but I can't move stuff out of a box as far as I know.
How would I consume my listeners on commit?
rust ownership-semantics
I have the following sketch of an implementation:
trait Listener {
fn some_action(&mut self);
fn commit(self);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self) {
println!("{:?}", "Commit");
}
}
struct Transaction {
listeners: Vec<Box<Listener>>,
}
impl Transaction {
fn commit(self) {
// How would I consume the listeners and call commit() on each of them?
}
}
fn listener() {
let transaction = Transaction {
listeners: vec![Box::new(FooListener {})],
};
transaction.commit();
}
I can have Transactions with listeners on them that will call the listener when something happens on that transaction. Since Listener is a trait, I store a Vec<Box<Listener>>.
I'm having a hard time implementing commit for Transaction. Somehow I have to consume the boxes by calling commit on each of the stored Listeners, but I can't move stuff out of a box as far as I know.
How would I consume my listeners on commit?
rust ownership-semantics
rust ownership-semantics
edited Oct 7 '17 at 13:37
Shepmaster
161k16332476
161k16332476
asked Oct 7 '17 at 13:35
WorldSEnderWorldSEnder
2,95711740
2,95711740
Moving "stuff" out of a box is easy; you just dereference it. Your case is more complicated because you no longer know how big the value stored inside the box was. This means you get an error: cannot move a value of type Listener: the size of Listener cannot be statically determined.
– Shepmaster
Oct 7 '17 at 13:44
add a comment |
Moving "stuff" out of a box is easy; you just dereference it. Your case is more complicated because you no longer know how big the value stored inside the box was. This means you get an error: cannot move a value of type Listener: the size of Listener cannot be statically determined.
– Shepmaster
Oct 7 '17 at 13:44
Moving "stuff" out of a box is easy; you just dereference it. Your case is more complicated because you no longer know how big the value stored inside the box was. This means you get an error: cannot move a value of type Listener: the size of Listener cannot be statically determined.
– Shepmaster
Oct 7 '17 at 13:44
Moving "stuff" out of a box is easy; you just dereference it. Your case is more complicated because you no longer know how big the value stored inside the box was. This means you get an error: cannot move a value of type Listener: the size of Listener cannot be statically determined.
– Shepmaster
Oct 7 '17 at 13:44
add a comment |
1 Answer
1
active
oldest
votes
Applying commit to the boxed object is not allowed because the trait object doesn't know its size (and it's not constant at compile-time). Since you plan to use listeners as boxed objects, what you can do is acknowledge that commit will be invoked on the box and change its signature accordingly:
trait Listener {
fn some_action(&mut self);
fn commit(self: Box<Self>);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self: Box<Self>) {
println!("{:?}", "Commit");
}
}
This enables Transaction to compile as you wrote it, because inside the implementation of FooListener the size of Self is well known and it is perfectly possible to move the object out of the box and consume both.
The price of this solution is that Listener::commit now requires a Box. If that is not acceptable, you could declare both commit(self) and commit_boxed(self: Box<Self>) in the trait, requiring all types to implement both, possibly using private functions or macros to avoid code duplication. This is not very elegant, but it would satisfy both the boxed and unboxed use case without loss of performance.
Does this work for trait objects? Like, if I have alet box: Box<Listener>, can I callbox.commit();?
– Lucretiel
Jul 9 '18 at 6:17
I ask becauseSelfis going to be FooListener, not Listener, correct?
– Lucretiel
Jul 9 '18 at 6:17
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f46620790%2fhow-to-call-a-method-that-consumes-self-on-a-boxed-trait-object%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Applying commit to the boxed object is not allowed because the trait object doesn't know its size (and it's not constant at compile-time). Since you plan to use listeners as boxed objects, what you can do is acknowledge that commit will be invoked on the box and change its signature accordingly:
trait Listener {
fn some_action(&mut self);
fn commit(self: Box<Self>);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self: Box<Self>) {
println!("{:?}", "Commit");
}
}
This enables Transaction to compile as you wrote it, because inside the implementation of FooListener the size of Self is well known and it is perfectly possible to move the object out of the box and consume both.
The price of this solution is that Listener::commit now requires a Box. If that is not acceptable, you could declare both commit(self) and commit_boxed(self: Box<Self>) in the trait, requiring all types to implement both, possibly using private functions or macros to avoid code duplication. This is not very elegant, but it would satisfy both the boxed and unboxed use case without loss of performance.
Does this work for trait objects? Like, if I have alet box: Box<Listener>, can I callbox.commit();?
– Lucretiel
Jul 9 '18 at 6:17
I ask becauseSelfis going to be FooListener, not Listener, correct?
– Lucretiel
Jul 9 '18 at 6:17
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
add a comment |
Applying commit to the boxed object is not allowed because the trait object doesn't know its size (and it's not constant at compile-time). Since you plan to use listeners as boxed objects, what you can do is acknowledge that commit will be invoked on the box and change its signature accordingly:
trait Listener {
fn some_action(&mut self);
fn commit(self: Box<Self>);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self: Box<Self>) {
println!("{:?}", "Commit");
}
}
This enables Transaction to compile as you wrote it, because inside the implementation of FooListener the size of Self is well known and it is perfectly possible to move the object out of the box and consume both.
The price of this solution is that Listener::commit now requires a Box. If that is not acceptable, you could declare both commit(self) and commit_boxed(self: Box<Self>) in the trait, requiring all types to implement both, possibly using private functions or macros to avoid code duplication. This is not very elegant, but it would satisfy both the boxed and unboxed use case without loss of performance.
Does this work for trait objects? Like, if I have alet box: Box<Listener>, can I callbox.commit();?
– Lucretiel
Jul 9 '18 at 6:17
I ask becauseSelfis going to be FooListener, not Listener, correct?
– Lucretiel
Jul 9 '18 at 6:17
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
add a comment |
Applying commit to the boxed object is not allowed because the trait object doesn't know its size (and it's not constant at compile-time). Since you plan to use listeners as boxed objects, what you can do is acknowledge that commit will be invoked on the box and change its signature accordingly:
trait Listener {
fn some_action(&mut self);
fn commit(self: Box<Self>);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self: Box<Self>) {
println!("{:?}", "Commit");
}
}
This enables Transaction to compile as you wrote it, because inside the implementation of FooListener the size of Self is well known and it is perfectly possible to move the object out of the box and consume both.
The price of this solution is that Listener::commit now requires a Box. If that is not acceptable, you could declare both commit(self) and commit_boxed(self: Box<Self>) in the trait, requiring all types to implement both, possibly using private functions or macros to avoid code duplication. This is not very elegant, but it would satisfy both the boxed and unboxed use case without loss of performance.
Applying commit to the boxed object is not allowed because the trait object doesn't know its size (and it's not constant at compile-time). Since you plan to use listeners as boxed objects, what you can do is acknowledge that commit will be invoked on the box and change its signature accordingly:
trait Listener {
fn some_action(&mut self);
fn commit(self: Box<Self>);
}
struct FooListener {}
impl Listener for FooListener {
fn some_action(&mut self) {
println!("{:?}", "Action!!");
}
fn commit(self: Box<Self>) {
println!("{:?}", "Commit");
}
}
This enables Transaction to compile as you wrote it, because inside the implementation of FooListener the size of Self is well known and it is perfectly possible to move the object out of the box and consume both.
The price of this solution is that Listener::commit now requires a Box. If that is not acceptable, you could declare both commit(self) and commit_boxed(self: Box<Self>) in the trait, requiring all types to implement both, possibly using private functions or macros to avoid code duplication. This is not very elegant, but it would satisfy both the boxed and unboxed use case without loss of performance.
edited Oct 9 '17 at 19:01
answered Oct 7 '17 at 22:37
user4815162342user4815162342
64.6k595151
64.6k595151
Does this work for trait objects? Like, if I have alet box: Box<Listener>, can I callbox.commit();?
– Lucretiel
Jul 9 '18 at 6:17
I ask becauseSelfis going to be FooListener, not Listener, correct?
– Lucretiel
Jul 9 '18 at 6:17
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
add a comment |
Does this work for trait objects? Like, if I have alet box: Box<Listener>, can I callbox.commit();?
– Lucretiel
Jul 9 '18 at 6:17
I ask becauseSelfis going to be FooListener, not Listener, correct?
– Lucretiel
Jul 9 '18 at 6:17
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
Does this work for trait objects? Like, if I have a
let box: Box<Listener>, can I call box.commit();?– Lucretiel
Jul 9 '18 at 6:17
Does this work for trait objects? Like, if I have a
let box: Box<Listener>, can I call box.commit();?– Lucretiel
Jul 9 '18 at 6:17
I ask because
Self is going to be FooListener, not Listener, correct?– Lucretiel
Jul 9 '18 at 6:17
I ask because
Self is going to be FooListener, not Listener, correct?– Lucretiel
Jul 9 '18 at 6:17
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
@Lucretiel Yes, the answer (and likely the question) was written with trait objects in mind.
– user4815162342
Jul 9 '18 at 6:20
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f46620790%2fhow-to-call-a-method-that-consumes-self-on-a-boxed-trait-object%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown

Moving "stuff" out of a box is easy; you just dereference it. Your case is more complicated because you no longer know how big the value stored inside the box was. This means you get an error: cannot move a value of type Listener: the size of Listener cannot be statically determined.
– Shepmaster
Oct 7 '17 at 13:44