Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
Cool. I was afraid that it will be harder for the compiler to optimize away the enum, but it seems to be doing fine. (If it does turn out that it's harder for the compiler, I don't see a real problem with the approach I suggested, as a runtime failure can only be caused by a bug in the code generator, not by user code) On Thu, Jun 12, 2014 at 2:13 AM, Kevin Cantu wrote: > Matthew Monrocq suggests this improvement, which looks even cleaner to > use, although slightly more complicated to implement generation of: > > > On Wed, Jun 11, 2014 at 11:38 AM, Matthieu Monrocq < > matthieu.monr...@gmail.com> wrote: > >> [snip] >> >> I do like the idea of the trait, however I would rather do away with all >> the `get_aa`: why not directly wrap the parameters ? >> >> enum AaBbEnum { >> Aa(int, f64), >> Bb(f64), >> } >> trait AaBb { >> fn get(&self) -> AaBbEnum; >> >> } >> >> impl AaBb for (int, f64) { >> fn get(&self) -> AaBbEnum { match *self { (i, f) => Aa(i, f), } } >> } >> >> impl AaBb for (f64) { >> fn get(&self) -> AaBbEnum { Bb(*self) } >> >> } >> >> fn overloaded(x: T) { >> match x.get() { >> Aa(i, f) => println!("got Aa: {}", (i, f)), >> Bb(f) => println!("got Bb: {}", f), >> >> } >> } >> >> #[main] >> fn main() { >> overloaded((5i, 7.3243)); // prints: got Aa: (5, 7.3243) >> overloaded((3.5)); // prints: got Bb: 3.5 >> } >> >> Now, there is no runtime failure => you cannot accidentally match on `Bb` >> and requests `get_aa`! >> > > > > Kevin > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Is there a Parsec equivalent in Rust?
Hi, Haskell's Parsec is really a good tool to parse languages. Scala also has the equivalent. What about Rust? -- Akira Hayakawa ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
Matthew Monrocq suggests this improvement, which looks even cleaner to use, although slightly more complicated to implement generation of: On Wed, Jun 11, 2014 at 11:38 AM, Matthieu Monrocq < matthieu.monr...@gmail.com> wrote: > [snip] > > I do like the idea of the trait, however I would rather do away with all > the `get_aa`: why not directly wrap the parameters ? > > enum AaBbEnum { > Aa(int, f64), > Bb(f64), > } > trait AaBb { > fn get(&self) -> AaBbEnum; > > } > > impl AaBb for (int, f64) { > fn get(&self) -> AaBbEnum { match *self { (i, f) => Aa(i, f), } } > } > > impl AaBb for (f64) { > fn get(&self) -> AaBbEnum { Bb(*self) } > > } > > fn overloaded(x: T) { > match x.get() { > Aa(i, f) => println!("got Aa: {}", (i, f)), > Bb(f) => println!("got Bb: {}", f), > > } > } > > #[main] > fn main() { > overloaded((5i, 7.3243)); // prints: got Aa: (5, 7.3243) > overloaded((3.5)); // prints: got Bb: 3.5 > } > > Now, there is no runtime failure => you cannot accidentally match on `Bb` > and requests `get_aa`! > Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
On 2014-06-11, at 21:47, Tommi wrote: > I said `Mul` and similar should do it, i.e. functions that take a variable > and return a variable of that same type. Although, a larger issue of genericity is that multiplication doesn't always return the same type as one of its arguments. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
Thanks! I looked at http://qt-project.org/doc/qt-4.8/qwidget.html, which has several overloaded functions, and didn't find overloaded functions with different return types. If there are, there are probably rare - I really think that overloaded functions with different return types are an abomination. On Wed, Jun 11, 2014 at 8:23 PM, Kevin Cantu wrote: > Noam, that's awesome. It even works for tuples like so (I didn't think it > would): > > ``` > enum AaBbEnum { > Aa, > Bb, > } > > trait AaBb { > fn get_type(&self) -> AaBbEnum; > fn get_aa(self) -> (int, f64) { fail!(); } > fn get_bb(self) -> (f64) { fail!(); } > } > > impl AaBb for (int, f64) { > fn get_type(&self) -> AaBbEnum { Aa } > fn get_aa(self) -> (int, f64) { self } > } > > impl AaBb for (f64) { > fn get_type(&self) -> AaBbEnum { Bb } > fn get_bb(self) -> (f64) { self } > } > > #[cfg(not(test))] > fn overloaded(x: T) { > match x.get_type() { > Aa => println!("got Aa: {}", x.get_aa()), > Bb => println!("got Bb: {}", x.get_bb()), > } > } > > fn overloaded_format(x: T) -> String { > match x.get_type() { > Aa => format!("got Aa: {}", x.get_aa()), > Bb => format!("got Bb: {}", x.get_bb()), > } > } > > #[cfg(not(test))] > #[main] > fn main() { > overloaded((5i, 7.3243)); // prints: got Aa: (5, 7.3243) > overloaded((3.5)); // prints: got Bb: 3.5 > } > > #[test] > fn overloaded_with_same_return_works() { > // now with a shared return > let x: String = overloaded_format((5i, 7.3243)); > let y: String = overloaded_format((3.5)); > assert_eq!(x, "got Aa: (5, 7.3243)".to_string()); > assert_eq!(y, "got Bb: 3.5".to_string()); > } > ``` > > I imagine if the functions being overloaded have different return types, > this gets uglier to use, but this is pretty good! > > > Kevin > > > On Wed, Jun 11, 2014 at 4:35 AM, Noam Yorav-Raphael > wrote: > >> You can achieve overloading which is equivalent to C++ by defining a >> trait for all the types a specific argument can get: >> >> ``` >> enum IntOrFloatEnum { >> Int, >> F64, >> } >> >> trait IntOrFloat { >> fn get_type(&self) -> IntOrFloatEnum; >> fn get_int(self) -> int { fail!(); } >> fn get_f64(self) -> f64 { fail!(); } >> } >> >> impl IntOrFloat for int { >> fn get_type(&self) -> IntOrFloatEnum { Int } >> fn get_int(self) -> int { self } >> } >> >> impl IntOrFloat for f64 { >> fn get_type(&self) -> IntOrFloatEnum { F64 } >> fn get_f64(self) -> f64 { self } >> } >> >> fn overloaded(x: T) { >> match x.get_type() { >> Int => println!("got int: {}", x.get_int()), >> F64 => println!("got f64: {}", x.get_f64()), >> } >> } >> >> fn main() { >> overloaded(5i); // prints: got int: 5 >> overloaded(3.5); // prints: got f64: 3.5 >> } >> ``` >> >> This is equivalent to having to functions, overloaded(int) and >> overloaded(f64). From what I see, the compiler even optimizes away the >> logic, so the generated code is actually equivalent to this: >> >> ``` >> fn overloaded_int(x: int) { println!("got int: {}", x); } >> fn overloaded_f64(x: f64) { println!("got f64: {}", x); } >> fn main() { >> overloaded_int(5i); >> overloaded_f64(3.5); >> } >> ``` >> >> (I actually think that if Rust gains one day some support for >> overloading, it should be syntactic sugar for the above, which will allow >> you to define a function whose argument can be of multiple types. I don't >> like the C++ style of defining several different functions with the same >> name and letting the compiler choose which function should actually be >> called). >> >> Using this method you can solve both the problem of overloading and >> default arguments. For every possible number of arguments that C++ would >> allow, define a function funcN(arg0: T0, arg1: T1, ..., >> argN-1: TN-1). The function would check the actual types of the arguments >> and call the right C++ function, filling default arguments on the way. So >> the only difference between C++ and Rust code would be that you'd have to >> add the number of arguments to the method name. >> >> It would probably not be easy to generate the required code, but I think >> it would solve the problem perfectly. >> >> Cheers, >> Noam >> >> >> On Thu, May 22, 2014 at 11:27 PM, Alexander Tsvyashchenko >> wrote: >> >>> Hi All, >>> >>> Recently I was playing with bindings generator from C++ to Rust. I >>> managed to make things work for Qt5 wrapping, but stumbled into multiple >>> issues along the way. >>> >>> I tried to summarize my "pain points" in the following blog post: >>> http://endl.ch/content/cxx2rust-pains-wrapping-c-rust-example-qt5 >>> >>> I hope that others might benefit from my experience and that some of >>> these "pain points" can be fixed in Rust. >>> >>> I'll try to do my best in answering questions / acting on feedback, if >>> any, but I have very limited amount of free time right now so sorry in >>> advance
Re: [rust-dev] Building rustc @ 1GB RAM?
Output of "make check" for those of you who are interested. failures: [run-pass] run-pass/intrinsic-alignment.rs [run-pass] run-pass/rec-align-u64.rs [run-pass] run-pass/stat.rs test result: FAILED. 1469 passed; 3 failed; 32 ignored; 0 measured On Wed, Jun 11, 2014 at 12:15 PM, Ian Daniher wrote: > I have a dual core arm machine with 1GB of RAM keeping up with rust master > - every 8hrs, it updates git, runs "make install," and 8hrs later I have an > up-to-date rustc w/ libs. > > No swap, no compression kmods, just a build of rustc & libs that passes > (almost) all tests. > > root@debian-0d0dd:/mnt/armscratch/node-v0.10.28# free -h; uname -a; cat >> /proc/cpuinfo; rustc -v >> total used free sharedbuffers cached >> Mem: 1.0G 982M24M 0B 155M 750M >> -/+ buffers/cache:76M 930M >> Swap: 0B 0B 0B >> Linux debian-0d0dd 3.4.79-r0-s20-rm2+ #54 SMP Tue Feb 18 01:09:07 YEKT >> 2014 armv7l GNU/Linux >> Processor : ARMv7 Processor rev 4 (v7l) >> processor : 0 >> BogoMIPS: 1819.52 >> processor : 1 >> BogoMIPS: 1819.52 >> Features: swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls >> vfpv4 idiva idivt >> CPU implementer : 0x41 >> CPU architecture: 7 >> CPU variant : 0x0 >> CPU part: 0xc07 >> CPU revision: 4 >> Hardware: sun7i >> Revision: >> Serial : >> rustc 0.11.0-pre (f92a8fa 2014-06-10 18:07:07 -0700) >> host: arm-unknown-linux-gnueabihf > > > > > On Tue, Jun 10, 2014 at 5:19 PM, Igor Bukanov wrote: > >> I tried building rust in a VM with 1GB of memory and it seems only >> zswap works. With zram-only solution without any real swap I was not >> able to compile rust at all. The compiler generated out-of-memory >> exception with zram configured to take 30-70% of memory. With zswap >> enabled, zswap.max_pool_percent=70 and the real swap of 2.5 GB the >> compilation time for the latest tip was about 2 hours. This is on Mac >> Air and Linux inside VirtualBox. >> >> On 5 June 2014 20:46, Ian Daniher wrote: >> > zram is a great suggestion, thanks! I'll give it a shot. >> > — >> > From My Tiny Glowing Screen >> > >> > >> > On Thu, Jun 5, 2014 at 2:25 PM, Igor Bukanov wrote: >> >> >> >> Have you considered to use zram? Typically the compression for >> >> compiler memory is over a factor of 3 so that can be an option as the >> >> performance degradation under swapping could be tolerable. A similar >> >> option is to enable zswap, but as the max compression with it is >> >> effectively limited by factor of 2, it may not be enough to avoid >> >> swapping. >> >> >> >> On 5 June 2014 20:13, Ian Daniher wrote: >> >> > 1GB is close-ish to the 1.4GB last reported (over a month ago!) by >> >> > http://huonw.github.io/isrustfastyet/mem/. >> >> > >> >> > Are there any workarounds to push the compilation memory down? I'm >> also >> >> > exploring distcc, but IRFY has a bit of semantic ambiguity as to >> whether >> >> > or >> >> > not it's 1.4GB simultaneous or net total. >> >> > >> >> > Thanks! >> >> > -- >> >> > Ian >> >> > >> >> > ___ >> >> > Rust-dev mailing list >> >> > Rust-dev@mozilla.org >> >> > https://mail.mozilla.org/listinfo/rust-dev >> >> > >> > >> > >> > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
Keeping in mind that the `self` value here can be a reference. Ie, implementing the traits also for references to a type. On Wed, Jun 11, 2014 at 11:47 AM, Tommi wrote: > On 2014-06-11, at 21:33, Daniel Micay wrote: > > Cloning big integers, rationals based on big integers or arbitrary > precision floating point values for every single operation has a high > cost. > > > I didn't say that all functions should start taking their arguments by > value. I said `Mul` and similar should do it, i.e. functions that take a > variable and return a variable of that same type. Instead of passing by > reference and making a clone of the passed reference inside those functions, > you force the caller to make the clone and mutate the passed argument in > place. This enables the C++ like rvalue reference optimization for functions > like multiplication. > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- http://octayn.net/ ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
On 2014-06-11, at 21:33, Daniel Micay wrote: > Cloning big integers, rationals based on big integers or arbitrary > precision floating point values for every single operation has a high > cost. I didn't say that all functions should start taking their arguments by value. I said `Mul` and similar should do it, i.e. functions that take a variable and return a variable of that same type. Instead of passing by reference and making a clone of the passed reference inside those functions, you force the caller to make the clone and mutate the passed argument in place. This enables the C++ like rvalue reference optimization for functions like multiplication. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
On 11/06/14 01:54 PM, Tommi wrote: > If the `Mul` trait and similar were changed to take `self` by value, perhaps > the following kind of language design would make more sense: > > If a variable of a type that has a destructor is passed to a function by > value (moved), and the variable is used after the function call, the variable > would be implicitly cloned before passing it to the function. Cloning big integers, rationals based on big integers or arbitrary precision floating point values for every single operation has a high cost. One of Rust's strength's is that it doesn't have implicit cloning as C++ does due to copy constructors. signature.asc Description: OpenPGP digital signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
If the `Mul` trait and similar were changed to take `self` by value, perhaps the following kind of language design would make more sense: If a variable of a type that has a destructor is passed to a function by value (moved), and the variable is used after the function call, the variable would be implicitly cloned before passing it to the function. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
Noam, that's awesome. It even works for tuples like so (I didn't think it would): ``` enum AaBbEnum { Aa, Bb, } trait AaBb { fn get_type(&self) -> AaBbEnum; fn get_aa(self) -> (int, f64) { fail!(); } fn get_bb(self) -> (f64) { fail!(); } } impl AaBb for (int, f64) { fn get_type(&self) -> AaBbEnum { Aa } fn get_aa(self) -> (int, f64) { self } } impl AaBb for (f64) { fn get_type(&self) -> AaBbEnum { Bb } fn get_bb(self) -> (f64) { self } } #[cfg(not(test))] fn overloaded(x: T) { match x.get_type() { Aa => println!("got Aa: {}", x.get_aa()), Bb => println!("got Bb: {}", x.get_bb()), } } fn overloaded_format(x: T) -> String { match x.get_type() { Aa => format!("got Aa: {}", x.get_aa()), Bb => format!("got Bb: {}", x.get_bb()), } } #[cfg(not(test))] #[main] fn main() { overloaded((5i, 7.3243)); // prints: got Aa: (5, 7.3243) overloaded((3.5)); // prints: got Bb: 3.5 } #[test] fn overloaded_with_same_return_works() { // now with a shared return let x: String = overloaded_format((5i, 7.3243)); let y: String = overloaded_format((3.5)); assert_eq!(x, "got Aa: (5, 7.3243)".to_string()); assert_eq!(y, "got Bb: 3.5".to_string()); } ``` I imagine if the functions being overloaded have different return types, this gets uglier to use, but this is pretty good! Kevin On Wed, Jun 11, 2014 at 4:35 AM, Noam Yorav-Raphael wrote: > You can achieve overloading which is equivalent to C++ by defining a trait > for all the types a specific argument can get: > > ``` > enum IntOrFloatEnum { > Int, > F64, > } > > trait IntOrFloat { > fn get_type(&self) -> IntOrFloatEnum; > fn get_int(self) -> int { fail!(); } > fn get_f64(self) -> f64 { fail!(); } > } > > impl IntOrFloat for int { > fn get_type(&self) -> IntOrFloatEnum { Int } > fn get_int(self) -> int { self } > } > > impl IntOrFloat for f64 { > fn get_type(&self) -> IntOrFloatEnum { F64 } > fn get_f64(self) -> f64 { self } > } > > fn overloaded(x: T) { > match x.get_type() { > Int => println!("got int: {}", x.get_int()), > F64 => println!("got f64: {}", x.get_f64()), > } > } > > fn main() { > overloaded(5i); // prints: got int: 5 > overloaded(3.5); // prints: got f64: 3.5 > } > ``` > > This is equivalent to having to functions, overloaded(int) and > overloaded(f64). From what I see, the compiler even optimizes away the > logic, so the generated code is actually equivalent to this: > > ``` > fn overloaded_int(x: int) { println!("got int: {}", x); } > fn overloaded_f64(x: f64) { println!("got f64: {}", x); } > fn main() { > overloaded_int(5i); > overloaded_f64(3.5); > } > ``` > > (I actually think that if Rust gains one day some support for overloading, > it should be syntactic sugar for the above, which will allow you to define > a function whose argument can be of multiple types. I don't like the C++ > style of defining several different functions with the same name and > letting the compiler choose which function should actually be called). > > Using this method you can solve both the problem of overloading and > default arguments. For every possible number of arguments that C++ would > allow, define a function funcN(arg0: T0, arg1: T1, ..., > argN-1: TN-1). The function would check the actual types of the arguments > and call the right C++ function, filling default arguments on the way. So > the only difference between C++ and Rust code would be that you'd have to > add the number of arguments to the method name. > > It would probably not be easy to generate the required code, but I think > it would solve the problem perfectly. > > Cheers, > Noam > > > On Thu, May 22, 2014 at 11:27 PM, Alexander Tsvyashchenko > wrote: > >> Hi All, >> >> Recently I was playing with bindings generator from C++ to Rust. I >> managed to make things work for Qt5 wrapping, but stumbled into multiple >> issues along the way. >> >> I tried to summarize my "pain points" in the following blog post: >> http://endl.ch/content/cxx2rust-pains-wrapping-c-rust-example-qt5 >> >> I hope that others might benefit from my experience and that some of >> these "pain points" can be fixed in Rust. >> >> I'll try to do my best in answering questions / acting on feedback, if >> any, but I have very limited amount of free time right now so sorry in >> advance if answers take some time. >> >> Thanks! >> >> -- >> Good luck! Alexander >> >> >> ___ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Building rustc @ 1GB RAM?
I have a dual core arm machine with 1GB of RAM keeping up with rust master - every 8hrs, it updates git, runs "make install," and 8hrs later I have an up-to-date rustc w/ libs. No swap, no compression kmods, just a build of rustc & libs that passes (almost) all tests. root@debian-0d0dd:/mnt/armscratch/node-v0.10.28# free -h; uname -a; cat > /proc/cpuinfo; rustc -v > total used free sharedbuffers cached > Mem: 1.0G 982M24M 0B 155M 750M > -/+ buffers/cache:76M 930M > Swap: 0B 0B 0B > Linux debian-0d0dd 3.4.79-r0-s20-rm2+ #54 SMP Tue Feb 18 01:09:07 YEKT > 2014 armv7l GNU/Linux > Processor : ARMv7 Processor rev 4 (v7l) > processor : 0 > BogoMIPS: 1819.52 > processor : 1 > BogoMIPS: 1819.52 > Features: swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls > vfpv4 idiva idivt > CPU implementer : 0x41 > CPU architecture: 7 > CPU variant : 0x0 > CPU part: 0xc07 > CPU revision: 4 > Hardware: sun7i > Revision: > Serial : > rustc 0.11.0-pre (f92a8fa 2014-06-10 18:07:07 -0700) > host: arm-unknown-linux-gnueabihf On Tue, Jun 10, 2014 at 5:19 PM, Igor Bukanov wrote: > I tried building rust in a VM with 1GB of memory and it seems only > zswap works. With zram-only solution without any real swap I was not > able to compile rust at all. The compiler generated out-of-memory > exception with zram configured to take 30-70% of memory. With zswap > enabled, zswap.max_pool_percent=70 and the real swap of 2.5 GB the > compilation time for the latest tip was about 2 hours. This is on Mac > Air and Linux inside VirtualBox. > > On 5 June 2014 20:46, Ian Daniher wrote: > > zram is a great suggestion, thanks! I'll give it a shot. > > — > > From My Tiny Glowing Screen > > > > > > On Thu, Jun 5, 2014 at 2:25 PM, Igor Bukanov wrote: > >> > >> Have you considered to use zram? Typically the compression for > >> compiler memory is over a factor of 3 so that can be an option as the > >> performance degradation under swapping could be tolerable. A similar > >> option is to enable zswap, but as the max compression with it is > >> effectively limited by factor of 2, it may not be enough to avoid > >> swapping. > >> > >> On 5 June 2014 20:13, Ian Daniher wrote: > >> > 1GB is close-ish to the 1.4GB last reported (over a month ago!) by > >> > http://huonw.github.io/isrustfastyet/mem/. > >> > > >> > Are there any workarounds to push the compilation memory down? I'm > also > >> > exploring distcc, but IRFY has a bit of semantic ambiguity as to > whether > >> > or > >> > not it's 1.4GB simultaneous or net total. > >> > > >> > Thanks! > >> > -- > >> > Ian > >> > > >> > ___ > >> > Rust-dev mailing list > >> > Rust-dev@mozilla.org > >> > https://mail.mozilla.org/listinfo/rust-dev > >> > > > > > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
On 06/11/2014 10:10 AM, Sebastian Gesemann wrote: On Wed, Jun 11, 2014 at 3:27 PM, SiegeLord wrote: [...] Along the same lines, it is not immediately obvious to me how to extend this lazy evaluation idea to something like num::BigInt. So far, it seems like lazy evaluation will force dynamic dispatch in that case which is a big shame (i.e. you'd store the operations in one array, arguments in another and then play them back at the assignment time). I havn't tried something like expression templates in Rust yet. How did you come to the conclusion that it would require dynamic dispatch? It's just the first idea I had with how this could work, but you're right, I can envision a way to do this without using dynamic dispatch. It'd look something like something like this: https://gist.github.com/SiegeLord/f1af81195df89ec04d10 . So, if nothing comes out of this discussion, at least you'd be able to do that. Note that the API is uglier, since you need to call 'eval' explicitly. Additionally, you need to manually borrow 'm' because you can't specify a lifetime of the &self argument in mul (another problem with by-ref-self methods). -SL ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
On 11/06/14 23:27, SiegeLord wrote: Aside from somewhat more complicated impl's, are there any downsides to never using anything but by value 'self' in traits? Currently trait objects do not support `self` methods (#10672), and, generally, the interactions with trait objects seem peculiar, e.g. if you've implemented Trait for &Type, then you would want to be coercing a `&Type` to a `&Trait`, *not* a `&(&Type)` as is currently required. However, I don't think these concerns affect the operator overloading traits. https://github.com/mozilla/rust/issues/10672 Huon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] &self/&mut self in traits considered harmful(?)
On Wed, Jun 11, 2014 at 3:27 PM, SiegeLord wrote: > [...] Along the same lines, it is not immediately obvious > to me how to extend this lazy evaluation idea to something like num::BigInt. > So far, it seems like lazy evaluation will force dynamic dispatch in that > case which is a big shame (i.e. you'd store the operations in one array, > arguments in another and then play them back at the assignment time). I havn't tried something like expression templates in Rust yet. How did you come to the conclusion that it would require dynamic dispatch? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Porting a small DSP test from C++ to Rust: Comments and performance observations
So I feel a little sheepish now, as I tried the C++ code again with LTO turned off, and it’s now slightly faster than the Rust version. I guess it’s a performance regression that gets triggered by LTO in this specific case. Here are the results I get now: clang PerformanceTest.cpp dsp.cpp -std=c++11 -ffast-math -O3 -o PerformanceTest Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn) Target: x86_64-apple-darwin13.2.0 Thread model: posix Iterations: 955 C results: 100,043,846 shorts per second. Rust is still very competitive with 93M shorts/second, and I would hope to see the gap narrowed or eliminated as the compiler & language continue to be improved. The code is also now available here if anyone is interested: https://gist.github.com/learnopengles/004ff4eee75057ca006c___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] &self/&mut self in traits considered harmful(?)
First, let me begin with a small discussion about C++ rvalue references. As some of you know, they were introduced to C++ in part to solve problems like this: Matrix m; m.data = {1.0, 2.0, 3.0}; Matrix m2 = m * 2.0 * 5.0 * 10.0; Before C++11, most implementations the multiplications on the third line would create two (unnecessary) temporary copies of the Matrix, causing widespread inefficiency if Matrix was large. By using rvalue references (see the implementation in this gist: https://gist.github.com/SiegeLord/85ced65ab220a3fdc1fc we can reduce the number of copies to one. What the C++ does is that the first multiplication (* 2.0) creates a copy of the matrix, and the remaining multiplications move that copy around. If you look at the implementation, you'll note how complicated the C++ move semantics are compared to Rust's (you have to use std::move everywhere, define move-constructors and move-assignment with easy-to-get-wrong implementations etc.). Since Rust has simpler move semantics, can we do the same thing in Rust? It turns out we cannot, because the operator overloading in Rust is done by overloading a trait with a method that takes self by reference: pub trait Mul { fn mul(&self, rhs: &RHS) -> Result; } This means that the crucial step of moving out from the temporary cannot be done without complicated alternatives (explained at the end of this email). If we define an a multiplication trait that takes self by value, however then this is possible and indeed relatively trivial (see implementation here: https://gist.github.com/SiegeLord/11456760237781442cfe ). This code will act just like the C++ did: it will copy during the first move_mul call, and then move the temporary around: let m = Matrix{ data: vec![1.0f32, 2.0, 3.0] }; let m2 = (&m).move_mul(2.0).move_mul(5.0).move_mul(10.0); So there's nothing in Rust move semantics which prevents this useful pattern, and it'd be possible to do that with syntax sugar if the operator overload traits did not sabotage it. Pretty much all the existing users (e.g. num::BigInt and sebcrozet's nalgebra) of operator overloading traits take the inefficient route of creating a temporary copy for each operation (see https://github.com/mozilla/rust/blob/master/src/libnum/bigint.rs#L283 and https://github.com/sebcrozet/nalgebra/blob/master/src/structs/dmat.rs#L593 ). If the operator overloading traits do not allow you to create efficient implementations of BigNums and linear algebra operations, the two use cases why you'd even *have* operator overloading as a language feature, why even have that feature? I think this goes beyond just operator overloading, however, as these kinds of situations may arise in many other traits. By defining trait methods as taking &self and &mut self, we are preventing these useful optimizations. Aside from somewhat more complicated impl's, are there any downsides to never using anything but by value 'self' in traits? If not, then I think that's what they should be using to allow people to create efficient APIs. In fact, this probably should extend to every member generic function argument: you should never force the user to tie their hands by using a reference. Rust has amazing move semantics, I just don't see what is gained by abandoning them whenever you use most traits. Now, I did say there are complicated alternatives to this. First, you actually *can* move out through a borrowed pointer using RefCell>. You can see what this looks like here: https://gist.github.com/SiegeLord/e09c32b8cf2df72b2422 . I don't know how efficient that is, but it is certainly more fragile. With my by-value MoveMul implementation, the moves are checked by the compiler... in this case, they are not. It's easy to end up with a moved-out, dangling Matrix. This is what essentially has to be done, however, if you want to preserve the general semantic of the code. Alternatively, you can use lazy evaluation/expression templates. This is the route I take in my linear algebra library. Essentially, each operation returns a struct (akin to what happens with many Iterator methods) that stores the arguments by reference. When it comes time to perform assignment, the chained operations are performed element-wise. There are no unnecessary copies and it optimizes well. The problem is that its a lot more complicated to implement and it pretty much forces you to use interior mutability (just Cell this time) if you don't want a crippled API. The latter bit introduces a whole slew of subtle bugs (in my opinion they are less common than the ones introduced by RefCell). Also, I don't think expression templates are the correct way to wrap, e.g., a LAPACK library. I.e. they only work well when you're implementing the math yourself which is not ideal for the more complicated algorithms. Along the same lines, it is not immediately obvious to me how to extend this lazy evaluation idea to something l
Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
You can achieve overloading which is equivalent to C++ by defining a trait for all the types a specific argument can get: ``` enum IntOrFloatEnum { Int, F64, } trait IntOrFloat { fn get_type(&self) -> IntOrFloatEnum; fn get_int(self) -> int { fail!(); } fn get_f64(self) -> f64 { fail!(); } } impl IntOrFloat for int { fn get_type(&self) -> IntOrFloatEnum { Int } fn get_int(self) -> int { self } } impl IntOrFloat for f64 { fn get_type(&self) -> IntOrFloatEnum { F64 } fn get_f64(self) -> f64 { self } } fn overloaded(x: T) { match x.get_type() { Int => println!("got int: {}", x.get_int()), F64 => println!("got f64: {}", x.get_f64()), } } fn main() { overloaded(5i); // prints: got int: 5 overloaded(3.5); // prints: got f64: 3.5 } ``` This is equivalent to having to functions, overloaded(int) and overloaded(f64). From what I see, the compiler even optimizes away the logic, so the generated code is actually equivalent to this: ``` fn overloaded_int(x: int) { println!("got int: {}", x); } fn overloaded_f64(x: f64) { println!("got f64: {}", x); } fn main() { overloaded_int(5i); overloaded_f64(3.5); } ``` (I actually think that if Rust gains one day some support for overloading, it should be syntactic sugar for the above, which will allow you to define a function whose argument can be of multiple types. I don't like the C++ style of defining several different functions with the same name and letting the compiler choose which function should actually be called). Using this method you can solve both the problem of overloading and default arguments. For every possible number of arguments that C++ would allow, define a function funcN(arg0: T0, arg1: T1, ..., argN-1: TN-1). The function would check the actual types of the arguments and call the right C++ function, filling default arguments on the way. So the only difference between C++ and Rust code would be that you'd have to add the number of arguments to the method name. It would probably not be easy to generate the required code, but I think it would solve the problem perfectly. Cheers, Noam On Thu, May 22, 2014 at 11:27 PM, Alexander Tsvyashchenko wrote: > Hi All, > > Recently I was playing with bindings generator from C++ to Rust. I managed > to make things work for Qt5 wrapping, but stumbled into multiple issues > along the way. > > I tried to summarize my "pain points" in the following blog post: > http://endl.ch/content/cxx2rust-pains-wrapping-c-rust-example-qt5 > > I hope that others might benefit from my experience and that some of these > "pain points" can be fixed in Rust. > > I'll try to do my best in answering questions / acting on feedback, if > any, but I have very limited amount of free time right now so sorry in > advance if answers take some time. > > Thanks! > > -- > Good luck! Alexander > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Porting a small DSP test from C++ to Rust: Comments and performance observations
Hi, Kevin! > * What would be the replacement for a struct-scoped static constant, so I > could put a static inside a struct instead of making it a global? It is not possible now. There are some suggestions on associated items, but I don’t think they are active. Currently Rust module system is used to control scopes of statics. > * Rust doesn't have prefix/postfix increment? Or, I just didn't find the > right syntax of using it? Yes, Rust doesn’t have it. You should use composite assignment: x += 1. It is not an expression, though. > * My biggest problem was figuring out how to use arrays. Originally, things > just weren't working and I think it's because I was inadvertently copying an > array instead of referring to the original. t just couldn't figure out how to > create a mutable alias to an array passed into a function by reference. Well, you have correctly figured out that it is done using slices :) > * I understand the reasoning behind explicit integer conversions, but > depending on what one is doing, it can add to a lot of explicit conversions, > and I also didn't figure out a way to do an unsigned for loop. Yes, explicit conversions may sometimes be too verbose. As for unsigned for loop, it is easy. Remember, Rust uses type inference to find out correct types of all local variables. `range()` function which creates range iterators is generic and looks like this: fn range(from: T, until: T) -> Range { … } (actual definition is different because T is not arbitrary but bounded with some traits) The `T` type parameter is determined automatically from the use site of the function. In your case it is deduced as `int` because of `length` variable (which is of `int` type). So you can just cast `length` to `uint`: for i in range(0, length as uint) { … } and `i` variable will be unsigned. BTW, why did you define `length` parameter as `int` at all? You can make it `uint` and you won’t need to do this cast. > * When creating / using arrays, there is sometimes duplication of the size > parameter. Is there a way to reduce that? I don’t think so. They are statically sized arrays, so they just need their size specified. When you don’t care about their size, you usually use slices anyway. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev