Idiomatic way to structure Rust trait Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern) Data science time! April 2019 and salary with experience The Ask Question Wizard is Live!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

Does the Rock Gnome trait Artificer's Lore apply when you aren't proficient in History?

Getting representations of the Lie group out of representations of its Lie algebra

Diophantine equation 3^a+1=3^b+5^c

One-one communication

What is "Lambda" in Heston's original paper on stochastic volatility models?

How many time has Arya actually used Needle?

The Nth Gryphon Number

3D Masyu - A Die

Why are two-digit numbers in Jonathan Swift's "Gulliver's Travels" (1726) written in "German style"?

By what mechanism was the 2017 UK General Election called?

Determine whether an integer is a palindrome

Where did Ptolemy compare the Earth to the distance of fixed stars?

As a dual citizen, my US passport will expire one day after traveling to the US. Will this work?

Sally's older brother

French equivalents of おしゃれは足元から (Every good outfit starts with the shoes)

Pointing to problems without suggesting solutions

How to name indistinguishable henchmen in a screenplay?

Plotting a Maclaurin series

Can two people see the same photon?

Why not use the yoke to control yaw, as well as pitch and roll?

How could a hydrazine and N2O4 cloud (or it's reactants) show up in weather radar?

Flight departed from the gate 5 min before scheduled departure time. Refund options

Twin's vs. Twins'

What does 丫 mean? 丫是什么意思?



Idiomatic way to structure Rust trait



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!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

1928 у кіно

Захаров Федір Захарович

Ель Греко