You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue was labelled with: in the Rust repository
Disclaimer
Please bear with me, this contains long code samples but you can skip through most of them until the last one if you are only mildly interested, they're just there to illustrate my point.
Problem
While adding comments on rand::rng() I figured that it would be a lot better if the function would return a generic "interface" type for Rngs instead of returning the type of the particular struct it uses at the moment. However after discussing this with @kballard and @cmr on IRC, it seems that it is now pretty much impossible to achieve.
I'll go through the variants I researched, and then propose a solution (which may not be realistic, I have no clue about rustc internals, but I hope it is).
Failed attempt 1: Returning traits as a makeshift interface
This failed miserably because it's just not how the language works at all, and I got that now, but it's included for completeness.
test.rs:6:4: 7:1 error: mismatched types: expected `T` but found `std::rand::IsaacRng` (expected type parameter but found struct std::rand::IsaacRng)
test.rs:6 IsaacRng::new()
test.rs:7 }
test.rs:10:4: 11:1 error: mismatched types: expected `T` but found `std::rand::XorShiftRng` (expected type parameter but found struct std::rand::XorShiftRng)
test.rs:10 XorShiftRng::new()
test.rs:11 }
test.rs:15:14: 15:31 error: the type of this value must be known in this context
test.rs:15 printfln!(rng.gen_bytes(10));
^~~~~~~~~~~~~~~~~
Failed attempt 2: Using newtypes to "hide" the real implementation
This would be an ok workaround, it's not perfect but it seems to be workable given the constraints of the language and isn't too crazy, however it fails because it is missing the proper implementations:
use std::rand::{IsaacRng,XorShiftRng,RngUtil,Rng};fnmain(){let rng = rng();printfln!(rng.gen_bytes(10));}structStrongRng(IsaacRng);pubfnrng() -> StrongRng{StrongRng(IsaacRng::new())}structWeakRng(XorShiftRng);pubfnweak_rng() -> WeakRng{WeakRng(XorShiftRng::new())}
test.rs:19:14: 19:31 error: failed to find an implementation of trait std::rand::Rng for StrongRng
test.rs:19 printfln!(rng.gen_bytes(10));
^~~~~~~~~~~~~~~~~
Failed attempt 3: Implementing a decorator newtype
This probably is workable unless I don't get how to work around the compiler errors that are left, but I assume it's not a dead end. The problem though is that it is extremely verbose and seriously painful to write all this boilerplate just to have a straight decorator wrapping the underlying struct.
test.rs:70:14: 70:31 error: multiple applicable methods in scope
test.rs:70 printfln!(rng.gen_bytes(10));
^~~~~~~~~~~~~~~~~
note: in expansion of fmt!
<std-macros>:226:20: 226:37 note: expansion site
<std-macros>:224:4: 231:5 note: in expansion of printfln!
test.rs:70:4: 70:33 note: expansion site
test.rs:98:4: 100:5 note: candidate #1 is `__extensions__::gen_bytes`
test.rs:98 fn gen_bytes(&mut self, len: uint) -> ~[u8] {
test.rs:99 return (**self).gen_bytes(len);
test.rs:100 }
test.rs:70:14: 70:31 note: candidate #2 is `std::rand::__extensions__::gen_bytes`
test.rs:70 printfln!(rng.gen_bytes(10));
^~~~~~~~~~~~~~~~~
note: in expansion of fmt!
<std-macros>:226:20: 226:37 note: expansion site
<std-macros>:224:4: 231:5 note: in expansion of printfln!
test.rs:70:4: 70:33 note: expansion site
test.rs:79:0: 122:1 error: multiple applicable methods in scope
test.rs:79 impl RngUtil for StrongRng {
test.rs:80 fn gen<T:Rand>(&mut self) -> T {
test.rs:81 return (**self).gen();
test.rs:82 }
test.rs:83 fn gen_int_range(&mut self, start: int, end: int) -> int {
test.rs:84 return (**self).gen_int_range(start, end);
...
test.rs:134:0: 177:1 error: multiple applicable methods in scope
test.rs:134 impl RngUtil for WeakRng {
test.rs:135 fn gen<T:Rand>(&mut self) -> T {
test.rs:136 return (**self).gen();
test.rs:137 }
test.rs:138 fn gen_int_range(&mut self, start: int, end: int) -> int {
test.rs:139 return (**self).gen_int_range(start, end);
...
error: aborting due to 3 previous errors
Proposal
The ideal way would be to allow the newtype to derive traits, so that making a decorator is not a PITA anymore. As you see right now it fails because the derive can't find the right impl, but I think it should just create it on the fly instead of complaining. That way we get explicit "interface" definition by defining which traits are implemented on the newtype, and we can return that and avoid a BC fiasco when we need to change the underlying RNG (see #8349 for more info on that).
I'd be happy to try and help implement this feature because I strongly believe this is needed, but to be honest I have no clue where to even start so pointers would be nice if the consensus is that it is a good thing and that it is at all feasible :)
use std::rand::{IsaacRng,XorShiftRng,RngUtil,Rng};fnmain(){let rng = rng();printfln!(rng.gen_bytes(10));}#[derive(Rng,RngUtil)]structStrongRng(IsaacRng);pubfnrng() -> StrongRng{StrongRng(IsaacRng::new())}#[derive(Rng,RngUtil)]structWeakRng(XorShiftRng);pubfnweak_rng() -> WeakRng{WeakRng(XorShiftRng::new())}
test.rs:70:14: 70:31 error: failed to find an implementation of trait std::rand::Rng for StrongRng
test.rs:70 printfln!(rng.gen_bytes(10));
^~~~~~~~~~~~~~~~~
note: in expansion of fmt!
The text was updated successfully, but these errors were encountered:
Issue by Seldaek
Tuesday Aug 06, 2013 at 21:15 GMT
For earlier discussion, see rust-lang/rust#8353
This issue was labelled with: in the Rust repository
Disclaimer
Please bear with me, this contains long code samples but you can skip through most of them until the last one if you are only mildly interested, they're just there to illustrate my point.
Problem
While adding comments on
rand::rng()
I figured that it would be a lot better if the function would return a generic "interface" type for Rngs instead of returning the type of the particular struct it uses at the moment. However after discussing this with @kballard and @cmr on IRC, it seems that it is now pretty much impossible to achieve.I'll go through the variants I researched, and then propose a solution (which may not be realistic, I have no clue about rustc internals, but I hope it is).
Failed attempt 1: Returning traits as a makeshift interface
This failed miserably because it's just not how the language works at all, and I got that now, but it's included for completeness.
Failed attempt 2: Using newtypes to "hide" the real implementation
This would be an ok workaround, it's not perfect but it seems to be workable given the constraints of the language and isn't too crazy, however it fails because it is missing the proper implementations:
Failed attempt 3: Implementing a decorator newtype
This probably is workable unless I don't get how to work around the compiler errors that are left, but I assume it's not a dead end. The problem though is that it is extremely verbose and seriously painful to write all this boilerplate just to have a straight decorator wrapping the underlying struct.
Proposal
The ideal way would be to allow the newtype to derive traits, so that making a decorator is not a PITA anymore. As you see right now it fails because the derive can't find the right impl, but I think it should just create it on the fly instead of complaining. That way we get explicit "interface" definition by defining which traits are implemented on the newtype, and we can return that and avoid a BC fiasco when we need to change the underlying RNG (see #8349 for more info on that).
I'd be happy to try and help implement this feature because I strongly believe this is needed, but to be honest I have no clue where to even start so pointers would be nice if the consensus is that it is a good thing and that it is at all feasible :)
The text was updated successfully, but these errors were encountered: