Re: [rust-dev] Implementation of traits in Rust: could it be dynamic?
I see. Thanks for the links, Greg Morrisett's notes are a great survey of possible approaches to this problem. It is funny because I had also come to the conclusion that JIT was the neater solution, as long as JIT is available with the runtime... and you don't have to implement it -- I guess it's even more complex than doing runtime dictionary passing. Has there been experiments using LLVM's JIT to implement polymorphism in Rust? I'm not sure about the cost of JIT, though. Maybe it would not make sense in Rust. Well, at least there should still be the static monomorphization option. 2014-07-26 5:31 GMT+02:00 Patrick Walton pcwal...@mozilla.com: On 7/25/14 8:26 PM, Patrick Walton wrote: Uniform value representations work well too (as OCaml shows), but of course you'll pay a performance cost for that. Oh, note that Greg's notes are a little bit out of date when discussing the performance tradeoffs of uniform value representation. On 64 bit (and even on 32 bit) you can do NaN-boxed fatvals [1] (scroll down to Mozilla's New JavaScript Value Representation) which avoid having to box every floating point value. Patrick [1] http://evilpie.github.io/sayrer-fatval-backup/cache.aspx.htm ___ 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] Implementation of traits in Rust: could it be dynamic?
On 7/25/14 8:26 PM, Patrick Walton wrote: Uniform value representations work well too (as OCaml shows), but of course you'll pay a performance cost for that. Oh, note that Greg's notes are a little bit out of date when discussing the performance tradeoffs of uniform value representation. On 64 bit (and even on 32 bit) you can do NaN-boxed fatvals [1] (scroll down to Mozilla's New JavaScript Value Representation) which avoid having to box every floating point value. Patrick [1] http://evilpie.github.io/sayrer-fatval-backup/cache.aspx.htm ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation of traits in Rust: could it be dynamic?
Hi, Could you provide a link to Patrick's description of size/alignment-passing implementation? I'm interested in these things. Well, there could be a warning if the compiler switches to such an implementation. It's arguably still better than not compiling at all. However, I don't have enough experience with type classes to know whether such situations actually happen in the real world. But didn't Nawfel BGH give an example of that? I'm not an expert in embedded systems, but I know that in some embedded systems, especially when memory is scarce or when the instruction cache is small, code size does matter more than the number of instructions executed per function call. It would probably be useful to be able to use generic libraries but still tweak the amount of monomoprhization in order to control the size of the generated executable. I don't know if this is the case for Rust, but executable size is an endemic problem in C++ because of wild template instantiation. I can't pronounce myself about the suitability of features in the Rust language, but it may be worth noting that some convenient high-level features are already present in the language, like garbage collection. Also, even C compilers output code with dramatically varying efficiency depending on the chosen levels of optimization -- and sometimes small details can disable optimization opportunities. Cheers, LP. 2014-07-23 4:13 GMT+02:00 Cameron Zwarich zwar...@mozilla.com: Even if we could do a size/alignment-passing implementation like Patrick describes, would be it even be appropriate? It wouldn’t make sense for a systems language to transparently switch to a dramatically less efficient implementation mechanism without the programmer’s involvement. Is there any place where an unbounded number of dictionaries at runtime is actually appropriate for solving a real problem in Rust? Cameron On Jul 22, 2014, at 10:16 AM, Lionel Parreaux lionel.parre...@gmail.com wrote: Hi, So traits seem to be quite similar to Haskell's classes, being also used for parametric polymorphism. Now, Haskell classes are usually implemented using runtime dictionary passing. In general, code cannot be specialized for every function call, since there may be an unbounded number of instances generated for it, as is explained in this reddit answer: http://www.reddit.com/r/haskell/comments/1ar642/what_type_of_binding_does_haskell_use/c94o2ju Knowing that Rust implements traits using monomorphization of code (much like C++ templates), I was curious about how it handled such cases, and tried this: struct WT { f: T } trait Show { fn show(self) - int; } impl Show for int { fn show(self) - int { 666 } } implT:Show Show for WT { fn show(self) - int { self.f.show()+1 } } implT:Clone Clone for WT { fn clone(self) - WT { W{f:self.f.clone()} } } fn fooS:Show+Clone(s: S, n: int) { let w = W{f:s.clone()}; if n 0 { foo(w, n-1); } } fn main() { foo(W{f:42i},42); } It gave me an error: reached the recursion limit during monomorphization, which... well, that's a possible solution :) I'm not sure whether this is a big problem in practice, but I was wondering if it would be possible to switch to some runtime mechanism in cases like this. Maybe we could make a special version of every generic functions, that takes a dictionary at runtime and that would be able to handle types unknown at compile-time. We would switch to this version when monomorphization does not work. It could also allow dynamic linking of libraries with generic functions, or it could be a way to compile some programs (or some parts of programs) much faster. I was thinking about, for example, an IDE where generic function calls to types defined inside the files currently being edited use their dynamic version, so that recompile times can be virtually inexistent (like Java). On the other hand, the release build would of course monomorphize as much as possible to make the perf optimal. Now the question is: would this conform to the current semantic of monomorphization? Do special things happen during monomorphization that cannot be reproduced at runtime? This is the case in C++ (and one of the reasons why C++ templates are so bad). Is it the case in Rust, which should already have all the required info (type bounds) before monomorphization? I apologize if this has already been discussed. I could not find many satisfying answers by googling. Cheers, LP. ___ 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] Implementation of traits in Rust: could it be dynamic?
On 24/07/14 11:59 AM, Lionel Parreaux wrote: I can't pronounce myself about the suitability of features in the Rust language, but it may be worth noting that some convenient high-level features are already present in the language, like garbage collection. There isn't an implementation of garbage collection. signature.asc Description: OpenPGP digital signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Implementation of traits in Rust: could it be dynamic?
Hi, So traits seem to be quite similar to Haskell's classes, being also used for parametric polymorphism. Now, Haskell classes are usually implemented using runtime dictionary passing. In general, code cannot be specialized for every function call, since there may be an unbounded number of instances generated for it, as is explained in this reddit answer: http://www.reddit.com/r/haskell/comments/1ar642/what_type_of_binding_does_haskell_use/c94o2ju Knowing that Rust implements traits using monomorphization of code (much like C++ templates), I was curious about how it handled such cases, and tried this: struct WT { f: T } trait Show { fn show(self) - int; } impl Show for int { fn show(self) - int { 666 } } implT:Show Show for WT { fn show(self) - int { self.f.show()+1 } } implT:Clone Clone for WT { fn clone(self) - WT { W{f:self.f.clone()} } } fn fooS:Show+Clone(s: S, n: int) { let w = W{f:s.clone()}; if n 0 { foo(w, n-1); } } fn main() { foo(W{f:42i},42); } It gave me an error: reached the recursion limit during monomorphization, which... well, that's a possible solution :) I'm not sure whether this is a big problem in practice, but I was wondering if it would be possible to switch to some runtime mechanism in cases like this. Maybe we could make a special version of every generic functions, that takes a dictionary at runtime and that would be able to handle types unknown at compile-time. We would switch to this version when monomorphization does not work. It could also allow dynamic linking of libraries with generic functions, or it could be a way to compile some programs (or some parts of programs) much faster. I was thinking about, for example, an IDE where generic function calls to types defined inside the files currently being edited use their dynamic version, so that recompile times can be virtually inexistent (like Java). On the other hand, the release build would of course monomorphize as much as possible to make the perf optimal. Now the question is: would this conform to the current semantic of monomorphization? Do special things happen during monomorphization that cannot be reproduced at runtime? This is the case in C++ (and one of the reasons why C++ templates are so bad). Is it the case in Rust, which should already have all the required info (type bounds) before monomorphization? I apologize if this has already been discussed. I could not find many satisfying answers by googling. Cheers, LP. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation of traits in Rust: could it be dynamic?
You can avoid monomorphization by using trait objects, which erase the precise implementing type through a vtable + pointer. http://doc.rust-lang.org/tutorial.html#trait-objects-and-dynamic-method-dispatch has some documentation. On Tue, Jul 22, 2014 at 10:16 AM, Lionel Parreaux lionel.parre...@gmail.com wrote: Hi, So traits seem to be quite similar to Haskell's classes, being also used for parametric polymorphism. Now, Haskell classes are usually implemented using runtime dictionary passing. In general, code cannot be specialized for every function call, since there may be an unbounded number of instances generated for it, as is explained in this reddit answer: http://www.reddit.com/r/haskell/comments/1ar642/what_type_of_binding_does_haskell_use/c94o2ju Knowing that Rust implements traits using monomorphization of code (much like C++ templates), I was curious about how it handled such cases, and tried this: struct WT { f: T } trait Show { fn show(self) - int; } impl Show for int { fn show(self) - int { 666 } } implT:Show Show for WT { fn show(self) - int { self.f.show()+1 } } implT:Clone Clone for WT { fn clone(self) - WT { W{f:self.f.clone()} } } fn fooS:Show+Clone(s: S, n: int) { let w = W{f:s.clone()}; if n 0 { foo(w, n-1); } } fn main() { foo(W{f:42i},42); } It gave me an error: reached the recursion limit during monomorphization, which... well, that's a possible solution :) I'm not sure whether this is a big problem in practice, but I was wondering if it would be possible to switch to some runtime mechanism in cases like this. Maybe we could make a special version of every generic functions, that takes a dictionary at runtime and that would be able to handle types unknown at compile-time. We would switch to this version when monomorphization does not work. It could also allow dynamic linking of libraries with generic functions, or it could be a way to compile some programs (or some parts of programs) much faster. I was thinking about, for example, an IDE where generic function calls to types defined inside the files currently being edited use their dynamic version, so that recompile times can be virtually inexistent (like Java). On the other hand, the release build would of course monomorphize as much as possible to make the perf optimal. Now the question is: would this conform to the current semantic of monomorphization? Do special things happen during monomorphization that cannot be reproduced at runtime? This is the case in C++ (and one of the reasons why C++ templates are so bad). Is it the case in Rust, which should already have all the required info (type bounds) before monomorphization? I apologize if this has already been discussed. I could not find many satisfying answers by googling. Cheers, LP. ___ 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] Implementation of traits in Rust: could it be dynamic?
this remindes me of the issue i got when trying to implement finger trees in Rust so long ago https://github.com/rust-lang/rust/issues/8613 I suggested to let add a way to specify (in the code) how match functions do we want to generate and failing at runtime when the limit is reached. This made sense in my situation. 2014-07-22 18:23 UTC+01:00, Corey Richardson co...@octayn.net: You can avoid monomorphization by using trait objects, which erase the precise implementing type through a vtable + pointer. http://doc.rust-lang.org/tutorial.html#trait-objects-and-dynamic-method-dispatch has some documentation. On Tue, Jul 22, 2014 at 10:16 AM, Lionel Parreaux lionel.parre...@gmail.com wrote: Hi, So traits seem to be quite similar to Haskell's classes, being also used for parametric polymorphism. Now, Haskell classes are usually implemented using runtime dictionary passing. In general, code cannot be specialized for every function call, since there may be an unbounded number of instances generated for it, as is explained in this reddit answer: http://www.reddit.com/r/haskell/comments/1ar642/what_type_of_binding_does_haskell_use/c94o2ju Knowing that Rust implements traits using monomorphization of code (much like C++ templates), I was curious about how it handled such cases, and tried this: struct WT { f: T } trait Show { fn show(self) - int; } impl Show for int { fn show(self) - int { 666 } } implT:Show Show for WT { fn show(self) - int { self.f.show()+1 } } implT:Clone Clone for WT { fn clone(self) - WT { W{f:self.f.clone()} } } fn fooS:Show+Clone(s: S, n: int) { let w = W{f:s.clone()}; if n 0 { foo(w, n-1); } } fn main() { foo(W{f:42i},42); } It gave me an error: reached the recursion limit during monomorphization, which... well, that's a possible solution :) I'm not sure whether this is a big problem in practice, but I was wondering if it would be possible to switch to some runtime mechanism in cases like this. Maybe we could make a special version of every generic functions, that takes a dictionary at runtime and that would be able to handle types unknown at compile-time. We would switch to this version when monomorphization does not work. It could also allow dynamic linking of libraries with generic functions, or it could be a way to compile some programs (or some parts of programs) much faster. I was thinking about, for example, an IDE where generic function calls to types defined inside the files currently being edited use their dynamic version, so that recompile times can be virtually inexistent (like Java). On the other hand, the release build would of course monomorphize as much as possible to make the perf optimal. Now the question is: would this conform to the current semantic of monomorphization? Do special things happen during monomorphization that cannot be reproduced at runtime? This is the case in C++ (and one of the reasons why C++ templates are so bad). Is it the case in Rust, which should already have all the required info (type bounds) before monomorphization? I apologize if this has already been discussed. I could not find many satisfying answers by googling. Cheers, LP. ___ 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 ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation of traits in Rust: could it be dynamic?
On 7/22/14 10:16 AM, Lionel Parreaux wrote: I'm not sure whether this is a big problem in practice, but I was wondering if it would be possible to switch to some runtime mechanism in cases like this. Maybe we could make a special version of every generic functions, that takes a dictionary at runtime and that would be able to handle types unknown at compile-time. We would switch to this version when monomorphization does not work. It could also allow dynamic linking of libraries with generic functions, or it could be a way to compile some programs (or some parts of programs) much faster. The hard part about doing that is not the dictionary passing. The hard part is that generic types may have unknown size or alignment. In Haskell this is not a problem because the language is garbage-collected and lazy so values have a uniform representation. But in Rust this is not true. Old Rust used to try to use runtime dictionary passing, where the dictionary contained size and alignment information, and all size/alignment info was computed at runtime for generics. I cannot overstate how *fiendishly* complex this was. We never got all the bugs out. In many cases, the amount of runtime code generated to compute size and alignment outweighed the cost of just monomorphizing. I strongly feel that the current system, where you can use generic type parameters to get monomorphization or trait objects to get dictionary passing, is the sweet spot. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev