Idiomatic way to structure Rust traitHow to clone a struct storing a boxed trait object?How can you make a safe static singleton in Rust?What is the difference between traits in Rust and typeclasses in Haskell?Issue with Rust using dynamic polymorphism on trait when specifying lifetime on selfImplementing Nested TraitsIdiomatic callbacks in RustIs it possible to implement ASN.1 DER in Rust using Serde?How can I test equality to a given boxed object implementing a trait?Is there any way to simulate Generic Associated Types / Associated Type Constructors in Rust?How to write a trait method taking an iterator of strings, avoiding monomorphization (static dispatch)?Store data that implements a trait in a vector

What are these boxed doors outside store fronts in New York?

Do I have a twin with permutated remainders?

Today is the Center

Why is Minecraft giving an OpenGL error?

Did Shadowfax go to Valinor?

If human space travel is limited by the G force vulnerability, is there a way to counter G forces?

Doing something right before you need it - expression for this?

Are the number of citations and number of published articles the most important criteria for a tenure promotion?

How is it possible to have an ability score that is less than 3?

LaTeX: Why are digits allowed in environments, but forbidden in commands?

How can I make my BBEG immortal short of making them a Lich or Vampire?

Why is 150k or 200k jobs considered good when there's 300k+ births a month?

tikz convert color string to hex value

Can a vampire attack twice with their claws using Multiattack?

Is it possible to run Internet Explorer on OS X El Capitan?

NMaximize is not converging to a solution

Maximum likelihood parameters deviate from posterior distributions

Do infinite dimensional systems make sense?

Why do I get two different answers for this counting problem?

What is the word for reserving something for yourself before others do?

Why are electrically insulating heatsinks so rare? Is it just cost?

Character reincarnated...as a snail

What does the "remote control" for a QF-4 look like?

Why can't I see bouncing of a switch on an oscilloscope?



Idiomatic way to structure Rust trait


How to clone a struct storing a boxed trait object?How can you make a safe static singleton in Rust?What is the difference between traits in Rust and typeclasses in Haskell?Issue with Rust using dynamic polymorphism on trait when specifying lifetime on selfImplementing Nested TraitsIdiomatic callbacks in RustIs it possible to implement ASN.1 DER in Rust using Serde?How can I test equality to a given boxed object implementing a trait?Is there any way to simulate Generic Associated Types / Associated Type Constructors in Rust?How to write a trait method taking an iterator of strings, avoiding monomorphization (static dispatch)?Store data that implements a trait in a vector






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








0















I have been writing a Ray Caster in Rust following "The Ray Tracer Challenge", and I've been having a hard time figuring out the proper way to implement polymorphism in Rust. My priorities are that the object can be used in a multi-threaded program, and that seems to be the main problem.



I have two cases on this, but I'll focus on one: a shape. There are different kinds of shapes (sticking with the able suffix I originally called my trait Intersectable). Here was a working trait object implementation, but it didn't work with multi-threading:



#[derive(Debug)]
pub struct Shape
pub parent: Option<Arc<Shape>>,
pub transform: Matrix4,
pub material: Material,
pub intersectable: Box<Intersectable>,

pub trait Intersectable: Debug + IntersectableClone
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>;


pub trait IntersectableClone
fn clone_box(&self) -> Box<Intersectable>;


impl<T> IntersectableClone for T
where
T: 'static + Intersectable + Clone,

fn clone_box(&self) -> Box<Intersectable>
Box::new(self.clone())



impl Clone for Box<Intersectable>
fn clone(&self) -> Box<Intersectable>
self.clone_box()



#[derive(Clone, Debug)]
pub struct Sphere

impl Intersectable for Sphere
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code



#[derive(Clone, Debug)]
pub struct Plane

impl Intersectable for Plane
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific code





As a pure struct, with no official polymorphism, I've written a kind of static dispatch that looks like this:



#[derive(Debug, Clone)]
pub enum IntersectableType
Sphere,
Plane,


#[derive(Debug, Clone)]
pub struct Intersectable
intersectable_type: IntersectableType,


impl Intersectable
pub fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
match self.intersectable_type
IntersectableType::Sphere => self.local_intersect_sphere(ray, object),
IntersectableType::Plane => self.local_intersect_plane(ray, object),
_ => Vec::new(),



fn local_intersect_sphere(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code


fn local_intersect_plane(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific implementation




This works great, but it feels very non-Rusty. I've hit a few problems with using other implementations:
- Using Box<Intersectable> (when it was a Trait, not a struct), is difficult to clone (I copied How to clone a struct storing a boxed trait object? but didn't love having to use 'static, since that made concurrency impossible).
- Using Arc<Intersectable> seemed to have the same problems as Box, though maybe there is a way to make that work.



Is there a way to do this in Rust that allows me to take advantage of concurrency and not write manual static dispatch like this?










share|improve this question
























  • Would you be able to show functional examples of the trait approach you've tried so far, so we can understand the issues you had? It'll be a lot easier than us trying to start from scratch.

    – loganfsmyth
    Mar 9 at 1:25







  • 1





    Yes, I have added the main implementation I had before this one!

    – Josh
    Mar 9 at 1:46












  • Perhaps you could just store a function pointer fn(&Ray, Arc<Shape>) -> Vec<Intersection> in your Shape. I believe fn is Clone + Send. It's essentially what you're already doing with dynamic dispatch on empty structs.

    – JayDepp
    Mar 9 at 2:52











  • That is a very interesting concept that I hadn't thought about, I will give it a shot and report back!

    – Josh
    Mar 9 at 6:17

















0















I have been writing a Ray Caster in Rust following "The Ray Tracer Challenge", and I've been having a hard time figuring out the proper way to implement polymorphism in Rust. My priorities are that the object can be used in a multi-threaded program, and that seems to be the main problem.



I have two cases on this, but I'll focus on one: a shape. There are different kinds of shapes (sticking with the able suffix I originally called my trait Intersectable). Here was a working trait object implementation, but it didn't work with multi-threading:



#[derive(Debug)]
pub struct Shape
pub parent: Option<Arc<Shape>>,
pub transform: Matrix4,
pub material: Material,
pub intersectable: Box<Intersectable>,

pub trait Intersectable: Debug + IntersectableClone
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>;


pub trait IntersectableClone
fn clone_box(&self) -> Box<Intersectable>;


impl<T> IntersectableClone for T
where
T: 'static + Intersectable + Clone,

fn clone_box(&self) -> Box<Intersectable>
Box::new(self.clone())



impl Clone for Box<Intersectable>
fn clone(&self) -> Box<Intersectable>
self.clone_box()



#[derive(Clone, Debug)]
pub struct Sphere

impl Intersectable for Sphere
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code



#[derive(Clone, Debug)]
pub struct Plane

impl Intersectable for Plane
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific code





As a pure struct, with no official polymorphism, I've written a kind of static dispatch that looks like this:



#[derive(Debug, Clone)]
pub enum IntersectableType
Sphere,
Plane,


#[derive(Debug, Clone)]
pub struct Intersectable
intersectable_type: IntersectableType,


impl Intersectable
pub fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
match self.intersectable_type
IntersectableType::Sphere => self.local_intersect_sphere(ray, object),
IntersectableType::Plane => self.local_intersect_plane(ray, object),
_ => Vec::new(),



fn local_intersect_sphere(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code


fn local_intersect_plane(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific implementation




This works great, but it feels very non-Rusty. I've hit a few problems with using other implementations:
- Using Box<Intersectable> (when it was a Trait, not a struct), is difficult to clone (I copied How to clone a struct storing a boxed trait object? but didn't love having to use 'static, since that made concurrency impossible).
- Using Arc<Intersectable> seemed to have the same problems as Box, though maybe there is a way to make that work.



Is there a way to do this in Rust that allows me to take advantage of concurrency and not write manual static dispatch like this?










share|improve this question
























  • Would you be able to show functional examples of the trait approach you've tried so far, so we can understand the issues you had? It'll be a lot easier than us trying to start from scratch.

    – loganfsmyth
    Mar 9 at 1:25







  • 1





    Yes, I have added the main implementation I had before this one!

    – Josh
    Mar 9 at 1:46












  • Perhaps you could just store a function pointer fn(&Ray, Arc<Shape>) -> Vec<Intersection> in your Shape. I believe fn is Clone + Send. It's essentially what you're already doing with dynamic dispatch on empty structs.

    – JayDepp
    Mar 9 at 2:52











  • That is a very interesting concept that I hadn't thought about, I will give it a shot and report back!

    – Josh
    Mar 9 at 6:17













0












0








0








I have been writing a Ray Caster in Rust following "The Ray Tracer Challenge", and I've been having a hard time figuring out the proper way to implement polymorphism in Rust. My priorities are that the object can be used in a multi-threaded program, and that seems to be the main problem.



I have two cases on this, but I'll focus on one: a shape. There are different kinds of shapes (sticking with the able suffix I originally called my trait Intersectable). Here was a working trait object implementation, but it didn't work with multi-threading:



#[derive(Debug)]
pub struct Shape
pub parent: Option<Arc<Shape>>,
pub transform: Matrix4,
pub material: Material,
pub intersectable: Box<Intersectable>,

pub trait Intersectable: Debug + IntersectableClone
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>;


pub trait IntersectableClone
fn clone_box(&self) -> Box<Intersectable>;


impl<T> IntersectableClone for T
where
T: 'static + Intersectable + Clone,

fn clone_box(&self) -> Box<Intersectable>
Box::new(self.clone())



impl Clone for Box<Intersectable>
fn clone(&self) -> Box<Intersectable>
self.clone_box()



#[derive(Clone, Debug)]
pub struct Sphere

impl Intersectable for Sphere
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code



#[derive(Clone, Debug)]
pub struct Plane

impl Intersectable for Plane
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific code





As a pure struct, with no official polymorphism, I've written a kind of static dispatch that looks like this:



#[derive(Debug, Clone)]
pub enum IntersectableType
Sphere,
Plane,


#[derive(Debug, Clone)]
pub struct Intersectable
intersectable_type: IntersectableType,


impl Intersectable
pub fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
match self.intersectable_type
IntersectableType::Sphere => self.local_intersect_sphere(ray, object),
IntersectableType::Plane => self.local_intersect_plane(ray, object),
_ => Vec::new(),



fn local_intersect_sphere(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code


fn local_intersect_plane(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific implementation




This works great, but it feels very non-Rusty. I've hit a few problems with using other implementations:
- Using Box<Intersectable> (when it was a Trait, not a struct), is difficult to clone (I copied How to clone a struct storing a boxed trait object? but didn't love having to use 'static, since that made concurrency impossible).
- Using Arc<Intersectable> seemed to have the same problems as Box, though maybe there is a way to make that work.



Is there a way to do this in Rust that allows me to take advantage of concurrency and not write manual static dispatch like this?










share|improve this question
















I have been writing a Ray Caster in Rust following "The Ray Tracer Challenge", and I've been having a hard time figuring out the proper way to implement polymorphism in Rust. My priorities are that the object can be used in a multi-threaded program, and that seems to be the main problem.



I have two cases on this, but I'll focus on one: a shape. There are different kinds of shapes (sticking with the able suffix I originally called my trait Intersectable). Here was a working trait object implementation, but it didn't work with multi-threading:



#[derive(Debug)]
pub struct Shape
pub parent: Option<Arc<Shape>>,
pub transform: Matrix4,
pub material: Material,
pub intersectable: Box<Intersectable>,

pub trait Intersectable: Debug + IntersectableClone
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>;


pub trait IntersectableClone
fn clone_box(&self) -> Box<Intersectable>;


impl<T> IntersectableClone for T
where
T: 'static + Intersectable + Clone,

fn clone_box(&self) -> Box<Intersectable>
Box::new(self.clone())



impl Clone for Box<Intersectable>
fn clone(&self) -> Box<Intersectable>
self.clone_box()



#[derive(Clone, Debug)]
pub struct Sphere

impl Intersectable for Sphere
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code



#[derive(Clone, Debug)]
pub struct Plane

impl Intersectable for Plane
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific code





As a pure struct, with no official polymorphism, I've written a kind of static dispatch that looks like this:



#[derive(Debug, Clone)]
pub enum IntersectableType
Sphere,
Plane,


#[derive(Debug, Clone)]
pub struct Intersectable
intersectable_type: IntersectableType,


impl Intersectable
pub fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
match self.intersectable_type
IntersectableType::Sphere => self.local_intersect_sphere(ray, object),
IntersectableType::Plane => self.local_intersect_plane(ray, object),
_ => Vec::new(),



fn local_intersect_sphere(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...sphere specific code


fn local_intersect_plane(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>
...plane specific implementation




This works great, but it feels very non-Rusty. I've hit a few problems with using other implementations:
- Using Box<Intersectable> (when it was a Trait, not a struct), is difficult to clone (I copied How to clone a struct storing a boxed trait object? but didn't love having to use 'static, since that made concurrency impossible).
- Using Arc<Intersectable> seemed to have the same problems as Box, though maybe there is a way to make that work.



Is there a way to do this in Rust that allows me to take advantage of concurrency and not write manual static dispatch like this?







rust






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 9 at 1:49







Josh

















asked Mar 9 at 1:01









JoshJosh

509




509












  • Would you be able to show functional examples of the trait approach you've tried so far, so we can understand the issues you had? It'll be a lot easier than us trying to start from scratch.

    – loganfsmyth
    Mar 9 at 1:25







  • 1





    Yes, I have added the main implementation I had before this one!

    – Josh
    Mar 9 at 1:46












  • Perhaps you could just store a function pointer fn(&Ray, Arc<Shape>) -> Vec<Intersection> in your Shape. I believe fn is Clone + Send. It's essentially what you're already doing with dynamic dispatch on empty structs.

    – JayDepp
    Mar 9 at 2:52











  • That is a very interesting concept that I hadn't thought about, I will give it a shot and report back!

    – Josh
    Mar 9 at 6:17

















  • Would you be able to show functional examples of the trait approach you've tried so far, so we can understand the issues you had? It'll be a lot easier than us trying to start from scratch.

    – loganfsmyth
    Mar 9 at 1:25







  • 1





    Yes, I have added the main implementation I had before this one!

    – Josh
    Mar 9 at 1:46












  • Perhaps you could just store a function pointer fn(&Ray, Arc<Shape>) -> Vec<Intersection> in your Shape. I believe fn is Clone + Send. It's essentially what you're already doing with dynamic dispatch on empty structs.

    – JayDepp
    Mar 9 at 2:52











  • That is a very interesting concept that I hadn't thought about, I will give it a shot and report back!

    – Josh
    Mar 9 at 6:17
















Would you be able to show functional examples of the trait approach you've tried so far, so we can understand the issues you had? It'll be a lot easier than us trying to start from scratch.

– loganfsmyth
Mar 9 at 1:25






Would you be able to show functional examples of the trait approach you've tried so far, so we can understand the issues you had? It'll be a lot easier than us trying to start from scratch.

– loganfsmyth
Mar 9 at 1:25





1




1





Yes, I have added the main implementation I had before this one!

– Josh
Mar 9 at 1:46






Yes, I have added the main implementation I had before this one!

– Josh
Mar 9 at 1:46














Perhaps you could just store a function pointer fn(&Ray, Arc<Shape>) -> Vec<Intersection> in your Shape. I believe fn is Clone + Send. It's essentially what you're already doing with dynamic dispatch on empty structs.

– JayDepp
Mar 9 at 2:52





Perhaps you could just store a function pointer fn(&Ray, Arc<Shape>) -> Vec<Intersection> in your Shape. I believe fn is Clone + Send. It's essentially what you're already doing with dynamic dispatch on empty structs.

– JayDepp
Mar 9 at 2:52













That is a very interesting concept that I hadn't thought about, I will give it a shot and report back!

– Josh
Mar 9 at 6:17





That is a very interesting concept that I hadn't thought about, I will give it a shot and report back!

– Josh
Mar 9 at 6:17












0






active

oldest

votes












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
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55072976%2fidiomatic-way-to-structure-rust-trait%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes















draft saved

draft discarded
















































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.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55072976%2fidiomatic-way-to-structure-rust-trait%23new-answer', 'question_page');

);

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







Popular posts from this blog

Identity Server 4 is not redirecting to Angular app after login2019 Community Moderator ElectionIdentity Server 4 and dockerIdentityserver implicit flow unauthorized_clientIdentityServer Hybrid Flow - Access Token is null after user successful loginIdentity Server to MVC client : Page Redirect After loginLogin with Steam OpenId(oidc-client-js)Identity Server 4+.NET Core 2.0 + IdentityIdentityServer4 post-login redirect not working in Edge browserCall to IdentityServer4 generates System.NullReferenceException: Object reference not set to an instance of an objectIdentityServer4 without HTTPS not workingHow to get Authorization code from identity server without login form

2005 Ahvaz unrest Contents Background Causes Casualties Aftermath See also References Navigation menue"At Least 10 Are Killed by Bombs in Iran""Iran"Archived"Arab-Iranians in Iran to make April 15 'Day of Fury'"State of Mind, State of Order: Reactions to Ethnic Unrest in the Islamic Republic of Iran.10.1111/j.1754-9469.2008.00028.x"Iran hangs Arab separatists"Iran Overview from ArchivedConstitution of the Islamic Republic of Iran"Tehran puzzled by forged 'riots' letter""Iran and its minorities: Down in the second class""Iran: Handling Of Ahvaz Unrest Could End With Televised Confessions""Bombings Rock Iran Ahead of Election""Five die in Iran ethnic clashes""Iran: Need for restraint as anniversary of unrest in Khuzestan approaches"Archived"Iranian Sunni protesters killed in clashes with security forces"Archived

Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme