Re: [rust-dev] Virtual fn is a bad idea
I like the way this handles all sorts of trivial casts. There seems to be a downside in that inherited struct field access becomes very noisy. Perhaps it would be possible to unify this with an anonymous fields syntax to get the best of both worlds? On Wed, Mar 12, 2014 at 1:51 AM, Vadim Chugunov vadi...@gmail.com wrote: By the way, I didn't see any discussion of the HasPrefix/Coercible proposalhttps://github.com/mozilla/rust/issues/9912#issuecomment-36073562in the workweek minutes. Did anybody bring it up at all? Vadim On Tue, Mar 11, 2014 at 2:30 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: I can't help but feel that forcing the single inheritance of fast field access and inheritance of trait functions into one mechanism would be regrettable. Would https://github.com/mozilla/rust/issues/10491 address all the requirements? If not, why? On Tue, Mar 11, 2014 at 10:52 PM, Brian Anderson bander...@mozilla.comwrote: The downsides you list are all more or less applicable to this design, indeed. We are seeing real requirements in real code that indicates that the current abstraction facilities provided by Rust are efficient enough for certain demanding use cases (the DOM in particular). Here are the identified requirements: tree of types (single inheritance) downcasting thin pointers cheap field access easy upcasting ___ 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] Virtual fn is a bad idea
I can't help but feel that forcing the single inheritance of fast field access and inheritance of trait functions into one mechanism would be regrettable. Would https://github.com/mozilla/rust/issues/10491 address all the requirements? If not, why? On Tue, Mar 11, 2014 at 10:52 PM, Brian Anderson bander...@mozilla.comwrote: The downsides you list are all more or less applicable to this design, indeed. We are seeing real requirements in real code that indicates that the current abstraction facilities provided by Rust are efficient enough for certain demanding use cases (the DOM in particular). Here are the identified requirements: tree of types (single inheritance) downcasting thin pointers cheap field access easy upcasting ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Thoughts on the Rust Roadmap
Not to re-ignite the thread about this, but one way `proc`s aren't sufficient because they are send-able (that is, allocated on the heap). Rust lacks a call-once stack-allocated closure types, which are immensely useful for manipulating container elements, creating DSL-ish syntax, etc. That's separate from the `decltype` issue, though. On Tue, Dec 31, 2013 at 3:55 PM, Armin Ronacher armin.ronac...@active-4.com wrote: Hi, On 30/12/2013 17:29, Patrick Walton wrote: Is `proc` not sufficient? We could prioritize adding unboxed closures, but since they're backwards compatible as far as I know, I don't see a major need to add them before 1.0. Procs can be called once. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Thoughts on the Rust Roadmap
The point is that sometimes you really *don't* want the closure to be send-able, because you want it to access from the surrounding context both owned pointers (- be called-once) _and also_ borrowed pointers (- be stack-allocated). This is vital for some use cases and is impossible today (ok, possible by painfully wrapping a cell around each owned pointer and taking its value in the stack closure). On Tue, Dec 31, 2013 at 4:20 PM, Daniel Micay danielmi...@gmail.com wrote: On Tue, Dec 31, 2013 at 9:15 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Not to re-ignite the thread about this, but one way `proc`s aren't sufficient because they are send-able (that is, allocated on the heap). Rust lacks a call-once stack-allocated closure types, which are immensely useful for manipulating container elements, creating DSL-ish syntax, etc. That's separate from the `decltype` issue, though. Closures don't need to be heap-allocated to be `Send`. An unboxed closure with only `Send` captures would be `Send` itself too. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Thoughts on the Rust Roadmap
Great news... I'll admit I have no idea what unboxed closures are, exactly, google wasn't helpful finding out a post clearly describing them. The example in http://www.mail-archive.com/rust-dev@mozilla.org/msg07569.html shows passing a closure to a map, so it obviously isn't a call-once so it can't consume an owned pointer. E.g., if it was `|x| x + f(move-some-owned-pointer-from-the-context-to-be-consumed-by-f)`, then it wouldn't - and shouldn't - work. But writing something like my_container.modify_value_of_existing_key(key, |old| f(old, move-some-owned-pointer-from-context))` should work - I don't see how both closures can have the same type. On Tue, Dec 31, 2013 at 4:29 PM, Patrick Walton pcwal...@mozilla.comwrote: On 12/31/13 6:26 AM, Oren Ben-Kiki wrote: The point is that sometimes you really *don't* want the closure to be send-able, because you want it to access from the surrounding context both owned pointers (- be called-once) _and also_ borrowed pointers (- be stack-allocated). This is vital for some use cases and is impossible today (ok, possible by painfully wrapping a cell around each owned pointer and taking its value in the stack closure). You can do all of that with unboxed closures. Patrick ___ 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] Thoughts on the Rust Roadmap
Thanks for the explanation. Of course, the point is that you'd meed two types, `OnceFn` which is stack-allocated (non-send-able, can take borrowed pointers from its context) and `SendFn` which is heap-allocated (send-able, can't take borrowed pointers from its context). Both would be able to consume an owned pointer. I guess we'll see how this ends up when it evolves past being a sketch of an idea :-) On Tue, Dec 31, 2013 at 4:42 PM, Patrick Walton pcwal...@mozilla.comwrote: On 12/31/13 6:39 AM, Oren Ben-Kiki wrote: Great news... I'll admit I have no idea what unboxed closures are, exactly, google wasn't helpful finding out a post clearly describing them. The example in http://www.mail-archive.com/rust-dev@mozilla.org/msg07569.html shows passing a closure to a map, so it obviously isn't a call-once so it can't consume an owned pointer. E.g., if it was `|x| x + f(move-some-owned-pointer-from-the-context-to-be-consumed-by-f)`, then it wouldn't - and shouldn't - work. Presumably along with `FnT,U` there will be something like `OnceFnT,U`: trait OnceFnRet,Args... { fn call(self, args: Args) - Ret; // note by-value self; this is what makes it one-shot } Note: This is just a strawman sketch of the idea; it may well not work, no promises, etc. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Let’s avoid having both foo() and foo_opt()
There was a whole thread about the need for once-stack-closures. They are really vital for simple programming with higher-order functions such as these. I'm not optimistic about them being added though :-( On Sat, Dec 7, 2013 at 8:15 AM, Brendan Zabarauskas bjz...@yahoo.com.auwrote: On 7 Dec 2013, at 10:47 am, Simon Sapin simon.sa...@exyr.org wrote: This is why we have methods like .map() and .and_then() I like using these higher order functions, but I run into lots of issues with moved values because we don’t have once functions. I end up having to use matches, which are awfully verbose for simple things. :( ~Brendan ___ 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] do
Once stack functions have nothing to do with RAII. It is about container manipulation methods. Consider the mangle function of a hashmap for example. It makes perfect sense to be able to access a borrowed pointer and also consume an owned pointer inside the mangle actions. This is currently impossible just because. I have ~10K of Rust LOC in my pet project and I run into this problem more than a dozen times. I ended up using cells and other nastiness to work around what is essentially an artificial restriction. Passing actions to other tasks is all well and good, and repeatedly applying a function to many container members (e.g., mapping or folding) is also common. Both of these use cases are very well supported. But it is as common to have a container that invokes a function exactly once on one specific member (as another example, basically any function of the Option type that invokes an action). And this common use case is very badly supported. On Sat, Nov 30, 2013 at 10:23 AM, Patrick Walton pwal...@mozilla.comwrote: I don't want stack once functions, because I feel that their use cases are better served with RAII, which serves the same purposes without rightward drift and without forcing LLVM to perform devirtualization. Patrick Oren Ben-Kiki o...@ben-kiki.org wrote: I find `do` syntax form is vital for DSL-ish code. Getting rid of it makes a lot of code look downright ugly. I'd rather it used a more Ruby-ish notation though, I find that putting the `do` far away from the `{ ... }` doesn't read well. `foo() do |...| { ... }` would have made more sense for me (think of `do` as a macro-ish binary operation injecting the proc into the function on the left). But the current form is acceptable. Syntax niceties aside, I find it extremely problematic that we have only two forms of callable, one that is on the stack but can be called multiple times, and one that is on the heap and can only be called once. This arrangement sort-of-makes-sense when one thinks from an implementation point of view, but I find it to lack a crucial use case, that of a form that is on the stack and is also called only once. The reason this 3rd form is so important is the extremely common case of a container that wants to take an action as a parameter for a method. ``` ... some_non_sendable_variable ... ... some_owned_variable ... do container.do_something_at_most_once |...| { ... use *both* variables ... } ``` This is a lose-lose situation. If the container takes a `proc`, then Rust complains that it can't capture the non-send-able variable. But if the container takes a stack closure, then Rust complains it can't use the owned variable. Of course, the container will _not_ send the action and will also _not_ call it twice, but it can't express this in the action type :-) The only workaround I found is to use a closure and wrap each and every non-send-able variable in a cell - this is an pointless and downright annoying manual boilerplate code. As long as this area of the language is being changed, I think that adding this missing 3rd variant should definitely be discussed (and hopefully implemented). This would affect the syntax discussion because there would be three forms instead of two; there are some more and less obvious choices here but they are secondary to the core issue of allowing the 3rd variant in the 1st place. On Sat, Nov 30, 2013 at 9:02 AM, Chris Morgan m...@chrismorgan.infowrote: (a) Kill ``do`` ... (b) Make ``do`` support both closures and procedures ... -- Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Sent from my Android phone with K-9 Mail. Please excuse my brevity. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
That would help a bit, but it would still require the programmer to manually setup and teardown the tuples, pass them to the closure, and so on. We'll also need to change each and every function that takes an action parameter to take the extra tuple in every container or container-like type. And then there's the possibility of modifying variables... It sounds like a lot of effort working around something the compiler can do automatically and actually already does automatically; all it needs is the ability to communicate the programmer intent via the type system so it can support and enforce it. On Sat, Nov 30, 2013 at 4:20 PM, Benjamin Herr b...@0x539.de wrote: On Sat, 2013-11-30 at 09:34 +0200, Oren Ben-Kiki wrote: This is a lose-lose situation. If the container takes a `proc`, then Rust complains that it can't capture the non-send-able variable. But if the container takes a stack closure, then Rust complains it can't use the owned variable. Of course, the container will _not_ send the action and will also _not_ call it twice, but it can't express this in the action type :-) The only workaround I found is to use a closure and wrap each and every non-send-able variable in a cell - this is an pointless and downright annoying manual boilerplate code. I think another previously mentioned workaround is to change all your closure-taking functions to have a name ending in _with and take an extra generic parameter by value that is then passed to the closure. In practice, that might end up being a tuple with all the values you're need to move into and from within the closure. It's not ideal and requires cooperation from the API but it probably reads better than a bunch of cells. :) -benh ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
Just to mention in passing - there's a related principle that converting a block to a closure shouldn't change its semantics. This obviously doesn't fully work because of return/break/continue; that said, if a block without such flow control constructs is wrapped into a closure, you'd expect it to just work. It doesn't, because to work it would have to be a once-called-stack-allocated lambda, which Rust doesn't have (I don't get the reason for that either :-) On Sat, Nov 30, 2013 at 9:40 PM, Kevin Ballard ke...@sb.org wrote: On Nov 30, 2013, at 10:20 AM, Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 10:05 AM, Kevin Cantu wrote: While we're changing this stuff, I'd like to see lambdas allow return, now that the need for forbidding that is gone, IIRC. That's more likely to continually trip me up than unusual allocation mechanisms. No objections here. Quite a while ago the restriction on `return` was explained to me as conforming to some principle (I forget the name, sadly) that basically says that wrapping a block of code in a closure and immediately calling the closure should not change the semantics of the code. Basically, `return` shouldn't return from the lambda because that's not what it would do if the closure was inlined manually. I didn't really understand the point of this, of course. -Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
There were several threads about this, https://mail.mozilla.org/pipermail/rust-dev/2013-October/006105.html for example. I don't see how that code can be converted to RAII at all. Sure it can be done with cells, or possibly with tuples (though, well, doing this _manually_? shudder). It really just begs for stack-allocated-once-closures. On Sat, Nov 30, 2013 at 11:28 PM, Patrick Walton pcwal...@mozilla.comwrote: On 11/30/13 11:38 AM, Kevin Ballard wrote: The problem here is that the type system already understands the idea of a `once` fn, it just has an artificial limitation that means it can only apply that to a heap closure and not a stack closure. No, it's merged with the idea of a heap/stack closure. Separating them out into separate axes would increase type system complexity. Patrick ___ 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] do
Like I said, this is a boiled-down example of the essence of the problem. Yes, the hashmap mangle is an example, and the option map, and similar standard container methods, and quite a few similar functions in my own specific container classes (contrary to popular opinion, in non-trivial projects people do end up writing their own specialized containers...). In general the problem is I am a container, give me a function to modify some piece of me combined with an invoker that says do the following to modify some piece of the container, accessing and updating all sort of variables. It is a pretty significant use case, which seems to have nothing to do with RAII, and bugs me a lot in my code. On Sat, Nov 30, 2013 at 11:57 PM, Patrick Walton pcwal...@mozilla.comwrote: On 11/30/13 1:54 PM, Oren Ben-Kiki wrote: There were several threads about this, https://mail.mozilla.org/pipermail/rust-dev/2013-October/006105.html for example. I don't see how that code can be converted to RAII at all. Sure it can be done with cells, or possibly with tuples (though, well, doing this _manually_? shudder). It really just begs for stack-allocated-once-closures. Well, the functions `attempt_1` and `attempt_2` in that message don't do anything, so there isn't anything to convert. Do you have other specific common examples of functions that can't be converted to RAII? `mangle` is one. `Option::map` and friends are another. Are there others? Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
I find `do` syntax form is vital for DSL-ish code. Getting rid of it makes a lot of code look downright ugly. I'd rather it used a more Ruby-ish notation though, I find that putting the `do` far away from the `{ ... }` doesn't read well. `foo() do |...| { ... }` would have made more sense for me (think of `do` as a macro-ish binary operation injecting the proc into the function on the left). But the current form is acceptable. Syntax niceties aside, I find it extremely problematic that we have only two forms of callable, one that is on the stack but can be called multiple times, and one that is on the heap and can only be called once. This arrangement sort-of-makes-sense when one thinks from an implementation point of view, but I find it to lack a crucial use case, that of a form that is on the stack and is also called only once. The reason this 3rd form is so important is the extremely common case of a container that wants to take an action as a parameter for a method. ``` ... some_non_sendable_variable ... ... some_owned_variable ... do container.do_something_at_most_once |...| { ... use *both* variables ... } ``` This is a lose-lose situation. If the container takes a `proc`, then Rust complains that it can't capture the non-send-able variable. But if the container takes a stack closure, then Rust complains it can't use the owned variable. Of course, the container will _not_ send the action and will also _not_ call it twice, but it can't express this in the action type :-) The only workaround I found is to use a closure and wrap each and every non-send-able variable in a cell - this is an pointless and downright annoying manual boilerplate code. As long as this area of the language is being changed, I think that adding this missing 3rd variant should definitely be discussed (and hopefully implemented). This would affect the syntax discussion because there would be three forms instead of two; there are some more and less obvious choices here but they are secondary to the core issue of allowing the 3rd variant in the 1st place. On Sat, Nov 30, 2013 at 9:02 AM, Chris Morgan m...@chrismorgan.info wrote: (a) Kill ``do`` ... (b) Make ``do`` support both closures and procedures ... ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
On Fri, Nov 15, 2013 at 11:47 AM, Huon Wilson dbau...@gmail.com wrote: As I understand it, default methods are specialised/monomorphised for each type for which the trait is implemented. The only time a virtual call ever happens is when one explicitly has a trait object. That would be awesome, if it were true; it is quite a trick to pull that off when the default methods are implemented in a different crate. Can someone provide an authoritative answer on this? Also, C++ faces the problem of providing a single copy of monomorphised functions (for templates). This is done during the link phase and AFAIK is one of the causes of C++ links taking a painfully long time. Will Rust suffer from the same problem? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
Thanks for the explanation! So virtual function calls are kept to the absolute theoretical minimum, that's very good to know. In my case I have one crate for some infrastructure and another crate for the application using it (there would be several of these). I guess having two copies isn't that bad. On Fri, Nov 15, 2013 at 2:30 PM, Daniel Micay danielmi...@gmail.com wrote: On Fri, Nov 15, 2013 at 6:54 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: That would be awesome, if it were true; it is quite a trick to pull that off when the default methods are implemented in a different crate. Can someone provide an authoritative answer on this? Also, C++ faces the problem of providing a single copy of monomorphised functions (for templates). This is done during the link phase and AFAIK is one of the causes of C++ links taking a painfully long time. Will Rust suffer from the same problem? Rust serializes any generic or inline functions to an AST stored in the crate metadata and will re-compile them as-needed per-crate. In both Rust and C++, you end up with one copy of these at runtime for each dynamically linked shared object. With C++ templates, the linker or link-time optimization discards duplicate instantiations across compilation units. Rust doesn't have compilation units smaller than a crate so there is no equivalent functionality. If you use crates as compilation units to make compiles incremental/parallel, the situation is much worse than C++ as you'll have many duplicates and they won't even go away with link-time optimization until `mergefunc` works. There's almost no point in doing anything but a massive crate at this point... ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Treating Vectors Like Any Other Container
If the traits were polymorphic in the index type (instead of always expecting an integer), then one could use them to make hash tables use vector syntax (e.g., `hash[foo] = 1`)... Ruby does that, for example. So something like bitset (with integer indices) isn't the only example. Not sure whether we want to go that way, though... On Fri, Nov 15, 2013 at 3:35 PM, Diggory Hardy li...@dhardy.name wrote: In reply to Nicholas Matsakis's post: http://smallcultfollowing.com/babysteps/blog/2013/11/14/treating-vectors-like-any-other-container/ That's a really nice write-up Nicholas. I wanted to chip in because I had a think about some similar issues in the past, but your review is far more thorough and knowledgeable than I could have managed. Regarding Gc[uint] (or @[T]), this seems fairly useless to me, given that @mut[T] would not be memory safe (unless it is @mut ~[T] or reallocating the buffer is not allowed), thus the only way of constructing @[T] would be to coerce a ~[T] or a literal. For me, the biggest plus of your proposal is uniformity: e.g. someone could implement something like C++'s std::bitset and have it look syntactically equivalent to VectorT (although given that std::bitset is not very useful and Boost's Pointer Containers are redundant in both C++11 and Rust, I'm struggling to find an example where this is actually needed). Given the three big drawbacks (implementation effort, syntax and pattern matching) it may not be worth it. Using a builder trait to construct user-defined objects from literals is a nice approach (I believe it could also be useful in type-safe printf-like formatters and embedded DSLs for things like constructing HTML or parser rules), but some things like method lookup won't always be possible: let v : Vectorint = [1,2,3].append_one( 4 ) ___ 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] Treating Vectors Like Any Other Container
Slice traits weren't: though, does `tree.mut_slice_between(foo, bar)` even make sense? On Fri, Nov 15, 2013 at 3:44 PM, Huon Wilson dbau...@gmail.com wrote: On 16/11/13 00:39, Oren Ben-Kiki wrote: If the traits were polymorphic in the index type (instead of always expecting an integer), then one could use them to make hash tables use vector syntax (e.g., `hash[foo] = 1`)... Ruby does that, for example. So something like bitset (with integer indices) isn't the only example. Not sure whether we want to go that way, though... Note that the traits in the blog posts are parameterised by the index type: trait IndexI, E { fn index'a('a self, index: I) - 'a E; } Etc. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
I'm not certain whether it is better than anonymous members; one has to list all the data members one by one, and there's more magic syntax. But it is up to the powers-that-be. On Sat, Nov 16, 2013 at 5:48 AM, Tommi rusty.ga...@icloud.com wrote: So... did anyone think that my idea (of doing multiple-inheritance by separating the responsibilities of providing functionality and providing data between the trait and the type which implements the trait) would warrant an enhancement request at github? Or how do these things tend to work around here? (I've done plenty of bug/enhancement reporting for D, but I know that language fairly well whereas I've just barely read the Rust tutorial/manual). ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
I added https://github.com/mozilla/rust/issues/10491 which links to https://github.com/mozilla/rust/issues/9728 to propose that single inheritance can co-exist and be compatible with anonymous fields, achieving the best of both worlds. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
In your code, when providing a default implementation for `inflate_by`, you are invoking the trait (hence virtual) method `get_radius`. If the compiler compiles `inflate_by` when seeing just the `Inflate` source code, then this must be translated to an indirect call through the vtable. The point of anonymous members (and, to a greater extent, of the single inheritance) is to ensure that access to data members is just that, without any function calls. To achieve that with the approach you described, the compiler will need to re-compile `inflate_by` for each and every struct that implements it; only then it would be able to inline `get_radius`. Is this what the Rust compiler does today? I have no specific knowledge of the answer, but the simplest thing for the compiler would be to keep `get_radius` as a virtual function call. Doing otherwise would require quite a bit of machinery (e.g., what if `Inflate` is defined in another crate, and all we have is its fully-compiled shared object file? There would need to be some extra stuff available to the compiler to do this re-compilation, as the source is not available at that point). Therefore I suspect that this approach would suffer from significant performance issues. On 2013-11-15, at 2:09, Tommi rusty.ga...@icloud.com wrote: trait Inflate { fn get_radius's('s mut self) - 's mut int; fn inflate_by(mut self, amount: int) { *self.get_radius() += amount; } } trait Flatten { fn get_radius's('s mut self) - 's mut int; fn release_all_air(mut self) { *self.get_radius() = 0; } } struct Balloon { radius: int } impl Inflate for Balloon { fn get_radius's('s mut self) - 's mut int { mut self.radius } } impl Flatten for Balloon { fn get_radius's('s mut self) - 's mut int { mut self.radius } } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
This is probably as good as we can get in the current system (I do something similar in my code today). I also think you probably need both super and mut_super, so it would be two methods to implement instead of one (still pretty good). I wonder whether it is possible to write a macro that automates writing these boilerplate methods? The key weakness is that (I think) the compiler can't inline the accesses to super so that you end up with a chain of virtual function calls every time it is accessed, so performance would be pretty bad. On Wed, Nov 13, 2013 at 10:27 AM, Eric Reed ecr...@cs.washington.eduwrote: Here's how I would do it using just existing Rust (assuming this hasn't all changed under me in the past couple months). NB: I haven't actually tried compiling this, but I'm pretty sure it (or something like it) would work. Nice properties over this solution: - Doesn't require language extensions (although syntax sugar wouldn't be unwelcome) - Doesn't require trait objects (i.e. static dispatch is possible) - Only need to implement one method for each derived type (super) in addition to overridden methods - Supports multiple inheritance in two ways (and avoids the diamond problem I think -- not a C++ expert so I may have misunderstood that) + no default parent and programmer must select which parent to use before calling + implementer-chosen default parent and programmer can chose to use a different parent if desired Neutral?: - Doesn't enforce or care about the prefix property. Not sure if that still matters so much w/o dynamic dispatch. Downsides: - Performance of delegation depends on LLVM's ability to inline (I think). - Does require repeating all the methods once (for delegating default implementations) // The base type struct Base { data : int; } // Characterize it's extensible behavior in a trait trait Trait { fn method(self); } // Implement the base behavior impl Trait for Base { fn method(self) { ... } } // Extension of trait that supports upcasting to existing implementations trait DerivingTraitP : Trait : Trait { // one extra method for accessing a parent's implementation. ideally this would be inlined by the compiler fn super(self) - P; // default implementations for all the methods in Trait let us avoid writing delegation everywhere manually fn method(self) { self.super().method() // just delegate to parent } } // Single inheritance struct Single { parent: Base, moreData: int, } impl DerivingTraitBase for Single { fn super(self) - Base { self.parent } } // Overriding behavior struct Override { parent: Base, otherData: u8, } impl DerivingTraitBase for Override { fn super(self) - Base { self.parent } fn method(self) { ... } } // Multiple inheritance struct Multiple { single: Single, override: Override, evenMoreData: ~str, } // must specify which parent's implementation we want (could hide wrapping inside of as_* methods impl'd on Multiple if you like) // if we want one of them as the default, then we can impl DerivingTrait on Multiple directly struct MultipleAsSingle(Multiple); struct MultipleAsOverride(Multiple); impl DerivingTraitSingle for MultipleAsSingle { fn super(self) - Single { self.single } } impl DerivingTraitOverride for MultipleAsOverride { fn super(self) - Override { self.override } } fn main() { let base = Base { ... }; let single = Single { ... }; let override = Override { ... }; let multiple = Multiple { ... }; base.method(); base.super(); // compile time error single.method(); // =inline delegation= single.super().method() =inline upcast= single.base.method() override.method(); // done! no delegating MultipleAsSingle(multiple).method(); // =delegate= MAS(multiple).super().method() =upcast= multiple.single.method() =delegate= multiple.single.super().method() =upcast= multiple.single.base.method() MutlipleAsOverride(multiple).method(); // =delegate= MAO(multiple).super().method() =upcast= multiple.override.method() } Thoughts? Eric On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard ke...@sb.org wrote: On Nov 12, 2013, at 10:26 PM, Kevin Ballard ke...@sb.org wrote: And even that restriction could be lifted if ~Trait objects could be represented using an array of pointers (one to each inherited struct), e.g. ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is not worth doing. Upon further reflection, this would need to be done anyway because of the ability to combine traits. If I have trait TraitA : A {} trait TraitB : B {} and I want to use ~TraitA+TraitB then I would need a fat trait. Although in this case the number of value pointers is equal to the number of combined traits, so it's a bit more sensible to allow for fat trait pointers here. -Kevin
Re: [rust-dev] linking to cells inside a data structure
You are right that the compiler needs to ensure no pointers escape the struct itself, so it is OK to move it (and all the pointers it includes). Intuitively this would require another level of static type checking (whether there are existing outside-the-struct borrowed pointers at any point), probably not easy to do. On Wed, Nov 13, 2013 at 6:08 PM, Niko Matsakis n...@alum.mit.edu wrote: I don't know how to make that sound, unfortunately, other than using an arena and allocating all the nodes into it (losing the ability to deallocate individual nodes). Arenas don't require that you lose the ability to deallocate individual nodes. See my thoughts in #10444. Briefly, the idea is that the arena allocation returns an affine type like `ArenaAlloc'self`. You can then have a free method that consumes this instance and adds it to a free list to be reused for future allocation. Niko ___ 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 Inheritance / mixins
Hmmm. Perhaps I was too hasty. It would be interesting to look at the generated binary code and see if it actually work this way... On Wed, Nov 13, 2013 at 8:08 PM, Eric Reed ecr...@cs.washington.edu wrote: I'm not sure I follow. My implementation doesn't use any trait pointers, so the only time there were would be a trait pointer is if you casted to ~Trait yourself. In that case, only the original method call would be dynamic dispatch; all the internal calls (delegating and upcasting) are still static dispatch. So my version doesn't pay for any dynamic dispatch over what the programmer is already paying for. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The future of M:N threading
On Wed, Nov 13, 2013 at 10:51 PM, james ja...@mansionfamily.plus.comwrote: On 13/11/2013 19:30, Daniel Micay wrote: I had high hopes of Rust having lightweight segmented stacks and precise per-task GC and portability too. Sort of Erlang with type safety and AOT compilation with a sane model. That's something I'd also love to see! The Erlang with type safety and compilation is definitely something I was (am!) expecting from Rust. (I think Rust could be a good basis for distributed actor-style systems, due to the owned pointers it is clear how to send messages from one machine to another, but that's another story...) But now much of this seems abandoned or clearly a long way out and it is becoming more like C++ with some functional bits, and I can get that with Scala and F# now. To be fair, Scala and F# are still VM languages while Rust is compiled. And I _hope_ not all is lost, so that Rust would still be friendly to actor-style programs (as well as to socket-server style programs). It does seem the focus has shifted away from this :-( I find it more scary that Rust might be turning towards a universal platform for implementing your own pointers/scheduler/abstractions rather than an opinionated platform providing a great set of pointers/scheduler/abstractions. The need to allow for any and every pattern combined with extract the last 1% of performance has IMO poisoned C++; I was drawn to Rust as take the good parts, bake them into the language, and ignore the rest, even at some reasonable performance cost. It is somewhat ironic that Rust, which at times has a much lower level feel to it, provides essential higher-level features like algebraic types and pattern matching and generics, while a more abstract language like Go doesn't. As an application developer who doesn't care about the last 15% of the performance, but cares a lot about productivity, I can't help but wish for a happy medium between the two :-) At any rate, language design is _hard_. Rust is actually doing pretty well... and one can drastically evolve the runtime/scheduler over time - even provide different versions for different needs. It is much harder to fix the basic language abstractions, which Rust gets pretty well. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
The Rust way to do that would be to have an array of objects that all implement the needed trait. But that would mean that access to the data members would be a virtual function call, while access to the data members of the new kind of traits you described would be cheap. I think that introducing two kinds of traits would have non-obvious implications on the type system, in addition to saddling us with all the pains of a single-inheritance types hierarchy system. Also, assuming you do introduce two types of traits, for the reason you described, making implementation reuse a feature of _only_ one kind of traits feels very wrong. There should be some way to do reasonable implementation reuse for the current kind of traits as well. You could view the new kind of traits you described as a special case of what I described. In fact you could say that `pub struct Foo : Bar { ... }` means exactly `pub struct Foo { reuse Bar::*; ... }`, and also allow the kind of pointer casts/heterogeneous arrays you are talking about. Or, we could move in the direction of anonymous members, which should also allow for the kind of pointer casts/heterogeneous arrays you want... These would offer a somewhat different tradeoff than the source code transformation approach, so you might like them better :-) On Tue, Nov 12, 2013 at 9:56 AM, Patrick Walton pcwal...@mozilla.comwrote: On 11/12/13 4:53 PM, Oren Ben-Kiki wrote: Your solution does not match the performance of single inheritance, because it has virtual method calls for every field access from the outside of the trait. Sorry, I don't follow. Access to members from outside of the traits would require accessing the concrete type. Since the approach I described used source transformation, then this would just be a normal data member access, as efficient as single inheritance. Oh, source transformation. I didn't read closely. That won't work as a replacement for single inheritance because it doesn't provide truly existential types--for example, an array of heterogeneous objects all of which share a common prefix. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] linking to cells inside a data structure
I have been struggling with variants of this for a while and there's no best solution. First, if the array holds values (as opposed to pointers to values), then pretty much your only option is to replace your pointers with indices to the array. You'd need access to the container to access the values, of course. But this is the only safe way because adding into the array may relocate it, invalidating all pointers. If your array holds pointers, then you can do something; e.g., store RcT in the array cells and also in the places you want to link to the values. If reference cycles are an issue you can use @T instead of RcT (keep in mind this will change to GcT or something in the future). If sending the whole thing is an issue, you are pretty much forced to use ArcT (and forget about reference cycles). And, of course, each of these (Rc, @, Arc) has a different name if you want mutation (RcMut, @mut, ArcRW). In performance-critical code I sometimes give up and just have an array of ~T and use an unsafe ptr to T in all my other references... which is OK as long as these only live as long as the container, but I get zero compiler support for that. I wish there was a way to say this borrowed pointer lives only as long as its container. That doesn't seem to be in the cards though :-( On Tue, Nov 12, 2013 at 2:24 PM, spir denis.s...@gmail.com wrote: Hello Rust people, A data structure holds (unpointed) cells in an array. Then, a number of linked lists part of the data structure link to those same cells. What is the right Rust way to do that? I cannot have the language accept the instruction establishing a link, whatever kind of pointer I use (both for self and for cells). Code and/or details on demand. Denis PS: It is in fact a hash table [1] which buckets are link lists as usually, but the cells are stored in an array instead of spread around the memory at the allocator's convenience ;-). First advantage is indeed entries are in order. (To move on in the meanwhile, I'll remove this aspect.) [1] Actually a mod table since keys are uints, there is no hash, only modulo. ___ 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] linking to cells inside a data structure
Yes, you lose the ability to deallocate individual nodes. Pretty hard to express in a type system. Still I wish I could at least have the compiler help me to ensure my unsafe pointers never escape the lifetime of the container; right now I must trust the programmer (and in my case, the container basically lives as long as the program, anyway). Slots sound nice. Is the idea that one would do RcT for read-only access and RcSlotT for mutable access? How does this protect against multiple mutations at once? On Tue, Nov 12, 2013 at 3:13 PM, Patrick Walton pcwal...@mozilla.comwrote: In performance-critical code I sometimes give up and just have an array of ~T and use an unsafe ptr to T in all my other references... which is OK as long as these only live as long as the container, but I get zero compiler support for that. I wish there was a way to say this borrowed pointer lives only as long as its container. That doesn't seem to be in the cards though :-( I don't know how to make that sound, unfortunately, other than using an arena and allocating all the nodes into it (losing the ability to deallocate individual nodes). Patrick ___ 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] copying pointers
For linked lists with no cycles, why not use OptionRcT (or RcMut)? On Tue, Nov 12, 2013 at 4:06 PM, spir denis.s...@gmail.com wrote: PS: What would be, in fact, the rusty way for a simplissim linked list. I use Option~Cell for now, to have something clean (None) to end the list, since Rust looks rather functional. But as always with Option this way quite obscures and complicates the code (Some() expressions, match expressions...). I'd rather just use a NULL pointer, for here it is fully safe. But this does not look rusty at all, I guess. What is your view? Denis ___ 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 Inheritance / mixins
It seems the argument on single-inheritance hinges on the following use case: struct Foo { foo: int } struct Bar : Foo { bar: bar } fn main() { let myFoos = [Foo{ foo: 1 } as ~Foo, Bar{ foo: Foo{foo: 1}, bar: 2} as ~Foo]; for myFoo in myFoos.iter() { myFoo.foo; // Fixed offset access } } If I understand correctly, this member access is vital for Servo. At the same time, I (and I think others) would like to see some form of a flexible implementation reuse for traits, with the understanding the invoking trait methods incurs the cost of a virtual function anyway. I think it is obvious that the same mechanism can't do both. So how about a compromise? There would be two mechanisms, but we'll make them play nice with each other. Mechanism #1: Struct-traits. Mechanism #3: Anonymous fields. struct Foo { foo: int } // Note: Use Foo as a trait. // Any type implementing Foo has a publicly-reachable Foo member at offset 0. // The trait Foo allows constant-offset access to all the Foo data members. fn use_fooT: Foo(ptr: T) - int { ptr.foo // Fixed offset } // By construction, Bar implements the Foo struct-trait struct Bar { Foo; bar: int; } (It is also possible to add a new syntax struct Bar : Foo { bar int }, if this is seen as clearer, but IMO it isn't really needed). // Baz also implements Foo by construction. struct Baz { Bar; baz: int; } // Qux doesn't implement Foo. struct Qux { qux: int, Foo } As for non-struct traits, anonymous fields would provide a default implementation. That is, suppose that: impl Trait for Foo { ... } Then one would be need to write (explicitly!): impl Trait for Bar {} // Just use the default from Foo Or: impl Trait for Bar { ... override some of the methods ... }; (I think it is a bad idea to have traits be implemented implicitly just because one anonymous field implements them; IMVHO an explicit impl Trait for Container is a very good idea). This way you can have your cake and eat it 2. I think it is pretty clean - traits do arbitrary mixin things with virtual-function cost (_with_ implementation reuse); And there's a by definition single inheritance special access-my-data-members-at-fixed-offset trait whose existence does not impact the power of the normal mixin traits in any way. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] formats 'Standard' {} and 'Poly' {:?}
I thought the trait for `{}` was called `Default`. At any rate, I also don't understand why we need both `{}` and `{:s}`, `{:i}`, etc. There's some reason for `{:x}` (change the output base to hexadecimal), but that's about it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Implementation Inheritance / mixins
I googled around and this has been asked before several times; there are answers that use obsolete syntax and Rust concepts, so I thought it might be a good idea to revisit the issue. The basic use case is having some trait, and having some (base/mixin) struct implementing it. Now, one wants to have a 2nd (derived/importing) struct implementing the trait, based on the 1st struct implementation (including its data members). I'm not certain what the idiomatic Rust answers to this common use case is, today. One can obviously simply duplicate the data members and the trait implementation, if the size of the code is small enough. This is very WET though. One can have the derived/importing class contain a member of the base/mixin struct, then delegate each and every trait function to it (providing overrides where needed). This is pretty tedious and results with a lot of boilerplate code. Performance would probably suffer. It is also difficult to override methods that are invoked by imported methods. One can write the 1st struct in a way that is intended to be overridden, e.g. by providing a trait with a get base accessor and using that all over the place. This makes the base struct code uglier (and, I think, less efficient), but results in less boilerplate code in the derived class. It makes overrides much trickier though. In general seems pretty restricted. One can implement a bunch of macros to automate injecting the common code into derived structs (I think - I'm not clear whether macros are allowed to add methods and members to a struct). Setting up the macros isn't fun, especially when one wants to take overrides into account. If there another option? Which one is more idiomatic Rust code? There are many options that would require compiler/language support... these basically automate the above approaches. Personally I am fond of a somewhat unusual approach I first saw in Sather (I think), which was to automate the macro based approach. That is, define implementation inheritance (actually, mixins) as a source-level operation. The source code of the imported/reused members from the base (mixin) struct would be (logically anyway) pasted inside the definition of the derived/importing struct, and then compiled as usual. This is very simple to define (it is basically similar to use - in fact, this resonates with the idea of changing the division of labor between structs and modules, but it is a separate discussion). It allows for great flexibility: one can import only specific methods and members, providing a different implementation for others; Using the ability to import something under a different name, it is possible to wrap the imported methods with additional functionality (foo { ...; renamed_imported_foo(); ... }), etc. So, this provides the functionality of virtual functions (an imported function calling one that is redefined - that is, not imported but implemented locally - will get the overriden behavior). At the same time, unlike virtual functions, it still allows for aggressive optimizations (since when compiling a struct, all methods are fully known and can be inlined etc.). It sidesteps a lot of sticky issues with a vtable-sharing oriented approach (like in C++). For example, re-importing would cause multiple definitions of the same member/method. It even allows for separate compilation (if the object file contains the AST tucked in it somewhere), and for reuse of compiled methods (if they don't invoke overriden methods - but that may be tricky to implement). At any rate, I'm not claiming this is necessarily the best approach for Rust; I'm just wondering, what is the proposed way to address this use case? None of the manual approaches seems very appealing (unless there's a better one I missed). Thanks, Oren Ben-Kiki ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Implementation Inheritance / mixins
Ah, thanks. I wasn't aware of that. I should start tracking that RSS feed... I am very concerned that single-inheritance takes the language in the wrong direction. I feel that a more mixin-oriented solution would better match Rust's traits based type system. I posted a comment the blog entry you gave, which I assume is a more appropriate venue than this thread...? Either way, I gather there's no current idiomatic pattern for this - we are waiting until some solution is agreed upon (and implemented :-) Thanks, Oren. On Mon, Nov 11, 2013 at 11:43 PM, Patrick Walton pcwal...@mozilla.comwrote: On 11/12/13 5:16 AM, Oren Ben-Kiki wrote: I googled around and this has been asked before several times; there are answers that use obsolete syntax and Rust concepts, so I thought it might be a good idea to revisit the issue. The basic use case is having some trait, and having some (base/mixin) struct implementing it. Now, one wants to have a 2nd (derived/importing) struct implementing the trait, based on the 1st struct implementation (including its data members). There are proposals for this, if I understand you correctly. This is needed in Servo. http://smallcultfollowing.com/babysteps/blog/2013/10/24/ single-inheritance/ Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] State of private
Well... you could consider each member as if it was implemented by accessor method, and control these methods even if it was an actual member; of course, also provide a the same syntax for accessing actual members and method-defined-members... but I think this is too far from the current Rust direction. A friend keyword, on the other hand, should be pretty simple to implement and is a rather minor tweak to the existing system. On Sat, Nov 9, 2013 at 5:50 AM, Gábor Lehel illiss...@gmail.com wrote: On Sat, Nov 9, 2013 at 7:43 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Many thanks for the replies. My problem is actually in accessing private methods/members of a struct defined in a different, but very closely related module. It seems @ nikomatsakis https://github.com/nikomatsakis is saying in the final text comment of https://github.com/mozilla/rust/issues/8215 that it is not possible to specify methods/members that are only accessible from within a small set of modules; they are either completely public, or private to a single module. FWIW, I think this might also be partially addressed by my earlier proposal to remove methods as a distinct concept, and just allow using dot-syntax with any function? (I have a draft of a follow-up to that thread that's been sitting there for two weeks... sigh.) It wouldn't help with struct members though, which is interesting. Maybe the import syntax could be extended to accomodate that? E.g. mod a { pub struct Point { x: int, y: int } } mod b { use a::Point; } // currently exists, import all fields mod c { use a::Point { * }; } // also import all fields mod d { use a::Point { }; } // import no fields mod e { use a::Point { x }; } // import only x, not y Then you could play similar games with struct fields as with items. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] About owned pointer
Now I'm confused; doesn't this mean str is fixed size, so the proposal to just use str for the 3-word struct and have ~str and str just be the normal thing makes sense after all? On Fri, Nov 8, 2013 at 8:56 PM, Marvin Löbel loebel.mar...@gmail.comwrote: On 11/08/2013 07:50 PM, Igor Bukanov wrote: On 8 November 2013 18:35, Patrick Walton pcwal...@mozilla.com wrote: But Daniel did some performance measurements and found that this had suboptimal performance characteristics when compared to: struct ~str { char *ptr; int size; int cap; } So we're changing to the latter. Does this mean that when ~str is passed as a parameter the compiler copies 3 words and that makes things faster? According to https://github.com/mozilla/rust/issues/8981, yes and yes apparently. :) You rarely pass around a ~[T] directly anyway, usually you work with slices to them, which right now consist of exactly two words. (Though that might change to three words too for unrelated consistency reasons) Other speed improvements come from the fact that empty vectors no longer allocate, and that you no longer need to dereference a pointer into heap memory to get the size of an vector. ___ 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] About owned pointer
So, the core question is whether we think of str as an object or as a pointer. Either we see it as an object (with fixed size, 3 words), which internally holds a nested pointer to a dynamically-sized region of characters; or we see it as a direct smart pointer to this array. The physics of str seem to be the former, but the abstraction presented to the programmer is the latter. Of course, there's also value in providing clean abstractions, but this is a leaky one. For example, it isn't very clean to have a concrete type T which allows ~T, T, @T, *T but forbids having a simple T (unless one is talking about a trait, which str isn't). It is weird and causes all sort of edge cases when trying to write generic code. Also, str != ~[u8] (for good reason). The internal array is hidden anyway, so pretending to be a smart pointer to it doesn't make a lot of sense to me. Of course there's a very related issue of whether we see a vector as a smart pointer or as an object, so even if str was == ~[u8] it would probably still make sense to view it as an object :-) In general, in a system language, one wants the low-level abstractions (such as str) to be close to the physics, so people would be able to easily reason about the code behavior. This would also lend support to the proposal of seeing str as a struct and not as a pointer. On Fri, Nov 8, 2013 at 11:22 PM, Patrick Walton pcwal...@mozilla.comwrote: On 11/8/13 11:33 AM, Oren Ben-Kiki wrote: Now I'm confused; doesn't this mean str is fixed size, so the proposal to just use str for the 3-word struct and have ~str and str just be the normal thing makes sense after all? No, `str` is not fixed-size. An *owned pointer* to a string is fixed-size (as all pointers are), but the string *itself* is dynamically sized. The size of pointers changes based on the kind of thing they point to. Patrick ___ 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] About owned pointer
Yes, the down side is another level of indirection. This could be optimized away for 'static str, but not for str. Good point. On Sat, Nov 9, 2013 at 12:06 AM, Patrick Walton pcwal...@mozilla.comwrote: On 11/8/13 2:00 PM, Oren Ben-Kiki wrote: Also, str != ~[u8] (for good reason). The internal array is hidden anyway, so pretending to be a smart pointer to it doesn't make a lot of sense to me. Of course there's a very related issue of whether we see a vector as a smart pointer or as an object, so even if str was == ~[u8] it would probably still make sense to view it as an object :-) No! Read the thread! You need `str and `'static str` for performance as well as `~str`. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] About owned pointer
Is there a place where one can see new proposals (is it all in the issues list in github and/or here, or is there a 3rd place?) E.g. there's the whole lets-get-rid-of-@, and now is the 1st time I heard there's a dynamically sized types proposal... well, other than in passing in this thread, that is. On Sat, Nov 9, 2013 at 12:09 AM, Patrick Walton pcwal...@mozilla.comwrote: On 11/8/13 2:08 PM, Oren Ben-Kiki wrote: I don't follow. ~Trait is a pointer, and therefore its size is fixed. There are checks in place to prevent using a trait as a type (there's a nice error message from the compiler saying using trait as a type :-)... So the Trait in ~Trait isn't a _type_, right? :-) No, the `Trait` in `~Trait` is a type under the dynamically sized types proposal. It is a type, just a dynamically sized one. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] About owned pointer
No need to apologize. You are quite right, this is tricky and there's a good reason for the current design choices (perhaps there are better, but they are far from obvious). I wish I could put more time into deep thinking about this... which, of course, you can :-) On Sat, Nov 9, 2013 at 12:32 AM, Patrick Walton pcwal...@mozilla.comwrote: On 11/8/13 2:19 PM, Brian Anderson wrote: This thread is has been running off the rails a bit. Let's all please take a step back. This subject is one of the most subtle areas of Rust's type system, is in flux, and a lot of our plans about it are scattered across various places and passed around through informal conversation. It's understandable that there's confusion and debate here. Agreed, and again, my apologies. Patrick ___ 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] Help: How to execute the owned method produce_obj?
It wouldn't be self.something because it doesn't take a self argument. Try Pool::produce_obj::T(...) ? Or add a self argument to it and then call it normally. On Sat, Nov 9, 2013 at 1:31 AM, wuyunlong wuyunl...@msn.com wrote: struct PoolT{ produce_obj : ~fn()-T, elements : ~[T] } implT:Send PoolT{ fn new_obj(mut self){ let obj = self. ... ;*// Here ,how to execute method produce_obj ?* self.elements.push(obj); } } ___ 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] State of private
I find that in several cases I would like to have sibling modules access private members, that is, allow foo::bar::Bar access the private members of foo::baz::Baz, but disallow any code in qux::* from accessing these members. Currently in these cases I am forced to expose as public stuff that really should be private, or merge too much code into one module. In a word, is this even possible, or is planned to be possible? I know there have been some hot debates on visibility and accessibility and modules and crates, and I don't want to re-open it :-) I just want to know what the state of affairs is. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] State of private
Many thanks for the replies. My problem is actually in accessing private methods/members of a struct defined in a different, but very closely related module. It seems @ nikomatsakis https://github.com/nikomatsakis is saying in the final text comment of https://github.com/mozilla/rust/issues/8215 that it is not possible to specify methods/members that are only accessible from within a small set of modules; they are either completely public, or private to a single module. Looking at the same thread, I see nobody asked about a possibility of keeping the existing rules, but also adding a friend keyword at the module level; that is, if a module foo says friend mod bar, then the module bar can access any private stuff in the module foo. I'm not very enamored of the friend keyword in C++, but it seems to me that having it only in module level greatly simplifies things. Also, in a Rust context, it seems it would cut down on much of the boilerplate code needed by barrier modules (which is not to say that re-exporting isn't a very useful feature as of itself). I don't want to re-open old discussions - is this something that was considered and rejected before? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] State of private
I added https://github.com/mozilla/rust/issues/10383 in the hope that enough people would find it useful and it would end up in 1.0 after all :-) In the meanwhile, I'll have to re-think my design to see if I can package all the private members in a separate structure, or something like that. Thanks, Oren Ben-Kiki On Fri, Nov 8, 2013 at 10:44 PM, Patrick Walton pcwal...@mozilla.comwrote: On 11/8/13 10:43 PM, Oren Ben-Kiki wrote: Looking at the same thread, I see nobody asked about a possibility of keeping the existing rules, but also adding a friend keyword at the module level... Nobody has proposed it AFAIK. I personally think it's not likely to be a Rust 1.0 feature, but I wouldn't necessarily be opposed in general. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Abandoning segmented stacks in Rust
Does ditching segmented stacks mean we can start getting a stack trace when a task `fail!`s? Or is this an unrelated issue? The lack of stack traces is extremely tedious when debugging failed assertions... ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Abandoning segmented stacks in Rust
Good to know! The GDB stack traces leave something to be desired, though - e.g. the way it reports closures isn't really very useful (adding source file name and line number would be really good there). But it is certainly better than nothing. Thanks! On Fri, Nov 8, 2013 at 8:40 AM, Corey Richardson co...@octayn.net wrote: Entirely unrelated. Do note that we have stack traces *now*, as long as you're using gdb to get them :). Break on `rust_begin_unwind` or catch throw. On Fri, Nov 8, 2013 at 1:27 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Does ditching segmented stacks mean we can start getting a stack trace when a task `fail!`s? Or is this an unrelated issue? The lack of stack traces is extremely tedious when debugging failed assertions... ___ 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] Abandoning segmented stacks in Rust
How bad would it be to add another 64 bits to the some data to go along with it part? I'm assuming 32 bit for file name index in some table and 32 bit for the line number in the file should be enough :-) On Fri, Nov 8, 2013 at 8:48 AM, Daniel Micay danielmi...@gmail.com wrote: On Fri, Nov 8, 2013 at 1:45 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Good to know! The GDB stack traces leave something to be desired, though - e.g. the way it reports closures isn't really very useful (adding source file name and line number would be really good there). But it is certainly better than nothing. Thanks! Rust only has boxed (type erased) closures so there's no source data to associate with them. They're a function pointer and some data to go along with it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Abandoning segmented stacks in Rust
Added https://github.com/mozilla/rust/issues/10350 then :-) On Fri, Nov 8, 2013 at 9:00 AM, Daniel Micay danielmi...@gmail.com wrote: On Fri, Nov 8, 2013 at 1:59 AM, Daniel Micay danielmi...@gmail.comwrote: On Fri, Nov 8, 2013 at 1:52 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: How bad would it be to add another 64 bits to the some data to go along with it part? I'm assuming 32 bit for file name index in some table and 32 bit for the line number in the file should be enough :-) In debug builds, no problem at all. It would mean updating all code doing transmutes of closures and the code generation for them though. On second thought... it does seem like if the debug data can be associated with functions, it's available for function pointers to them. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] struct def
I would think: let mut ps = *Points* {xs:~[1], ys:~[1]}; let mut ps : *Pointsuint* = *Points* {xs:~[1], ys:~[1]}; In Haskell-speak, there is a different between the type and the constructor, even though by convention they are given the same name. On Wed, Nov 6, 2013 at 9:46 AM, spir denis.s...@gmail.com wrote: I can write this: struct Points {xs:~[uint], ys:~[uint]} fn main () { let mut ps = Points{xs:~[1u], ys:~[1u]}; ... } But I cannot write that: struct PointsT {xs:~[T], ys:~[T]} fn main () { let mut ps = Pointsuint{xs:~[1u], ys:~[1u]}; ... } In the second case, I get the error: sparse_array.rs:106:31: 106:32 error: expected one of `; }` but found `:` sparse_array.rs:106let mut ps = Pointsuint{xs:~[1u], ys:~[1u]}; ^ Sorry to bother you with that, I find myself unable to find the right syntactic schema (and could not find any example in any doc online). I'm blocked, stupidly. spir@ospir:~$ rust -v rust 0.8 host: x86_64-unknown-linux-gnu Also, I have a general problem with writing struct instances with the type apart; meaning, without any type param, I get the same error: struct Points {xs:~[uint], ys:~[uint]} fn main () { let mut ps : Points = {xs:~[1], ys:~[1]}; ... } == parse_array.rs:106:28: 106:29 error: expected one of `; }` but found `:` sparse_array.rs:106let mut ps : Points = {xs:~[1], ys:~[1]}; ^ More generally, I don't know why there are 2 syntactic schemas to define vars. I would be happy with the latter alone (despite the additional pair of spaces) since it is more coherent and more general in allowing temporalily uninitialised declarations. Denis ___ 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] The let keyword
I didn't consider that; `pattern := expression` would require infinite lookahead in the parser, I guess. Good point. Thanks! On Wed, Nov 6, 2013 at 8:56 PM, Patrick Walton pcwal...@mozilla.com wrote: `let` tells the parser that there's a pattern coming up. Languages that do 'x := whatever' can never have destructuring without some sort of cover grammar hack. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Separating heaps from tasks
ARCs have their place, sure! But letting it leak isn't acceptable in my case. Instead, in my use case, no deletes until the whole heap is released makes way more sense (heaps are small, grow a bit, and get released). Since the lifetime of the object becomes == the lifetime of the heap, there's no issue with cycles. There's only an issue with multiple mutations, which like I said only needs a bit per pointer (and a non-atomic one at that as each heap is accessed by one thread - the only thing that gets sent between tasks is the whole heap!). So... different use cases, different solutions. ARC is a different trade-off. I guess the right thing to do would be to implement some sufficiently smart AppendOnlyHeapT pointer, but this seems hard to do (same heap can hold objects of multiple types, etc.) so for now I have some AlmostSafeHeapPointerT instead :-( Language support for heaps-separate-from-tasks would have solved it (and a bit more)... On Mon, Nov 4, 2013 at 8:32 AM, Daniel Micay danielmi...@gmail.com wrote: On Mon, Nov 4, 2013 at 1:29 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Even if RC allowed cycles (I don't quite see how...) the whole thing wouldn't be send-able, unless one uses ARC. But ARC has even more performance penalties than RC... And doing cycle-supporting ARC across tasks seems like pushing it - you might as well admit you are doing global GC in the 1st place. It can't support ownership cycles but it can certainly support cyclic links like `std::shared_ptr` + `std::weak_ptr` in C++. The performance penalty for supporting sends between tasks is atomic reference counting and the price for supporting weak pointers is an extra word per box. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Separating heaps from tasks
Essentially, yes. On Mon, Nov 4, 2013 at 11:59 AM, Huon Wilson dbau...@gmail.com wrote: On 04/11/13 20:09, Oren Ben-Kiki wrote: ARCs have their place, sure! But letting it leak isn't acceptable in my case. Instead, in my use case, no deletes until the whole heap is released makes way more sense (heaps are small, grow a bit, and get released). Since the lifetime of the object becomes == the lifetime of the heap, there's no issue with cycles. There's only an issue with multiple mutations, which like I said only needs a bit per pointer (and a non-atomic one at that as each heap is accessed by one thread - the only thing that gets sent between tasks is the whole heap!). So... different use cases, different solutions. ARC is a different trade-off. I guess the right thing to do would be to implement some sufficiently smart AppendOnlyHeapT pointer, but this seems hard to do (same heap can hold objects of multiple types, etc.) so for now I have some AlmostSafeHeapPointerT instead :-( Language support for heaps-separate-from-tasks would have solved it (and a bit more)... Is this essentially an arena allocator where one can transfer the whole arena and all the objects allocated in it into another task? ___ 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] Abandoning segmented stacks in Rust
Note that as memory becomes cheaper and larger there will be more pressure on 64-bit OS-es to switch to large pages; the number of pages needed to map several GBs of memory today is already getting out of hand, causing TLB misses to become a performance issue in some cases - imagine a system with 0.xTBs of memory and it becomes ludicrous. So playing tricks with MMU and lazy page loading may not work as well as it does with today's the small 4K page size. Of course, Rust is hardly the only platform that would be affected :-) and ideally, it would be possible to have more flexibility than today in choosing which page sizes are used where in the program's address space... but it remains to be seen how exactly this would play out. Just a point to keep in mind... On Tue, Nov 5, 2013 at 4:21 AM, Brian Anderson bander...@mozilla.comwrote: Instead of segmented stacks we're going to rely on the OS and MMU to help us map pages lazily. Although the details aren't clear yet, I expect that on 64-bit platforms the number of concurrent tasks will be comparable to using segmented stacks. On 32-bit platforms, with their limited address space, the situation will not be as good, but this is a calculated risk that we can live without the same amount of concurrency there. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Separating heaps from tasks
I am toying with a non-trivial Rust project to get a feel for the language. There's a pattern I keep seeing in my code which isn't easy to express in Rust. I wonder what the right thing to do is here. The pattern is as follows. I have some container, which contains some components of different types. The container as a whole is send-able . The components form a complex graph (with cycles). What I'd like to do is something like this: - Declare a pool of objects of some types, which is held by the container. - Declare pointer-to-object whose scope is the container; that is, the lifetime of the pointer is the lifetime of the container. The pointer can be freely passed around, cloned, etc. but (for mutable objects), only one mutable access is allowed at a time. This calls for something between GC pointers and RC pointers. GC is out, because it isn't send-able. RC is out, because it doesn't allow for loops. So right now I use explicit pools and a semi-safe (that is, unsafe...) smart pointer type. And I don't support dropping objects until the whole container is done (which is OK in my specific app but isn't really a good solution). Ideally what I'd like to see is separating heaps from tasks. That is, suppose that GC pointers had a heap attribute (like borrowed pointers have a lifetime attribute). By default, each task has a heap, but it is also possible to define additional heaps (like we have the static lifetime and can also define additional lifetimes). So, the container could hold a heap and then many components with heap-scoped pointers. The whole thing is send-able and GC is done in the scope of each heap on its own (like today). There are implications on the type system (no mixing pointers between different heaps, unless the heaps are nested) - this seems very similar to the lifetimes type checking... Overall this seems very symmetrical with lifetimes. Basically, lifetimes == static (compile-time computable) free/malloc; heaps == dynamic (run-time computable) free/malloc. One interesting pattern allowed by this is ad-hoc actors (there are others of course). Currently, if one wants to write actor-style code, one ties in the GC pointers to one heap of one actor, which means one forces the parallelization policy to one task per actor. One could argue that the run-time should be good enough that any aggregation of actor threads to OS threads would be done optimally (which is a good goal); but in some apps, to get good performance one would like to control this. If we could separate heaps from tasks, we could spawn fewer tasks (roughly the number of OS threads) and use application code to decide which actor runs when and where (e.g., in combination with thread affinity to ensure better cache locality). At any rate - is this something that makes sense in the Rust view? If so, is there a chance of something like that being added (a completely separate question :-)? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Separating heaps from tasks
Yes, using keys (or indices into a vector) is an option. There are two problems with this. It is pretty inefficient; one has to access the pool at any point, which means doubling the sizes of the pointers (at least), probably more; One needs a lot of unsafe code to allow mutating the pools; And there's the issue of keeping multiple pools (one per type)... So it gets complex fast, though perhaps a sufficiently smart library could still do a good job? On Mon, Nov 4, 2013 at 8:18 AM, Daniel Micay danielmi...@gmail.com wrote: On Mon, Nov 4, 2013 at 1:11 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: I am toying with a non-trivial Rust project to get a feel for the language. There's a pattern I keep seeing in my code which isn't easy to express in Rust. I wonder what the right thing to do is here. The pattern is as follows. I have some container, which contains some components of different types. The container as a whole is send-able . The components form a complex graph (with cycles). If there are keys, the path of least resistance is to use a map or a pair of maps. Reference counting can allow cyclic links in data structures as long as the ownership graph is acyclic, but Rust doesn't offer a type like this at the moment. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Separating heaps from tasks
Even if RC allowed cycles (I don't quite see how...) the whole thing wouldn't be send-able, unless one uses ARC. But ARC has even more performance penalties than RC... And doing cycle-supporting ARC across tasks seems like pushing it - you might as well admit you are doing global GC in the 1st place. On Mon, Nov 4, 2013 at 8:20 AM, Patrick Walton pcwal...@mozilla.com wrote: On 11/3/13 10:19 PM, Oren Ben-Kiki wrote: Because they don't allow cycles. Aha. I personally think we should relax this restriction; it's pretty onerous. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC about std::option and std::result API
I would love it if '?' was allowed at the end of any identifier, to make it natural to name boolean variables, methods, constants, etc. Having to say is_xxx is ugly IMO. A lint option ensuring this is only applied to boolean typed constructs could help reduce abuse, if this is seen as an issue. On Nov 2, 2013 8:02 AM, Steve Klabnik st...@steveklabnik.com wrote: Would a ruby-style ok?/ok work to replace is_ok/ok? ___ 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] This Week in Rust
Indeed. It is invaluable in helping me decide when to pull a new master and be prepared for what I need to fix in my code. Many thanks for doing this! On Tue, Oct 29, 2013 at 10:51 AM, Gaetan gae...@xeberon.net wrote: +1 I just subscribed yesterday and I really appreciates this overview :) - Gaetan 2013/10/29 Jack Moffitt j...@metajack.im I just wanted to thank you for the This Week in Rust notes. I love reading them and I am sure that I am not the only one who appreciates the effort that you put into each one. +1! These are great. They are the easiest way for us on the Servo team to estimate how much work we'll need to do to upgrade. jack. ___ 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] recursive types
I assume the compiler suggests you replace @Expr with RcExpr (Rc is defined in std::rc). This means you wouldn't be able to create cycles (that is, expressions must form a tree, or at most a DAG), and that there would be the overhead of reference counting when you create new expressions, clone the pointers to them etc.; on the other hand, there wouldn't be any GC involved. On Mon, Oct 28, 2013 at 6:40 PM, Ramakrishnan Muthukrishnan vu3...@gmail.com wrote: Hello rust hackers, In section 8.1.7 of the Rust manual (Recursive types), there is an example of a List definition which is recursive. Here I define a very simple arithmetic expression which consists of numbers and add expressions. When I compile it I get errors.. enum Expr { Num(int), Add(@Expr, @Expr), } fn eval(e: Expr) - int { match e { Num(x) = x, Add(x, y) = eval(x) + eval(y), } } fn main() { println(format!(eval 2 = {:d}, eval(Num(2; println(format!(eval 2 + 3 = {:d}, eval(Add(Num(2), Num(3); } $ rustc arith.rs arith.rs:4:8: 4:13 error: The managed box syntax may be replaced by a library type, and a garbage collector is not yet implemented. Consider using the `std::rc` module as it performs much better as a reference counting implementation. arith.rs:4 Add(@Expr, @Expr), ^ arith.rs:4:8: 4:13 note: add #[feature(managed_boxes)] to the crate attributes to enable arith.rs:4 Add(@Expr, @Expr), ^ arith.rs:4:15: 4:20 error: The managed box syntax may be replaced by a library type, and a garbage collector is not yet implemented. Consider using the `std::rc` module as it performs much better as a reference counting implementation. arith.rs:4 Add(@Expr, @Expr), ^ arith.rs:4:15: 4:20 note: add #[feature(managed_boxes)] to the crate attributes to enable arith.rs:4 Add(@Expr, @Expr), ^ error: aborting due to 2 previous errors I am running rust from master. What exactly is the compiler suggesting me to do? How can `std::rc' module help in this situation? TIA -- Ramakrishnan ___ 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] recursive types
Right, it would have to be @mut Expr to allow for cycles... and you'd have to really work hard to construct the cycle. At any rate, this isn't what you'd want - very probably just using ~Expr would be enough. On Mon, Oct 28, 2013 at 8:29 PM, Daniel Micay danielmi...@gmail.com wrote: On Mon, Oct 28, 2013 at 2:27 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: If you use ~Expr instead of @Expr, then the expressions would have to form a tree (A = B + C). If you use RcExpr, you could build a DAG (A = B + B). With @Expr (if that worked), in principle you could allow for cycles (A = B + A), which is probably not what you want. You won't actually be able to create cycles with @T unless T is non-Freeze because it's immutable and Rust doesn't use laziness. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] return type of closure
Off the top of my head, I'd take out the in front of the |x| everywhere, it seems like you are borrowing a pointer out of something that is already a borrowed pointer to a function (expected , found , you have one too many, right? :-). On Sun, Oct 27, 2013 at 2:15 PM, Ramakrishnan Muthukrishnan vu3...@gmail.com wrote: I am having a hard time trying to figure out what is going on here. fn ntimes(f: fn(int) - int, n: int) - fn(int) - int { match n { 0 = |x| { x }, _ = |x| { f(x) }, _ = |x| { let nf = ntimes(f, n - 1); nf(f(x)) }, } } fn double(a: int) - int { a * 2 } fn main() { let quadruple = ntimes(double, 2); println(format!(quad = {:d}, quadruple(2))); } When I compile it, I get this error message: $ rustc --version rustc 0.9-pre (950add4 2013-10-26 02:16:08 -0700) host: x86_64-apple-darwin $ rustc fn1.rs fn1.rs:2:4: 10:5 error: mismatched types: expected `fnno-bounds(int) - int` but found `fnno-bounds(int) - int` (expected fn but found -ptr) fn1.rs:2 match n { fn1.rs:3 0 = |x| { x }, fn1.rs:4 _ = |x| { f(x) }, fn1.rs:5 _ = |x| fn1.rs:6 { fn1.rs:7 let nf = ntimes(f, n - 1); ... error: aborting due to previous error task 'unnamed' failed at 'explicit failure', /Users/rkrishnan/src/rust/src/libsyntax/diagnostic.rs:101 task 'unnamed' failed at 'explicit failure', /Users/rkrishnan/src/rust/src/librustc/rustc.rs:396 Can someone help me understand what is going on here? I tried omitting the return type of ntimes and let compiler try to infer the type. The only change is in the first line of the code omitting the return type of ntimes. But I then get an error about quadruple function. It says that quadruple is a void. Thanks. -- Ramakrishnan ___ 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] return type of closure
You got me there... On Sun, Oct 27, 2013 at 6:04 PM, Ramakrishnan Muthukrishnan vu3...@gmail.com wrote: On Sun, Oct 27, 2013 at 6:12 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Off the top of my head, I'd take out the in front of the |x| everywhere, it seems like you are borrowing a pointer out of something that is already a borrowed pointer to a function (expected , found , you have one too many, right? :-). Yes, I had tried that too but get cannot infer an appropriate lifetime due to conflicting requirements errors. Is there some way to fix that? Ramakrishnan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
This is a good summary of the situation. There's one more twist to it though; I not only want both ownership and aliasing, I also want send-ability. That is, it should be possible to send the whole arena to another task. I think this rules out option 1 (though I don't know enough about lifetimes to be sure). It leaves option 2 on the table, though. The main problem with option 2 is that if one borrows a mutable pointer to `root.poolOfSomeObjects[someIndex]` then the whole `root` is now considered to be borrowed-as-mutable, disallowing borrowing a mutable pointer to `root.poolOfOtherObjects[otherIndex]`. I'm tempted to say that the type system should be smart enough to allow this, but I'm not 100% certain it is actually safe to do so without some run-time support. For now I am going with (3) which is using an UnsafePtr struct and scary comments :-( On Fri, Oct 25, 2013 at 7:05 PM, Niko Matsakis n...@alum.mit.edu wrote: On Mon, Sep 30, 2013 at 08:10:45PM +0300, Oren Ben-Kiki wrote: That's good! But there remains the fact that there's no way to say my lifetime is the same as the struct that contains me. If 'self specialness goes away, perhaps it can be re-introduced to mean that (or a different name can be given to it). So, I have had this thread on a must read list of e-mails for a while, but didn't get around to it until just now. Sorry about that. It is true that there is no way to have a lifetime that means as long as the current struct -- at least not in a type definition. The reason for this is that this is not a well-defined thing; structs can be moved, for example. The only place you can get a lifetime like that is in a method: fn foo'a('a mut self, ...) Here, 'a is the lifetime you are looking for (the current lifetime of the struct itself). We do have a way to express the notion of memory that moves with a struct and is freed when the struct is freed: ownership. That's what a `~` pointer is for. But of course the `~` pointer is designed for recursive ownership and transfers and thus prevents aliasing, which may not be what you need. Sometimes you want ownership and aliasability: basically you want to be able to create a subcomponent tied to a struct that will never itself be moved out of the struct into some other container. You can imagine doing this by having an arena that moves with the struct, and pointers that live as long as that arena. I had originally hoped to support this (that was indeed the origin of the 'self name) but it's quite complex to do so; that lifetime is a kind of existential lifetime and we don't really have a good way to capture it. In the meantime, you have two options: 1. Parameterize the struct with a lifetime, and have it contain the arena that way. This technique works when there is ultimately some master stack frame that the struct will not outlive; this master frame owns the arena, and the struct just borrows it. You can see an example in this (yet to be landed) code. [1] 2. Have the struct own a vector or other data structure, and replace pointers with indices. This works best when the struct will be moved around. You can see an example in this Graph data structure. [2] While I know that neither technique feels perfect, they are quite workable, and I have used both with much rejoicing. Niko [1] https://gist.github.com/nikomatsakis/7157110 [2] https://github.com/mozilla/rust/blob/master/src/librustc/middle/graph.rs ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] What does `once fn` mean?
I have code which (greatly simplified) boiled down to: ``` fn attempt_1T(action: fn() - T) - T { action() } fn call_attempt_1() - ~str { let mut index = 0; let string = ~str; do attempt_1 { // No problem here. We have a stack closure. index += 1; // Error: cannot move out of captured outer variable // Makes sense. Compiler can't tell the action will only be invoked // once. string } } ``` So, I heard there are things called `once fn`, which seem to be what I need. Even though the compiler warned me away from them, I thought I'd give them a try in the spirit of investigation: ``` fn attempt_2T(action: once fn() - T) - T { action() } fn call_attempt_2() - ~str { let mut index = 0; let string = ~str; do attempt_2 { // Error: cannot assign to immutable captured outer variable in a heap closure // It seems that `once fn` is a _heap_ closure? Makes no sense... It // would have made sense if it was an `~once fn`, but there's no way // that `action_2` should be able to store somewhere a reference to an // `once fn`, so a stack closure should be fine! index += 1; string } } ``` So, obviously `once fn` doesn't do what I expected it to do, which is to simply assert this fn is only called once. It seems it does that but also carries some extra baggage of also saying force me to be a heap closure. It isn't clear to me _why_ these two should be conflated - after all, one could just say `~once fn` if one wanted a heap closure. Can someone enlighten me on this? At any rate, I then resorted to: ``` fn attempt_2T(action: fn() - T) - T { action() } fn call_attempt_2() - ~str { let mut index = 0; let string = ~str; let string_cell = Cell::new(string); do attempt_1 { // No problem here. We have a stack closure. index += 1; // Dynamic assertion that the action is only invoked once. Costs in // both extra ugly source code lines and in run-time overhead. string_cell.take() } } ``` So, this works, but boy is it ugly, not to mention inefficient Can someone suggest a better way to achieve this, and shed some light on the status of the `once fn` construct in general? Thanks, Oren Ben-Kiki ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Strange behavior about Writer trait
I'm not sure I follow. Assuming that the trait `T` has no method that uses `Self`, then any `impl` requiring `T` should happily accept an `T` / `@T`. Why penalize non-self-referential traits (like `Writer`), just because some traits (like `AdderIncr`) are self-referential? On Sun, Oct 20, 2013 at 1:10 AM, Steven Blenkinsop steven...@gmail.comwrote: Consider this program: trait AdderIncr { fn add(self, x: Self) - Self; fn incr(mut self); } impl AdderIncr for int { fn add(self, x: int) - int { *self + x } fn incr(mut self) { *self += 1; } } fn incrAdd(x: mut AdderIncr, y: mut AdderIncr) { x.incr(); x.add(y); } fn main() {} It fails to compile: Documents/test.rs:13:1: 13:10 error: cannot call a method whose type contains a self-type through an object Documents/test.rs:13x.add(y); ^ The Self type is meaningless in object methods, since I have no way to ensure that y has the same underlying type as x. Thus, only a subset of the methods of a trait are available on the corresponding object, which means that objects can't automatically implement their corresponding trait. That means any impls that implement a trait for all types that implement AdderIncr, for example, won't implement that trait for AdderIncr, since AdderIncr doesn't implement AdderIncr. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
Coming from a functional programming perspective, it would still be very nice indeed to easily pipeline a series of functions (not methods). The current method of requiring defining a new trait (with possibly just one impl!) just to be able to use the `.` syntax means discouraging functional style in favor of OO style. If it is impossible to allow for `foo.bar(baz)` to be the same as `bar(foo, baz)`, without giving up on the OO-like behavior (is it, really?), is there any chance of introducing a whole new operator (such as `|`) to do the trick (as in `foo | bar(baz)`)? See for example Elixir, which provides both a magic `.` OO-ish method dispatch and also a function-ish pipelining `|` operator. On Sun, Oct 20, 2013 at 6:11 PM, Marijn Haverbeke mari...@gmail.com wrote: I want to add that we did initially have a scheme where you have to import every impl you used (not every method), and that this was abandoned because it was burdensome and, in typical situations, completely redundant. Another problem with this proposal seems that it does away with the possibility of explicitly grouping a bunch of methods that make up the implementation of an interface. Implementing interfaces go-style, by just happening to have implemented all the methods that make up the interface, seems inappropriate for a language where interfaces aren't structural. So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). Best, Marijn ___ 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] Strange behavior about Writer trait
I run into the following problem (the code below is a toy example). ``` use std::io::Writer; // Makes no difference if added/removed. trait PrintWithSpice { fn print(self, writer: Writer, spice: bool); } struct Bar { bar: ~PrintWithSpice, } impl Bar { pub fn print(self, writer: Writer) { self.bar.print(writer, false); Bar::print_via_borrowed(writer, self.bar); } fn print_via_borrowed(writer: Writer, data: PrintWithSpice) { // Invoking the `print` function via the borrowed pointer to the `PrintWithSpice` trait: // Works fine, as expected.. data.print(writer, true); } } struct Foo { foo: bool } impl PrintWithSpice for Foo { fn print(self, writer: Writer, spice: bool) { // Invoking the `write_str` function via the borrowed pointer to the `Writer` trait: // error: failed to find an implementation of trait std::io::Writer for std::io::Writerno-bounds // What is going on? writer.write_str(format!(foo: {:b} spice: {:b}, self.foo, spice)); } } ``` I didn't understand what the compiler is complaining about. failed to find an implementation of Foo for Foono-bounds? A Foo is a Foo, no? Calling a function via a borrowed pointer to a trait should just work (it does a few lines above). After digging I discovered what the compiler really meant (I think). The `write_str` method is defined for `WriterUtils` rather than for `Writer`. So, if I replace `Writer` by `WriterUtil` in the above code, it compiles fine. So, I ended up defining `trait MyWriter: Writer + WriterUtil` and I am using that instead of `Writer` all over my code. I can see doing that as a workaround, but it doesn't smell right to me. So: * Why is the compiler complaining about not finding an implementation for `Writer` when the method I invoke is from `WriterUtil`? * Since there is an `implT: Writer for WriterUtil`, shouldn't the compiler be sufficiently smart to deduce that the code is valid in the 1st place? * Until the compiler is sufficiently smart (or, if there is a good reason why it would never be), shouldn't we rename `Writer` to `BasicWriter` and define `trait Writer: BasicWriter, WriterUtil {}` so `Writer` would become more usable? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Strange behavior about Writer trait
Ugh, I was too optimistic. Yes, I can write my code using `MyWriter`, but I can't cast any @Writer (such as `io::stdout()`) to it. I guess I should just use `@Writer` everywhere for now :-( This raises the question of how come the compiler is smart enough to figure out a `@Writer` has the trait `WriterUtil`, but isn't smart enough to figure out a `Writer` has the trait... On Sat, Oct 19, 2013 at 9:08 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: I run into the following problem (the code below is a toy example). ``` use std::io::Writer; // Makes no difference if added/removed. trait PrintWithSpice { fn print(self, writer: Writer, spice: bool); } struct Bar { bar: ~PrintWithSpice, } impl Bar { pub fn print(self, writer: Writer) { self.bar.print(writer, false); Bar::print_via_borrowed(writer, self.bar); } fn print_via_borrowed(writer: Writer, data: PrintWithSpice) { // Invoking the `print` function via the borrowed pointer to the `PrintWithSpice` trait: // Works fine, as expected.. data.print(writer, true); } } struct Foo { foo: bool } impl PrintWithSpice for Foo { fn print(self, writer: Writer, spice: bool) { // Invoking the `write_str` function via the borrowed pointer to the `Writer` trait: // error: failed to find an implementation of trait std::io::Writer for std::io::Writerno-bounds // What is going on? writer.write_str(format!(foo: {:b} spice: {:b}, self.foo, spice)); } } ``` I didn't understand what the compiler is complaining about. failed to find an implementation of Foo for Foono-bounds? A Foo is a Foo, no? Calling a function via a borrowed pointer to a trait should just work (it does a few lines above). After digging I discovered what the compiler really meant (I think). The `write_str` method is defined for `WriterUtils` rather than for `Writer`. So, if I replace `Writer` by `WriterUtil` in the above code, it compiles fine. So, I ended up defining `trait MyWriter: Writer + WriterUtil` and I am using that instead of `Writer` all over my code. I can see doing that as a workaround, but it doesn't smell right to me. So: * Why is the compiler complaining about not finding an implementation for `Writer` when the method I invoke is from `WriterUtil`? * Since there is an `implT: Writer for WriterUtil`, shouldn't the compiler be sufficiently smart to deduce that the code is valid in the 1st place? * Until the compiler is sufficiently smart (or, if there is a good reason why it would never be), shouldn't we rename `Writer` to `BasicWriter` and define `trait Writer: BasicWriter, WriterUtil {}` so `Writer` would become more usable? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Strange behavior about Writer trait
Hmmm That sounds strange. Shouldn't `obj: T` allow me to invoke `obj.method_of_T()`? For example, how did I manage to invoke the `data.print(...)` method via the borrowed `data: PrintWithSpice` pointer? Automatic dereference? And if so, why didn't it work for `Writer` as well? On Sat, Oct 19, 2013 at 9:29 AM, Steven Fackler sfack...@gmail.com wrote: If T is a trait, its trait objects ~T, @T and T do not implement T. There is an implementation of Writer for @Writer, but not for ~Writer or Writer which is why you're seeing that error. Steven Fackler On Fri, Oct 18, 2013 at 11:27 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ugh, I was too optimistic. Yes, I can write my code using `MyWriter`, but I can't cast any @Writer (such as `io::stdout()`) to it. I guess I should just use `@Writer` everywhere for now :-( This raises the question of how come the compiler is smart enough to figure out a `@Writer` has the trait `WriterUtil`, but isn't smart enough to figure out a `Writer` has the trait... On Sat, Oct 19, 2013 at 9:08 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: I run into the following problem (the code below is a toy example). ``` use std::io::Writer; // Makes no difference if added/removed. trait PrintWithSpice { fn print(self, writer: Writer, spice: bool); } struct Bar { bar: ~PrintWithSpice, } impl Bar { pub fn print(self, writer: Writer) { self.bar.print(writer, false); Bar::print_via_borrowed(writer, self.bar); } fn print_via_borrowed(writer: Writer, data: PrintWithSpice) { // Invoking the `print` function via the borrowed pointer to the `PrintWithSpice` trait: // Works fine, as expected.. data.print(writer, true); } } struct Foo { foo: bool } impl PrintWithSpice for Foo { fn print(self, writer: Writer, spice: bool) { // Invoking the `write_str` function via the borrowed pointer to the `Writer` trait: // error: failed to find an implementation of trait std::io::Writer for std::io::Writerno-bounds // What is going on? writer.write_str(format!(foo: {:b} spice: {:b}, self.foo, spice)); } } ``` I didn't understand what the compiler is complaining about. failed to find an implementation of Foo for Foono-bounds? A Foo is a Foo, no? Calling a function via a borrowed pointer to a trait should just work (it does a few lines above). After digging I discovered what the compiler really meant (I think). The `write_str` method is defined for `WriterUtils` rather than for `Writer`. So, if I replace `Writer` by `WriterUtil` in the above code, it compiles fine. So, I ended up defining `trait MyWriter: Writer + WriterUtil` and I am using that instead of `Writer` all over my code. I can see doing that as a workaround, but it doesn't smell right to me. So: * Why is the compiler complaining about not finding an implementation for `Writer` when the method I invoke is from `WriterUtil`? * Since there is an `implT: Writer for WriterUtil`, shouldn't the compiler be sufficiently smart to deduce that the code is valid in the 1st place? * Until the compiler is sufficiently smart (or, if there is a good reason why it would never be), shouldn't we rename `Writer` to `BasicWriter` and define `trait Writer: BasicWriter, WriterUtil {}` so `Writer` would become more usable? ___ 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] Unified function/method call syntax and further simplification
Interesting idea; in that case, one could string together any series of functions - basically, `.` would become the equivalent of `|` (or whatever other name you want to call it). That is, instead of writing `baz(bar(foo(x), y), z)` one could write `foo(x).bar(y).baz(z)`. This would make it easier to write things in functional style, using the same syntax as the object style. It could be viewed as the natural complement for the `do` keyword, which adds a last block parameter to the end of the function. I'm less certain about giving up `impl Foo { ... }`, though - that is useful for logically grouping, documenting and accessing functions (as in `Foo::foo(...)`). But it seems we don't have to give it up, just make it optional? On Sat, Oct 19, 2013 at 3:47 PM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: I see no reason for the restriction of self. Why not simply say that any function can be called with first_arg.func(...) style ? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Proposal for macro invocation sugar
That does make sense. Well, this still leaves the `foo!!` proposal as viable, and a possible solution for https://github.com/mozilla/rust/issues/9358 - so, +1 for that. On Thu, Oct 17, 2013 at 9:29 AM, Marvin Löbel loebel.mar...@gmail.comwrote: As I understand it, there is a high incentive to have macros be tokenizable and parseable without needing to expand them - it's a necessarily if we ever want importable macros (Can't resolve macro imports if you can't parse the source). Hence the requirement to have explicit brackets and the need to have properly nested and paired brackets in them. On 10/17/2013 06:30 AM, Oren Ben-Kiki wrote: In general I'd favor anything that would help with https://github.com/mozilla/rust/issues/9358 - that is, allow more eDSL-ish macros. Writing `foo!!(...) { ... }` has the cost of the extra `!` but that really isn't too bad. That said, I wonder why do macro invocations require the outer set of parenthesis? Since a macro is expressed in terms of parser rules (expressions, identifiers, tokens, etc.), isn't it unambiguous to allow macros to be invoked without the outer `()`? E.g.: macro_rules! foo ( (bar: $expr :: baz: $expr) = ..., ) Today, one would use it as in `f(foo!(1 :: 2), 3)`. But suppose one could somehow indicate the outer `()` were never to be used for this macro (say writing `syntax_rules!` instead of `macro_rules!`, or by some other extension of the `macro_rules!` notation), then parsing `f(foo! 1 :: 2, 3)` would be unambiguous - assuming we (1) strictly use greedy parsing of $expr etc. and (2) always expand a later macro before parsing and expanding earlier macros, where later and earlier are in source text order. This strategy makes irrelevant the issue of determining the nesting of such macros while doing the right thing with a simple deterministic rule. This would probably be more complex to implement than the multiple-`!` proposal, but would allow for more generic patterns. For example, allowing to omit the outer `()` would allow invoking `my_match! pattern = action`; if I understand it correctly, using `!!` would only allow for writing `my_match!! pattern action`. At any rate, this is just as an idea - like I said, I'd like anything that would allow me to write `foo!(...) { ... }` (or `foo!!(...) { ... }`, or something along these lines). Writing `foo!(..., { ... })` just seems ugly to me... On Thu, Oct 17, 2013 at 2:10 AM, Marvin Löbel loebel.mar...@gmail.comwrote: Hello! I was thinking a bit about macros, and I had an idea for a kind of syntactic sugar that might be useful to have. I also posted this to the issue tracker at https://github.com/mozilla/rust/issues/9894. # Current situation Right now, rust knows about two kinds of macro invocation: IDENT!(...) IDENT! IDENT (...) The latter one is just used by `macro_rules!` right now, and seems kinda out of place because of that. Additionally, just being restricted to `IDENT!(...)` means that, while you can define macros just fine, the resulting invocation syntax often looks a bit weird because of the need for the outer `()` pair. For example, if you want to write some kind of custom `match` macro you ideally want a syntax like `macro! EXPR { CASES... }`, but in practice are forced to decide between redundant, deeply nested brackets or weird syntax if you want to reduce the brackets: ~~~ my_match!( foo().bar().baz() { case 1 = ... case 2 = ... ... } ) my_match!(foo().bar().baz() cases: case 1 = ... case 2 = ... ... ) ~~~ # Proposal We can't just allow macros to accept different syntax like `IDENT! EXPR ( ... )`, because it would create ambiguity in the parser, but it occurred to me that we _can_ provide syntactic sugar for transforming 'nicer looking' variants into the regular `IDENT!(...)` syntax. Basically, I'm thinking of leveraging the bang in a macro invocation to annotate how many following bracket pairs to group into one regular macro invocation: ~~~ IDENT!! (...) (...) = desugaring = IDENT!((...) (...)) IDENT!!! (...) (...) (...) = desugaring = IDENT!((...) (...) (...)) ... etc ~~~ The number of bangs could become confusing fast, but I don't expect that macros with more than two bracket groups are going to be common. And because it would just be sugar, you could always write it as the regular form. # Advantages There are a number of advantages I see with this proposal: 1. The two macro invocation forms can be folded into one: ~~~ IDENT!(...)= IDENT!(...) IDENT! IDENT (...) = IDENT!! (IDENT) (...) == IDENT!((IDENT) (...)) ~~~ 2. Custom syntax can become nicer looking, especially for control structures. Looking at the `my_match` example: ~~~ my_match!! (foo().bar().baz()) { case 1 = ... case 2 = ... ... } ~~~ ... which looks more natural than any
Re: [rust-dev] what is stable, what is likely to change, in Rust
Is there any published roadmap for the reasonable time frame? The last quotes I saw when searching were ancient and optimistically hoped that Rust will hit 1.0 by the end of this year :-). Is there a goal of reaching 1.0 at some rough time frame or is Rust going for it will be done when it is done? I'm not pushing for either, they both have their dis/advantages - but it would be nice to be explicit about it either way. On Wed, Oct 2, 2013 at 8:10 PM, Alex Crichton a...@crichton.co wrote: It is my understanding that there aren't a whole lot of portions of the libraries/compiler which are 100% guaranteed to not change from here on out. There are still fairly large language changes in flight (dynamically sized types, closure reform, etc.) which could have large impacts on how the language is used. In addition to a the language stabilizing, there's also the factor of libraries stabilizing. Huon's recent work on adding stability attributes is a fantastic step in this direction though. As Rust moves forward, the general strategy for us is to first enforce usage of the stability attributes to prevent regressions in terms of stability (stable functions calling unstable ones, etc.). After these safeguards are in place, the plan is to closely scrutinize the core modules of libstd. From the inside out, interfaces will be pruned/refactored and flagged as #[stable]. Once an interface is #[stable], the idea is to be very reluctant to accept modifications to existing functions, and functions/modules flagged as such can be thought of as being backwards compatible for the time being at least. That being said, I've got a fairly large side project which has been compiling just fine (without modifications) for nearly a month now which is truly a record for rust. The rate of change in the language is far less than it used to be, and library APIs are settling down a little but, but they're still predominately in flux. As usual, Rust is not currently in a backwards compatible state for nearly its entire surface area (except for maybe the program fn main() {}), but it's certainly a major goal to achieve this within a reasonable time frame. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] The new format!
I just transitioned my code to use the new format! macros. I was happy to get rid of all the .to_str() I had all over the place, but this turned out not quite as I had expected. I was hoping I'd be able to simply base on the ToStr trait to print anything with {:s}. It turns out that actually there's a String trait with an fmt function - Ok, that makes sense, as one can emit stuff piecewise without having to pay the costs of creating an intermediate complete string. But it turns out that the standard library hard-wires the implementation of the String trait to use the Str trait, which has two functions - to_owned and as_slice. I understand the motivation of as_slice for more efficient formatting (though I don't see why it needs to provide to_owned, but anyway). Ok, just a bit more boilerplate, I thought - but then I hit a wall. The as_slice function requires returning a borrowed pointer whose lifetime is specified by the caller. If my type has to_str which returns a ~str, I can't really return a borrowed pointer to it (as the ~str will live too short). This problem is unique to the String trait. All the other traits (Bool, Pointer, ...) just allow specifying the trait directly without getting too clever with string slices. So... I cheated and added a LowerHex instance my types instead of String (which conflicts with libstd) or Str (which I can't implement). I now print my types with {:x} (I think of it as user eXtended format). I know, this is pretty horrible... what is the right thing here? Using {:s} and keep calling .to_str() everywhere? A second, related problem, is formatting simple enums. It is easy to derive ToStr for such enums, but this means I still need to say {:s} and my_enum.to_str() - exactly what I hoped to avoid. And I really don't want to manually specify a LowerHex or Str instance to each and every enum (it is bad enough I need to do it for each of the relevant small-struct types). If there was a, say, {:S} that was automatically available for everything that had ToStr, then both problems would have been solved. {:s} would remain a more efficient way to format things that were actually strings, while {:S} would allow formatting things that could be viewed as strings. Does that make sense? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The new format!
Ah, so simple. I missed it because it is not listed in the formatting traits list in the documentation. This would solve half my problem - I'd no longer need to use {:x} but use the simpler {}, which is great. Thanks! But it wouldn't solve the problem for printing enums, though. I guess I'd still have to litter my code with lots of .to_str() when printing them :-( On Tue, Oct 1, 2013 at 9:12 AM, Huon Wilson dbau...@gmail.com wrote: On 01/10/13 16:13, Oren Ben-Kiki wrote: This problem is unique to the String trait. All the other traits (Bool, Pointer, ...) just allow specifying the trait directly without getting too clever with string slices. So... I cheated and added a LowerHex instance my types instead of String (which conflicts with libstd) or Str (which I can't implement). I now print my types with {:x} (I think of it as user eXtended format). I know, this is pretty horrible... what is the right thing here? Using {:s} and keep calling .to_str() everywhere? There's std::fmt::Default, which corresponds to having no format specifier (e.g. {} or {:10} or {a}, etc). Huon __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The new format!
Perhaps if the type system was smart enough to provide a default implementation of the Default trait for everything that had the ToStr trait, and allowing overrides for specific types? I know that currently this sort of inference is not supported, but it is intended that it would be possible in the future, right? On Tue, Oct 1, 2013 at 9:24 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ah, so simple. I missed it because it is not listed in the formatting traits list in the documentation. This would solve half my problem - I'd no longer need to use {:x} but use the simpler {}, which is great. Thanks! But it wouldn't solve the problem for printing enums, though. I guess I'd still have to litter my code with lots of .to_str() when printing them :-( On Tue, Oct 1, 2013 at 9:12 AM, Huon Wilson dbau...@gmail.com wrote: On 01/10/13 16:13, Oren Ben-Kiki wrote: This problem is unique to the String trait. All the other traits (Bool, Pointer, ...) just allow specifying the trait directly without getting too clever with string slices. So... I cheated and added a LowerHex instance my types instead of String (which conflicts with libstd) or Str (which I can't implement). I now print my types with {:x} (I think of it as user eXtended format). I know, this is pretty horrible... what is the right thing here? Using {:s} and keep calling .to_str() everywhere? There's std::fmt::Default, which corresponds to having no format specifier (e.g. {} or {:10} or {a}, etc). Huon __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The new format!
Yes, both suggestions sound very reasonable. It would also eliminate the need for the Str trait altogether (since the Default fmt function would avoid the allocation). So there would really be no need for most format specifiers, except stuff like controlling the base of integers, etc. On Tue, Oct 1, 2013 at 9:30 AM, Huon Wilson dbau...@gmail.com wrote: I think we should just replace ToStr and the #[deriving] with Default and a default method .to_str() on that trait, since ToStr's current design makes it very allocation-heavy (it has to allocate a new ~str for each subfield, rather than just appending to a common buffer as using the new format infrastructure would allow). Also, not directly related to this exact discussion, but we could probably cope with having fewer format specifiers, e.g. format!({:b}, true) could just be format!({}, true), and similarly for `c`. (and even `s` itself!) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Huh, this is _exactly_ my use case. I have data structures which I grow but never shrink, and I never move anything out of them. This idiom isn't that uncommon when writing in functional style... I incrementally build a complex structure that allows quick access to the same pieces using different criteria (e.g., access a piece by a unique id, or look it up by a path, or via a direct pointer held by a related piece, etc.). All accesses are of (possibly mutable) borrowed pointers that live as long as the whole thing exist. Then when done I can discard the whole thing. Sometimes I have a less-complex structure to which I attach a related view structure. The view holds borrowed pointers to pieces of the original immutable structure, allowing efficient access in new and interesting ways. When done I can then discard the view and keep the original. So basically, I want something that gives me the freedoms granted to 'static, but only for as long as the main structure provably exists. Something like 'shadow :-) I found Rust doesn't like these idioms at all. I some cases, where I was too tired, performance wasn't an issue, and there was no need to send the whole thing between tasks, I just used @ pointers. Otherwise, I used RcMut, though this incurs boilerplate access code and hurts performance for no real reason. In critical cases I may end up using unsafe pointers... Using a macro - hmm. Interesting and if possible, would be a great solution. I'm not certain what such a macro would expand to, though. It would need to be something that would express the concept of I live only as long as my container structure _somehow_, and I thought we established that can't be done... Thanks, Oren. On Mon, Sep 30, 2013 at 4:26 AM, Steven Blenkinsop steven...@gmail.comwrote: Yeah, I was trying to come up with a design a while ago to allow intrastructural borrowed pointers, and basically the effect this had was that you could never move anything out of the datastructure since that would leave dangling pointers. Which means you could grow the structure but never shrink it, which is sort of not good. Now my thought is about whether it would be possible to make a macro which allows you to define a safely encapsulated smart node which ensures that any intrastructural references meet certain invariants about where they point within the structure, but I haven't developed the idea enough to say whether you could make something truly general this way. On Sun, Sep 29, 2013 at 7:28 PM, Steven Fackler sfack...@andrew.cmu.eduwrote: Foo can't really be used safely. Say that we have struct Bar { baz: BazPartOfBar } struct Foo { bar: Bar, baz: 'magic BazPartOfBar } And let's say we add a `self` syntax to allow field initializers to refer to other fields: let foo = Foo { bar: Bar { baz: BazPartOfBar }, baz: self.bar.baz }; We can't really do much with Foo. If we move it, foo.baz is no longer a valid reference, so that can't happen. We could modify foo.bar in this case, but not if Bar were defined as struct Bar { baz: ~BazPartOfBar } since foo.baz would point to deallocated memory if we replace self.bar or self.bar.baz. Steven Fackler On Sun, Sep 29, 2013 at 3:15 PM, Tim Kuehn tku...@cmu.edu wrote: Could you use struct methods for quick access? Or is there a reason this wouldn't fit your use case? Sorry, I haven't followed the whole thread closely. struct Owner { owned: ~[int], } impl Owner { fn quick_access'a('a mut self) - 'a mut int { mut self.owned[0] } } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
I see what you mean about the macro - it would get quite complex though. Regardless of macros, neat extensions with GC heaps and arenas and so on... I still find it surprising that it is flat-out impossible to explicitly name the default lifetime of a struct, and also that the natural name for this lifetime ('self) is used for an entirely different purpose. It would be nice if we could rename the existing 'self to something (anything :-) else, and allow 'self to be used in struct field types and elsewhere for the more natural (and currently unavailable) lifetime of the current struct. Yes, this comes with some limitations, but it is useful for some interesting cases and its lack of an explicit name seems arbitrary (it is the default in many cases, after all). At any rate, I now have a better grasp of what is going on, so I have a better chance of writing code that actually works :-) Thanks for the explanations! On Mon, Sep 30, 2013 at 5:34 PM, Steven Blenkinsop steven...@gmail.comwrote: On Monday, 30 September 2013, Oren Ben-Kiki wrote: Yes, it is very much like an arena... And yes, the idea is that all the pointers are contained in it, so the ~arena as a whole should be safe to send, but that contradicts using @ - maybe it could be re-written using Rc... hmmm. At any rate, thanks for the pointer - I wasn't aware of arenas before. Another hmmm... An arena sounds a lot like a weak version of a GC-ed heap... So here's a thought: What if @ pointers had a heap associated with them, just like pointers have a lifetime? We have the task-global @ heap, and we have the static lifetime... but we can explicitly manage lifetimes - how about if we could explicitly create a new Gc-heap use it to happily muck about with @'my-heap pointers (which would be statically prevented from being mixed with @'other-heap pointers), and be able to send the whole heap between tasks, etc.? (Not that I necessarily suggest @'heap as a syntax, but you get the idea) Gc would still run in the context of one heap at a time... but this would remove the restriction of one task = one heap. This would be neat, yes. In this case, accessing such a heap would be conceptually identical to temporarily joining a task, except without the overhead of having to schedule it, since it would have no independently executing code. Figuring out how to hook it into the GC would be a neat trick... As for what a macro would expand to, I was thinking more that it would expand to the containing structure and some smart references that use lifetimes to ensure that the containing structure is pinned during their existence and that they don't outlive it. You'd have to interact with it using methods which make sure you can't break any of the invariants, such as aliasing something and then trying to freeze it. To what extent you could do this statically rather than dynamically, I'm not sure, but lifetimes are a fairly powerful concept, so it's plausible one could work something out. Doing it dynamically would basically mean using Cells modified to have lifetimes as the smart references into the structure. It would be nice to have a version of the smart references that ensured you didn't externally alias something which is also externally mutable, though. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
That's good! But there remains the fact that there's no way to say my lifetime is the same as the struct that contains me. If 'self specialness goes away, perhaps it can be re-introduced to mean that (or a different name can be given to it). On Mon, Sep 30, 2013 at 7:01 PM, Benjamin Striegel ben.strie...@gmail.comwrote: I've only skimmed this conversation, but note that the specialness of the 'self lifetime will be going away in the future. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a struct is either 'self or 'static. A simple should be 'self as that makes more sense (but if Rust wants me to be explicit, fine). This were my least surprise expectations, but things don't work this way... the problem is I don't have a simple mental model to replace the above with, so I struggle. What _is_ 'self, exactly? Isn't a function fn foo(self) - T the same as returning a 'self T? Why would I want to say fn foo'a('a self) in the 1st place - 'a is by definition the same as 'self? How come David's Foo example fails the borrow check? Besides failing (my) least surprise expectations, the current rules also seem to be a leaky abstraction. If I have a struct that holds a ComplexT member, it needs no 'self parameter. If I then add a private member to my struct to hold some 'self PartOfT (say, cached access to an internal member), then boom, all uses of my struct now have to say 'self, I can no longer put it in thread-local-storage, etc. I'd expect keeping these sort of cached borrowed pointers should be an internal implementation detail which does not affect the users of the struct at all. I suppose there's a good reason for all this, and a reasonable mental model I need to put in my head, but digging around the docs I didn't find one... Any hints would be appreciated :-) On Sun, Sep 29, 2013 at 5:42 PM, David Renshaw dwrens...@gmail.com wrote: Cool! I think that solution is much better than mine. But I think that polluting traits-interfaces with lifetime annotation is wrong. Why the trait should have lifetime annotation? It is implementation detail. Just in case you want to see a case where it *does* make sense to put a 'self lifetime in a trait definition, here is an example: https://gist.github.com/dwrensha/db919b8e130e9eb72f0f ___ 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] Trait method self parameter type clashes with lifetime annotation required by the implementation
Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.com wrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a struct is either 'self or 'static. A simple should be 'self as that makes more sense (but if Rust wants me to be explicit, fine). This were my least surprise expectations, but things don't work this way... the problem is I don't have a simple mental model to replace the above with, so I struggle. What _is_ 'self, exactly? Isn't a function fn foo(self) - T the same as returning a 'self T? Why would I want to say fn foo'a('a self) in the 1st place - 'a is by definition the same as 'self? How come David's Foo example fails the borrow check? Besides failing (my) least surprise expectations, the current rules also seem to be a leaky abstraction. If I have a struct
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
That's... surprising. Even ignoring the fact the name self means exactly the opposite (déjà vu from const here)... I don't suppose there's a chance that something like what I expected 'self to be like would be supported at some point? Its lack rules out a lot of reasonable, safe, useful code. On Mon, Sep 30, 2013 at 12:13 AM, Gábor Lehel illiss...@gmail.com wrote: `On Sun, Sep 29, 2013 at 9:21 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } Per my understanding, this is correct. Because there is a constraint on the lifetime of a part of `Foo`, there must a constraint on the lifetime of `Foo`. It has to propagate outwards to make sure the lifetime of the whole structure is properly constrained. You basically want to propagate inwards. I don't think that's possible, but maybe someone will correct me. When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? This sounds similar to the case of a doubly linked list (with forward pointers being the spine and backwards the quick access), which is not possible as an 'owned' structure as far as I know without unsafe pointers. On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.com wrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.orgwrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were
Re: [rust-dev] Some suggestions of Rust language
On Wed, Sep 25, 2013 at 6:29 PM, Patrick Walton pwal...@mozilla.com wrote: On 9/25/13 6:32 AM, Alexander Sun wrote: Embedded anonymous structure? Embedded anonymous structure in Go is good idea, I think. Not the way Go does it, where you can have method conflicts like C++ multiple inheritance and it can be surprising which method gets called when two anonymous fields have a method with the same name. I'm not necessarily opposed to anonymous fields, but we should tread carefully. Can you say a bit more about that? I thought if two anonymous fields supported a method than it was a conflict and one had to refer to it with the specific field type (foo.TypeOfFirstField.method or foo.TypeOfSecondField.method as opposed to foo.method - the latter would be an error). This sounds pretty reasonable... Since Rust has no implicit traits anywhere, it seems reasonable to require an explicit impl Trait for Container, but allow omitting functions that are obtained from anonymous field(s) - unless one wants to override them, or when they are in conflict between more than one such field. This ensures all type checking is done at declaration rather than in code that uses the traits. It sounds like something along these lines could work in Rust, and it would be very useful... ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Should we add a Haskell-like `$` operator?
Not sure about $ but I sometimes miss the | operator (which takes the value from the left and inserts it as the 1st argument of the function call to the right). foo(a, b) | bar(c, d) | baz(e, f) == baz(bar(foo(a, b), c, d), e, f) This allows for easier functional decompsition of chains of operations. I found it to be very useful when writing Elixir; in Rust there's the OO-like traits which may make it less useful - it still might be worthwhile for people writing more functional code. On Wed, Sep 25, 2013 at 9:40 PM, Marvin Löbel loebel.mar...@gmail.comwrote: We don't use the symbol in our syntax, but are using functional paradigm that sometimes result in a bit hard to read nested calls. I'd propose that it works similar to `do`, in that it allows to move the last expression of an function or method call after the parentheses, though they would still remain required for ambiguity reasons: ~~~ a(b(c(1,d(2,3,4,e() == a() $ b() $ c(1) $ d(2,3,4) $ e() let v: ~[uint] = from_iter() $ range(0, 100); ~~~ In that sense, it wouldn't really be an operator but syntactic sugar for a function call. It might even be possible to replace `do` with it, though the now required parentheses would make it longer: ~~~ do task::spawn { ... } task::spawn() $ || { ... } ~~~ Downside is of course that it adds another symbol, which could alienate more potentiall users, and it could mean a shift-away-from or at least an inconsistency-with methods and method chaining in general. Which would be ironic because I wanted it in some complicated Iterator chain. ;) It could of course always be implemented as a syntax extension, and in any case I don't expect this to get any attention before Rust 2.0. :) __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Should we add a Haskell-like `$` operator?
Not sure about $ but I sometimes miss the | operator (which takes the value from the left and inserts it as the 1st argument of the function call to the right). foo(a, b) | bar(c, d) | baz(e, f) == baz(bar(foo(a, b), c, d), e, f) This allows for easier functional decompsition of chains of operations. I found it to be very useful when writing Elixir; in Rust there's the OO-like traits which may make it less useful - it still might be worthwhile for people writing more functional code. On Wed, Sep 25, 2013 at 9:40 PM, Marvin Löbel loebel.mar...@gmail.comwrote: We don't use the symbol in our syntax, but are using functional paradigm that sometimes result in a bit hard to read nested calls. I'd propose that it works similar to `do`, in that it allows to move the last expression of an function or method call after the parentheses, though they would still remain required for ambiguity reasons: ~~~ a(b(c(1,d(2,3,4,e() == a() $ b() $ c(1) $ d(2,3,4) $ e() let v: ~[uint] = from_iter() $ range(0, 100); ~~~ In that sense, it wouldn't really be an operator but syntactic sugar for a function call. It might even be possible to replace `do` with it, though the now required parentheses would make it longer: ~~~ do task::spawn { ... } task::spawn() $ || { ... } ~~~ Downside is of course that it adds another symbol, which could alienate more potentiall users, and it could mean a shift-away-from or at least an inconsistency-with methods and method chaining in general. Which would be ironic because I wanted it in some complicated Iterator chain. ;) It could of course always be implemented as a syntax extension, and in any case I don't expect this to get any attention before Rust 2.0. :) __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Should we add a Haskell-like `$` operator?
Not sure about $ but I sometimes miss the | operator (which takes the value from the left and inserts it as the 1st argument of the function call to the right). foo(a, b) | bar(c, d) | baz(e, f) == baz(bar(foo(a, b), c, d), e, f) This allows for easier functional decompsition of chains of operations. I'm not certain it is as useful in an OO-like language like Rust - I cer On Wed, Sep 25, 2013 at 9:40 PM, Marvin Löbel loebel.mar...@gmail.comwrote: We don't use the symbol in our syntax, but are using functional paradigm that sometimes result in a bit hard to read nested calls. I'd propose that it works similar to `do`, in that it allows to move the last expression of an function or method call after the parentheses, though they would still remain required for ambiguity reasons: ~~~ a(b(c(1,d(2,3,4,e() == a() $ b() $ c(1) $ d(2,3,4) $ e() let v: ~[uint] = from_iter() $ range(0, 100); ~~~ In that sense, it wouldn't really be an operator but syntactic sugar for a function call. It might even be possible to replace `do` with it, though the now required parentheses would make it longer: ~~~ do task::spawn { ... } task::spawn() $ || { ... } ~~~ Downside is of course that it adds another symbol, which could alienate more potentiall users, and it could mean a shift-away-from or at least an inconsistency-with methods and method chaining in general. Which would be ironic because I wanted it in some complicated Iterator chain. ;) It could of course always be implemented as a syntax extension, and in any case I don't expect this to get any attention before Rust 2.0. :) __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] If and pattern match
I agree that is a macro like your `if_matches` examples were possible, it would be a reasonable solution, including conferring the right scope for `a` and `b`. It is completely unclear to me how to implement it though. What does use_more_macros line mean? Thanks, Oren. On Mon, Sep 23, 2013 at 2:06 PM, Huon Wilson dbau...@gmail.com wrote: On 23/09/13 20:52, Jason Fager wrote: Doesn't seem like enough bang for the buck to me. In your first example you save 3 vertical lines but get a really wide one in return, and lose some indentation levels but add more syntax and conceptual overhead to the language. Might be my lack of imagination, but the feature doesn't seem to expand out to many other use cases, either. Your second case you could write as: let foo = get_option(foo); let bar = get_option(bar); if foo.is_some() bar.is_some() { use(foo.unwrap(), bar.unwrap()); } It's also possible to write a `matches` macro: macro_rules! matches { ($e:expr ~ $($p:pat)|*) = { match $e { $($p)|* = true, _ = false } } } fn main() { let a = Some(1); let b = Some(2); if matches!((a,b) ~ (Some(_), Some(_))) { println(whatever); } } (This has the drawback that accidentally (or otherwise) using a pattern that always matches, e.g. `matches!((a,b) ~ (_,_))` gives a error message about the `_ = false` arm being unreachable, which isn't particularly intuitive.) Following the use-more-macros line, one could modify the above to give something like if_matches!(foo ~ (Some(a), Some(b)) = { // use a, b }) by adding an $expr argument to use instead of `true` and replacing the false arm with `{}`. Note: this *may* break when match-var-hygiene is implemented (https://github.com/mozilla/rust/issues/9384), I'm not sure. Huon ___ 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] If and pattern match
A question / proposed syntax... How about allowing writing something like: if (Some(foo), Some(bar)) ~~ (get_option(foo), get_option(bar)) { use(foo, bar); } Instead of having to write the more combersome: match (get_option(foo), get_option(bar)) { (Some(foo), Some(bar)) = { use(foo, bar); }, _otherwise = {}, } Not to mention: let foo_bar: bool = (Some(_foo), Some(_bar)) ~~ (get_option(foo), get_option(bar)); match (get_option(foo), get_option(bar)) { (Some(foo), Some(bar)) = { use(foo, bar); }, _otherwise = {}, } Instead of the very cumbersome: let foo_bar: bool = match (get_option(foo), get_option(bar)) { (Some(_foo), Some(_bar)) = true, _otherwise = false, } } So, in general allow `pattern ~~ expression` to be a boolean expression and if it is used in an if statement allow it to introduce the matched variables to the then scope. The operator doesn't have to be ~~, it could be anything unique (though using ~ for matching has a lot of precedence in other languages). Thoughts? Oren Ben-Kiki ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] rusti - the - repl renovation
Would running test-to-destruction cases that are expected to fail count as running in a sandbox? Currently I spawn them to a separate task and catch its failure, which is probably better practice - but it would be nice if I were able to access the message given to fail and compare it with the expected one. If the unsafe catch would allow for that, it may be worthwhile to switch to it... On Fri, Sep 20, 2013 at 4:54 PM, Patrick Walton pwal...@mozilla.com wrote: On 9/19/13 11:40 PM, Jason E. Aten wrote: Agreed. I'm convinced that fail! should result in an almost-magical lets pretend that never happened jump back in time. I'm personally fine with adding an unsafe catch function or form that will stop unwinding if you absolutely have to use it, incidentally. In general fail! is not supposed to be used as an exception mechanism, because monadic use of Result does that better. But if you're doing special things like trying to sandbox Rust code, it seems relatively harmless to me. We already have all the low-level infrastructure (DWARF unwinding based C++ exceptions) necessary to make it work... Patrick __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Struct members in trait definitions
How about allowing anonymous fields, like go does? It seems to provide most of the benefits at very little language complexity cost. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Struct members in trait definitions
AFAIK the go solution walks a thin line here. An anonymous field means one can directly access any subfield, and also that the container has all the included struct traits - as implemented by the included struct. It is also possible to override the implementation. This is different from what was asked which was the opposite - the go way is the struct implies the trait, what was asked was that the trait implies the struct. I think the go approach makes a lot of sense - I found it to need very useful and simple (e.g. ambiguities are not allowed). The go docs have a better description - give it a look... On Sep 20, 2013 11:30 PM, Tobias Müller trop...@bluewin.ch wrote: Andres Osinski andres.osin...@gmail.com wrote: Hi all, I have a question which I'm sure must have already been discussed and dealt with, but I wanted to understand the design rationale: A lot of trait-level functionality would be enhanced if a trait could specify members to be included in the struct which implements the trait. This can be solved in practice by wrapping member access in accessor methods, but I fail to see why that would be preferable. IMO this would completely defeat the advantage of traits over inheritance based interfaces. The beauty of traits is, that the trait and the type are separated, only connected by the implementation: - You can add an implementation for your custom trait to any existing type. - You can add an implementation for any existing trait to your custom type. Now if you add a fields specification to the trait, the former isn't true anymore. The type has now a dependency on the trait since it must at least contain a field of a given type, if not even with a given name. If you the concrete type is under your control, this is obviously not a problem, as it is the case with inheritance based interfaces. But you cannot simply assume that for every use case. Tobi ___ 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] RFC: Syntax for raw string literals
Just to make sure - how does the C++ syntax behave in the presence of line breaks? Specifically, what does it do with leading (and trailing) white space of each line? My guess is that they would be included in the string, is that correct? At any rate, having some sort of here documents would be very nice. The C++ syntax is reasonable, though I really don't have a strong preference here. It might be more Rust-ish to use a macro notation instead: str!(delimiter.delimiter), or something like that. BTW, I found myself creating (in several languages) an unindent string function that would (1) if the string starts with a line break, remove it; (2) remove the leading white space of the 1st line from all the lines. Applying this to here documents allows indenting them together with the code that includes them. In Rust, the downside of this approach is that the result isn't 'static any more... Not that this warrants making such complex functionality a built-in of the syntax, of course. Oren. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Type parameters in trait bounds
Rust newbie here as well, trying to develop an intuition for these things myself :-) Off the top of my head - you are saying the map holds entries whose lifetime is 'input; but there's no guarantee that the map lifetime itself wouldn't be longer than that. Try saying 'input M instead of M and see how it goes. Oren. On Fri, Sep 6, 2013 at 10:27 PM, Alex quixop...@googlemail.com wrote: Hey Everyone, I'm new to rust but enjoying it a lot. I'm having trouble with the following code example: use std::hashmap::{HashMap, Map}; fn do_something'input, M: Mapint, 'input str (key: int, map: M){ match map.find(key){ Some(result) = println(fmt!(%s, result)), None = println(no match) }; } fn main(){ let map : HashMapint, str = HashMap::new(); map.insert(1, one); do_something(1, map); } This fails with a compilation error: example.rs:4:44: 4:47 error: Illegal lifetime 'input: only 'self is allowed as part of a type declaration example.rs:4 fn do_something'input, M: Mapint, 'input str (key: int, map: M){ Now, I'm probably misunderstanding a bunch of things here, firstly all the example code I've seen out there uses the HashMap type directly rather than the Map trait, is this idiomatic? Secondly, I'm still getting my head around lifetimes and probably have this all muddled so any pointers there would be welcome. Thanks Alex Good ___ 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] RFC: Stealing: lexically-scoped temporary violation of linearity
Another thought on this. Currently, either the compiler is satisfies that the code is 100% safe, or we slap an unsafe keyword around the code and put 100% of the responsibility on the programmer, with no support from the Rust system. Wouldn't it make sense to have a not statically safe, but verified at run time safety as a middle ground? In the context of the stolen proposal, when one steals a pointer, the original location could be set to null, and only be restored to a non-null pointer when the value is put back. This means any access to it would cause an exception - which is what one would intuitively expect a hold to behave like. I have a feeling that there is a non-trivial amount of code which is actually safe but would impossible to convince the compiler it is statically safe. Surely having run-time safety in such cases is better than none at all...? On Sat, Aug 31, 2013 at 3:50 AM, Patrick Walton pwal...@mozilla.com wrote: On 8/30/13 3:39 PM, Patrick Walton wrote: Thoughts? Does this seem useful? Are there soundness issues I didn't notice? Brian pointed out a massive soundness hole in this, unfortunately. The problem is that you can read from the original locations; the right to read is not shut off during the borrow. I think the fix would have to be to replace this with some sort of generalized swap operation. Patrick __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stealing: lexically-scoped temporary violation of linearity
Is there any system in actual use where actually dereferencing a null pointer will not cause an exception? I mean, _sure_, the C spec says the result is undefined, but isn't this just a leftover from the bad old days, like also supporting non-byte-addressible machines (with non-power-of-two word size!), and other such horribleness? If in practice on any machine today (X86, ARM, PowerPC, MIPS, SPARC, ...) every null pointer will fault (which I strongly hope will...), then I'd be quite happy in saying formally that accessing a hole leads to undefined behavior and make good use of knowledge that any such access will, in fact, fault, on any machine I might be coding to today. On Sat, Sep 7, 2013 at 6:55 PM, Patrick Walton pwal...@mozilla.com wrote: On 9/7/13 8:39 AM, Oren Ben-Kiki wrote: I have a feeling that there is a non-trivial amount of code which is actually safe but would impossible to convince the compiler it is statically safe. Surely having run-time safety in such cases is better than none at all...? I would be fine with this, but one big problem is that null pointer dereferences are undefined behavior in LLVM. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stealing: lexically-scoped temporary violation of linearity
I miss-spoke; when I said machine I meant platform (combination of HW and SW). Is unintentionally dereferencing a null pointer a silent error on any existing platform? But isn't a very good question either. A better one would be: Would it be _useful_ to define `steal` and use it in programs, such that it triggers a null pointer dereference (undefined behavior and all) if someone tries to access the hole? This is a softer question and I suspect the answer is yes - at least until a better way to safely update structures in-place is found... On Sat, Sep 7, 2013 at 7:20 PM, Daniel Micay danielmi...@gmail.com wrote: On Sat, Sep 7, 2013 at 12:09 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: If in practice on any machine today (X86, ARM, PowerPC, MIPS, SPARC, ...) every null pointer will fault (which I strongly hope will...), then I'd be quite happy in saying formally that accessing a hole leads to undefined behavior and make good use of knowledge that any such access will, in fact, fault, on any machine I might be coding to today. You get a segmentation fault on Linux because the first page is marked read-only for userland processes. It's valid on almost any hardware to dereference a pointer equal to zero, which is how LLVM defines the null pointer. However, LLVM explicitly considers a dereference of the null pointer to be undefined behaviour so it doesn't matter how it could or couldn't be implemented in hardware. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stealing: lexically-scoped temporary violation of linearity
Alas. So I guess it all depends on someone finding a smart safe way to generalize the swap operation, or something... as things stand, it is extremely difficult to efficiently and safely implement complex nested containers. I will admit I am using the `steal` function for now, it just makes things so much easier, but I know I'll have to pay for my sins down the line... On Sat, Sep 7, 2013 at 11:27 PM, Geoffrey Irving irv...@naml.us wrote: To clarify why undefined behavior is really bad in practice: if LLVM ever detects that your code performs undefined behavior according to the standard, it is *designed* to take full advantage of that fact when making optimizations. In other words, all hell will break lose, in potentially very complicated and subtle ways. Geoffrey On Sep 7, 2013, at 1:22 PM, Daniel Micay danielmi...@gmail.com wrote: On Sat, Sep 7, 2013 at 4:15 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: I miss-spoke; when I said machine I meant platform (combination of HW and SW). Is unintentionally dereferencing a null pointer a silent error on any existing platform? Yes, it's only a segmentation fault in userland code on platforms where the kernel is set up to make the lowest page read-only. Rust still needs to be memory safe in a kernel. But isn't a very good question either. A better one would be: Would it be _useful_ to define `steal` and use it in programs, such that it triggers a null pointer dereference (undefined behavior and all) if someone tries to access the hole? This is a softer question and I suspect the answer is yes - at least until a better way to safely update structures in-place is found... It would be undefined behaviour, so it wouldn't be useful. Rust is a memory safe language and can't allow safe code to generate LLVM IR invoking undefined behaviour. ___ 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] RFC: Stealing: lexically-scoped temporary violation of linearity
Since swap seems to have its own problems - would it be possible to tweak the stealing idea so the compiler would know there's a burrowed mutable pointer to the hole, effectively preventing further access to it in the vulnerable block? I really would like to be able to use this approach, it really improved my code... On Sat, Aug 31, 2013 at 3:50 AM, Patrick Walton pwal...@mozilla.com wrote: On 8/30/13 3:39 PM, Patrick Walton wrote: Thoughts? Does this seem useful? Are there soundness issues I didn't notice? Brian pointed out a massive soundness hole in this, unfortunately. The problem is that you can read from the original locations; the right to read is not shut off during the borrow. I think the fix would have to be to replace this with some sort of generalized swap operation. Patrick __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stealing: lexically-scoped temporary violation of linearity
I just tested this in my code, it solved a sticky problem I had with updating owned data nested deep inside a tree-ish container. My original solution wasn't very nice (it just compromised on efficiency and copied too much data around). The new code is shorter and more efficient (no copies! yey!). So, +1 for usefulness, and thanks! I wish I could also attest to the correctness, but that is harder to prove... On Sat, Aug 31, 2013 at 1:39 AM, Patrick Walton pwal...@mozilla.com wrote: Hi everyone, I've been tossing around an idea for a library utility designed to make unique pointers easier to use, especially for balanced binary search trees and the like. The core of the idea is that I conjecture it's safe to temporarily violate linearity *while the locations in question are borrowed*, as long as linearity is *dynamically* preserved once the borrow ends. First off, let me motivate this with an example, showing that this generalizes swap: struct Test { a: ~str, b: ~str, } fn main() { let mut test = Test { a: ~Burma, b: ~Shave, }; { let (a, a_loc) = steal(mut test.a); let (b, b_loc) = steal(mut test.b); println(a); // prints Burma println(b); // prints Shave a_loc.put_back(b); b_loc.put_back(a); } println(test.a); // prints Shave println(test.b); // prints Burma } Concretely, what steal does is that it takes a mutable borrow and returns two things: (1) a shallow copy of the referent, temporarily violating linearity; (2) a stolen location which must be filled with a value of the same type as the referent via the `put_back` method before the scope ends. If the scope ends (i.e. the borrow expires) without calling `put_back` on a stolen location, then task failure occurs. For example, this program fails (with the above definition of `Test`): fn main() { let mut test = Test { a: ~Burma, b: ~Shave, }; { let (a, a_loc) = steal(mut test.a); let (b, b_loc) = steal(mut test.b); a_loc.put_back(b); } // dynamic failure: b_loc was not filled } The idea behind this is to allow complex pointer rewirings such as those that self-balancing binary search trees want to be expressed in a natural way without a tricky series of swaps. The thing that initially seems questionable for soundness is that, while borrowed and while linearity is violated, the original value is still readable (although not immutably or mutably borrowable). I believe this is OK, even in the fact of LLVM alias optimizations, because while something is borrowed linearity is no longer guaranteed anyhow. The implementation is quite small and simple and fits here: struct Stolen'self,T { priv location: 'self mut T, } #[unsafe_destructor] impl'self,T Drop for Stolen'self,T { fn drop(self) { fail!(stolen) } } impl'self,T Stolen'self,T { fn put_back(self, value: T) { unsafe { intrinsics::move_val_init(**self.location, value); cast::forget(self) } } } fn steal'a,T(value: 'a mut T) - (T, Stolen'a,T) { unsafe { (cast::transmute_copy(value), Stolen { location: value, }) } } Thoughts? Does this seem useful? Are there soundness issues I didn't notice? Patrick __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Stealing: lexically-scoped temporary violation of linearity
Sigh, I guess it was too good to be true :-( I'd settle for the ability to say: update_in_place(foo.owned_pointer, fn(~T) - ~T) - surely this would be safe? Speaking of which, a secondary problem I encountered when doing this sort of thing, is the Once function issue listed in https://github.com/mozilla/rust/wiki/Doc-under-construction-FAQ. Wouldn't it be possible to say, for example, that ~fn can only be invoked once to resolve this issue? On Sat, Aug 31, 2013 at 3:50 AM, Patrick Walton pwal...@mozilla.com wrote: On 8/30/13 3:39 PM, Patrick Walton wrote: Thoughts? Does this seem useful? Are there soundness issues I didn't notice? Brian pointed out a massive soundness hole in this, unfortunately. The problem is that you can read from the original locations; the right to read is not shut off during the borrow. I think the fix would have to be to replace this with some sort of generalized swap operation. Patrick __**_ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/**listinfo/rust-devhttps://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Doc comment conventions + straw poll
I prefer using /// for comments before functions and types, and ///! for comments following fields: /// ... pub struct Foo { foo: int, //! ... } (BTW, it would be nice to document function arguments: /// ... pub fn foo( foo: int, //! ... ) { ... } But rustdoc doesn't have the concept of a doc for an argument. Oh well.) At any rate, //! allows structs to stay compact but still document the fields, as opposed to having a /// before each one which takes double the amount of lines. I actually use /// for struct fields, because rustdoc doesn't using allow //! this way today (it says expected outer comment). A bug, I guess? So I only use //! at the top to document the whole module. The main reason I use //-style everywhere is that this way I can safely use /* ... */ to comment out chunks of code. I don't comment code chunks a lot, but when I need to, it is good to know one can just do it without worrying about nesting /* ... */. If /* ... */ allowed nesting, I'd probably still prefer //-style - The '*' seem visually noisy, it takes up extra lines (in multi-line comments), and I'm never comfortable when I see: /*! * foo */ Whether it would end up meaning: // * foo Or (more likely): /// foo ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
Yes, this would be similar to the `Typeable` type class in Haskell. It queries the vtable-equivalent, which contains stuff like the name of the type and allows doing `typeof(x)`, dynamic casts, etc. This is heavily magical (that is, depends on the hidden internal representation) and properly belongs in the standard platform and not in a user-level library. On Fri, Aug 23, 2013 at 4:40 PM, Niko Matsakis n...@alum.mit.edu wrote: Currently, this is not directly supported, though downcasting in general is something we have contemplated as a feature. It might be possible to create some kind of horrible hack based on objects. A trait like: trait Dynamic { } implT Dynamic for T { } would allow any value to be cast to an object. The type descriptor can then be extracted from the vtable of the object using some rather fragile unsafe code that will doubtless break when we change the vtable format. The real question is what you can do with the type descriptor; they are not canonicalized, after all. Still, it's ... very close. This is basically how dynamic downcasting would work, in any case. Niko On Fri, Aug 23, 2013 at 07:49:57AM +0300, Oren Ben-Kiki wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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