Re: [rust-dev] Do I need to watch out for memory fragmentation?
On Mon, Apr 14, 2014 at 10:32 PM, Daniel Micay danielmi...@gmail.comwrote: On 14/04/14 12:41 PM, Matthieu Monrocq wrote: Memory fragmentation is a potential issue in all languages that not use a Compacting GC, so yes. It's much less of an issue than people make it out to be on 32-bit, and it's a non-issue on 64-bit with a good allocator (jemalloc, tcmalloc). Small dynamic memory allocations are tightly packed in arenas, with a very low upper bound on fragmentation and metadata overhead. At a certain cutoff point, allocations begin to fall through directly to mmap instead of using the arenas. On 64-bit, the address space is enormous so fragmenting it is only a problem when it comes to causing TLB misses. By the way, do you have any idea how this is going to pan out on processors like the Mill CPU where the address space is shared among processes ? There are some attenuating circumstances in Rust, notably the fact that unless you use a ~ pointer the memory is allocated in a task private heap which is entirely recycled at the death of the task, but memory fragmentation is always a potential issue. All dynamic memory allocations are currently done with the malloc family of functions, whether you use sendable types like `VecT`, `ArcT` and `~T` or task-local types like `RcT`. Using a task-local heap for types like `RcT` would only serve to *increase* the level of fragmentation by splitting it up more. For example, jemalloc implements thread-local caching, and then distributes the remaining workload across a fixed number of arenas. Increasing the level of thread-local caching has a performance benefit but by definition increases the level of fragmentation due to more unused capacity assigned to specific threads. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do I need to watch out for memory fragmentation?
On 15/04/14 12:46 PM, Matthieu Monrocq wrote: By the way, do you have any idea how this is going to pan out on processors like the Mill CPU where the address space is shared among processes ? x86_64 and ARM64 really have a 48-bit address space (cut down to 47-bit by Linux to separate the kernel/userspace) while the Mill has a 60-bit address space so it doesn't seem like a problem. It's an enormous amount of usable virtual memory. signature.asc Description: OpenPGP digital signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do I need to watch out for memory fragmentation?
Memory fragmentation is a potential issue in all languages that not use a Compacting GC, so yes. There are some attenuating circumstances in Rust, notably the fact that unless you use a ~ pointer the memory is allocated in a task private heap which is entirely recycled at the death of the task, but memory fragmentation is always a potential issue. On Mon, Apr 14, 2014 at 6:19 PM, Zach Moazeni zach.li...@gmail.com wrote: Hello, I'm starting to explore Rust, and as someone who has primarily worked in GC'd languages I'm curious if I need to watch out for anything related to memory fragmentation. Or if Rust or LLVM is doing something under the covers where this is less of an issue. Kind regards, Zach ___ 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 I need to watch out for memory fragmentation?
Thanks Matthieu. I thought that might be the case. I'll keep a look out as I work with Rust and ping the mailing list if I need to cross that bridge. Kind Regards, Zach On Mon, Apr 14, 2014 at 12:41 PM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: Memory fragmentation is a potential issue in all languages that not use a Compacting GC, so yes. There are some attenuating circumstances in Rust, notably the fact that unless you use a ~ pointer the memory is allocated in a task private heap which is entirely recycled at the death of the task, but memory fragmentation is always a potential issue. On Mon, Apr 14, 2014 at 6:19 PM, Zach Moazeni zach.li...@gmail.comwrote: Hello, I'm starting to explore Rust, and as someone who has primarily worked in GC'd languages I'm curious if I need to watch out for anything related to memory fragmentation. Or if Rust or LLVM is doing something under the covers where this is less of an issue. Kind regards, Zach ___ 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 I need to watch out for memory fragmentation?
On 14/04/14 12:41 PM, Matthieu Monrocq wrote: Memory fragmentation is a potential issue in all languages that not use a Compacting GC, so yes. It's much less of an issue than people make it out to be on 32-bit, and it's a non-issue on 64-bit with a good allocator (jemalloc, tcmalloc). Small dynamic memory allocations are tightly packed in arenas, with a very low upper bound on fragmentation and metadata overhead. At a certain cutoff point, allocations begin to fall through directly to mmap instead of using the arenas. On 64-bit, the address space is enormous so fragmenting it is only a problem when it comes to causing TLB misses. There are some attenuating circumstances in Rust, notably the fact that unless you use a ~ pointer the memory is allocated in a task private heap which is entirely recycled at the death of the task, but memory fragmentation is always a potential issue. All dynamic memory allocations are currently done with the malloc family of functions, whether you use sendable types like `VecT`, `ArcT` and `~T` or task-local types like `RcT`. Using a task-local heap for types like `RcT` would only serve to *increase* the level of fragmentation by splitting it up more. For example, jemalloc implements thread-local caching, and then distributes the remaining workload across a fixed number of arenas. Increasing the level of thread-local caching has a performance benefit but by definition increases the level of fragmentation due to more unused capacity assigned to specific threads. signature.asc Description: OpenPGP digital signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 1 December 2013 03:54, Daniel Micay danielmi...@gmail.com wrote: I don't understand the point of `do` beyond making zero-parameter closures look a bit better. If it doesn't even do that, why bother? If an editor isn't indenting it properly, that's an editor issue. As far as I can tell, the vim indent file now handles it fine. I agree, I feel do should be considered for removal - I feel the amount of sugar it provides is minimal yet it complicates the language unnecessarily. Supposing that Rust did not have the `do` syntax already, I tend to think there would be resistance to adding it for these reasons. Is there currently an issue open regarding the future of `do`? Alex ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
if do makes the code more readable or more beautiful, I higly recommend keeping this sugar syntax. If there are corner cases where do doesn't do the job, the developer should not use it in these cases. It's still the same debat, when GIMP had this ugly multi panels system, developers was saying it is a window manager issue to handle them correctly. Yet, the GIMP software was a nightmare to use on almost everybody's desktop. Now they solved with a single window application, it is much more acceptable. It will be the same here. If you rely on special feature of the editor to indent properly. if is was only curly brace, most editor would do indentation properly, but here you have || and other exotic syntax most editor doesn't understand until a proper extension is written (which can take year for some editors). I personnally will always find much more readable (and maintainable): do function { someotherFunction() }; than function(|| someotherFunction()); - Gaetan 2013/12/2 Alex Bradbury a...@asbradbury.org On 1 December 2013 03:54, Daniel Micay danielmi...@gmail.com wrote: I don't understand the point of `do` beyond making zero-parameter closures look a bit better. If it doesn't even do that, why bother? If an editor isn't indenting it properly, that's an editor issue. As far as I can tell, the vim indent file now handles it fine. I agree, I feel do should be considered for removal - I feel the amount of sugar it provides is minimal yet it complicates the language unnecessarily. Supposing that Rust did not have the `do` syntax already, I tend to think there would be resistance to adding it for these reasons. Is there currently an issue open regarding the future of `do`? Alex ___ 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
Not sure what you mean by `self` on `T`. I thought traits can take self by-value? On Dec 1, 2013, at 1:22 PM, Patrick Walton pcwal...@mozilla.com wrote: On 12/1/13 7:42 AM, Vadim wrote: Once fn()'s should consume their environment, perhaps it should be simply self, where Self is non-copyable, so it gets moved out? Doesn't work unless we have unboxed closures, as you can't call a method that takes `self` on `T`. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
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.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 -- 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
The main reason for do's existence is to make task spawning look nice. The closure inference was removed throughout the language because it masked allocation and doesn't work well with custom smart pointers. If do is still causing confusion, I'd rather just remove it entirely. Patrick Chris Morgan m...@chrismorgan.info wrote: (Do I win the prize for the shortest thread name yet?) error: last argument in `do` call has non-procedure type: || In the past three or four days I've seen at least as many enquiries in #rust about this error, and I'm sure there have been at least several others while I haven't been monitoring it. This is evidently causing quite a bit of confusion. Here's a summary of the change. The syntax is the same as it was before:: do expr { block } do expr |args| { block } do expr(args) { block } do expr(args) |args| { block } These used to desugar to the following, respectively:: expr(|| { block }) expr(|args| { block }) expr(args, || { block }) expr(args, |args| { block }) These now desugar to the following, respectively:: expr(proc() { block }) expr(proc(args) { block }) expr(args, proc() { block }) expr(args, proc(args) { block }) The change is that it now accepts a procedure rather than a closure. No syntax change, just a semantics change which breaks a lot of code. Closure: a stack function; used to be ``fn(..) - _``, is now ``|..| - _``. Can be called multiple times, requires no allocations and is not Send. Procedure: a heap function; used to be ``~once fn(..) - _``, is now ``proc(..) - _``. Can be called once, requires heap allocation and is Send. Procedures are good for sending cross-task; things like the task body are a good match. Still, I think there are a few problems with how things are at present (i.e. after the do semantics change): 1. ``do`` is still using the syntax of a closure (``|..| { .. }``), despite it now being a procedure. 2. All of a sudden, things using closures need to shift away from using ``do`` or use procedures; this is causing confusion and may cause bad design decisions where nice sugar triumphs over what is actually needed; often the best solution may not be clear. (I, for example, had not thought about the fact that ``proc`` was going to allocate; the ``~once fn`` name was clearer about that. I'll speak about ``once fn`` another time. Don't mention it now, this thread is just about ``do``.) I have two solutions that I think could answer these concerns. Leaving it as it is seems a bad idea to me. (a) Kill ``do`` --- I've had mixed feelings about ``do``. Overall, it's pretty trivial syntax sugar, but it's sugar of a dubious sort, because it changes something that looks like a function call with N arguments to be a function call with N+1 arguments. That's just a matter of learning it. Still, ``do`` *is* nice sugar in the way it gets rid of parentheses at the end. Overall, is it worth it? I don't know. Once ``do`` is gone, there's no problem left: just remove the sugar *everywhere* it was used and everything works and will do for the foreseeable future. (b) Make ``do`` support both closures and procedures The syntax of ``do`` can be clearly seen to include the closure syntax. We could easily extend it to support both closures and procedures. Here is a proposed ``do`` using closures once more, keeping the syntax it had last week:: do expr || { block } do expr(args) || { block } do expr |args| { block } do expr(args) |args| { block } Here is a proposed ``do`` using procedures as the current behaviour is, but with new syntax which is clearly a procedure:: do expr proc() { block } do expr(args) proc() { block } do expr proc(args) { block } do expr(args) proc(args) { block } This does leave these cases which are currently valid unclear:: do expr { block } do expr(args) { block } The options for this are (a) disallowing it; (b) making it always of the function types; and (c) inferring the type. I generally prefer the last solution but it is the most difficult. I'm not sure how it all fits into the function traits stuff at all. Incidentally, all this leaves the possibility open of making ``do`` work for *any* argument type, where ``do expr1 expr2`` simply desugars to ``expr1(expr2)`` and ``do expr1(args) expr2`` to ``do expr1(args, expr2)``. I don't know if that would be a good thing or not; it's probably best to avoid discussion of that at present. Summary === Leaving ``do`` in its present form seems to me a distinctly bad idea, with the syntax of one form of function while it uses another form of function. I think we need to redo ``do`` very soon. (I'd save this joke for later in the thread, but I'm afraid someone else might steal it. I expect all responses to indicate they're in favour of this by using the title Re: do :P.) For myself, I have no preference to indicate; I
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
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
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
If do is still causing confusion, I'd rather just remove it entirely. I rather like `do`. I agree that if it's confusing it should be considered for removal, but IMO the confusion here stems from familiarity with the prior, obsolete semantics rather than any inherent problem with the construct itself. I say we should wait for people to familiarize themselves with the new closure types before thinking about giving it the axe. On Sat, Nov 30, 2013 at 3:26 AM, Patrick Walton pwal...@mozilla.com wrote: The main reason for do's existence is to make task spawning look nice. The closure inference was removed throughout the language because it masked allocation and doesn't work well with custom smart pointers. If do is still causing confusion, I'd rather just remove it entirely. Patrick Chris Morgan m...@chrismorgan.info wrote: (Do I win the prize for the shortest thread name yet?) error: last argument in `do` call has non-procedure type: || In the past three or four days I've seen at least as many enquiries in #rust about this error, and I'm sure there have been at least several others while I haven't been monitoring it. This is evidently causing quite a bit of confusion. Here's a summary of the change. The syntax is the same as it was before:: do expr { block } do expr |args| { block } do expr(args) { block } do expr(args) |args| { block } These used to desugar to the following, respectively:: expr(|| { block }) expr(|args| { block }) expr(args, || { block }) expr(args, |args| { block }) These now desugar to the following, respectively :: expr(proc() { block }) expr(proc(args) { block }) expr(args, proc() { block }) expr(args, proc(args) { block }) The change is that it now accepts a procedure rather than a closure. No syntax change, just a semantics change which breaks a lot of code. Closure: a stack function; used to be ``fn(..) - _``, is now ``|..| - _``. Can be called multiple times, requires no allocations and is not Send. Procedure: a heap function; used to be ``~once fn(..) - _``, is now ``proc(..) - _``. Can be called once, requires heap allocation and is Send. Procedures are good for sending cross-task; things like the task body are a good match. Still, I think there are a few problems with how things are at present (i.e. after the do semantics change): 1. ``do`` is still using the syntax of a closure (``|..| { .. }``), despite it now being a procedure. 2. All of a sudden, things using closures need to shift away from using ``do`` or use procedures; this is causing confusion and may cause bad design decisions where nice sugar triumphs over what is actually needed; often the best solution may not be clear. (I, for example, had not thought about the fact that ``proc`` was going to allocate; the ``~once fn`` name was clearer about that. I'll speak about ``once fn`` another time. Don't mention it now, this thread is just about ``do``.) I have two solutions that I think could answer these concerns. Leaving it as it is seems a bad idea to me. (a) Kill ``do`` --- I've had mixed feelings about ``do``. Overall, it's pretty trivial syntax sugar, but it's sugar of a dubious sort, because it changes something that looks like a function call with N arguments to be a function call with N+1 arguments. That's just a matter of learning it. br / Still, ``do`` *is* nice sugar in the way it gets rid of parentheses at the end. Overall, is it worth it? I don't know. Once ``do`` is gone, there's no problem left: just remove the sugar *everywhere* it was used and everything works and will do for the foreseeable future. (b) Make ``do`` support both closures and procedures -- The syntax of ``do`` can be clearly seen to include the closure syntax. We could easily extend it to support both closures and procedures. Here is a proposed ``do`` using closures once more, keeping the syntax it had last week:: do expr || { block } do expr(args) || { block } do expr |args| { block } do expr(args) |args| { block } Here is a proposed ``do`` using procedures as the current behaviour is, but with new syntax which is clearly a procedure:: do expr proc() { block } do expr(args) proc() { block } br /do expr proc(args) { block } do expr(args) proc(args) { block } This does leave these cases which are currently valid unclear:: do expr { block } do expr(args) { block } The options for this are (a) disallowing it; (b) making it always of the function types; and (c) inferring the type. I generally prefer the last solution but it is the most difficult. I'm not sure how it all fits into the function traits stuff at all. Incidentally, all this leaves the possibility open of making ``do`` work for *any* argument type, where ``do expr1 expr2`` simply desugars to ``expr1(expr2)`` and ``do expr1(args) expr2`` to ``do expr1(args, expr2)``. I don't know if that would be a
Re: [rust-dev] do
On Sat, Nov 30, 2013 at 9:34 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: 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. I agree, having annotations so that the type system can enforce safety is a better idea than hacking around it with alternate versions of every function for taking closures only used once. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 3:25 AM, Oren Ben-Kiki wrote: 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. You can use the with pattern, as discussed elsewhere in the thread. 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). That doesn't work if `Option` is to actually implement the container traits, since it has to have the same signature. And if it doesn't implement those traits, the with pattern works. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
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. Kevin On Nov 30, 2013 10:02 AM, Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 8:32 AM, Tiffany Bennett wrote: On Sat, Nov 30, 2013 at 9:34 AM, Oren Ben-Kiki o...@ben-kiki.org mailto:o...@ben-kiki.org wrote: 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. I agree, having annotations so that the type system can enforce safety is a better idea than hacking around it with alternate versions of every function for taking closures only used once. You don't need alternate versions: you just need one version that passes arguments through. I don't agree in general that the right solution for every problem that can be solved through the type system is in the type system. Every type system feature has a cost; when something can be done via what's already present in the language then it becomes difficult to justify adding more features to what is already a quite complex type system by industry standards. 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
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. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
Should an issue for this be filed then? -- Ziad On Sat, Nov 30, 2013 at 10:20 AM, Patrick Walton pcwal...@mozilla.comwrote: 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. 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
On Nov 30, 2013, at 10:02 AM, Patrick Walton pcwal...@mozilla.com wrote: I don't agree in general that the right solution for every problem that can be solved through the type system is in the type system. Every type system feature has a cost; when something can be done via what's already present in the language then it becomes difficult to justify adding more features to what is already a quite complex type system by industry standards. 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. -Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
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
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
(I forget the name, sadly) This is usually referred to as Tennet's Correspondence Principle: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html ...though it is sometimes debated whether or not the modern interpretation of this principle is actually what Tennet intended (the book in which it appeared is apparently quite hard to get a hold of). On Sat, Nov 30, 2013 at 2: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 ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 6:34 AM, Oren Ben-Kiki wrote: 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. As I mentioned before, most of those in the library can be turned into RAII. (I made informal measurements of the number of them that could be RAII-ified when I was removing do; the vast majority would be better as RAII.) Some of those that can't are generic container traits that wouldn't benefit from `once fn` anyway. For the remainder, adding the tuples doesn't seem much of a burden to me. If it is, we can always add `once fn` if we have to, but we haven't really tried not having it. And then there's the possibility of modifying variables... Can you elaborate? You can already use mut on individual pattern bindings, including individual elements of destructured tuples. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 12:04 PM, Oren Ben-Kiki wrote: 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 :-) If you decompose into a lambda plus the tupled set of upvars which it's moving out of, then this respects TCP. Patrick ___ 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
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
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
It's also not clear to me how once fn can decompose into a trait in the future. The goal in the future is to make fn() a type of trait, to allow for C++-like zero-indirection closures. The different types of functions that we have today correspond to different self parameters: |A|-B corresponds to mut self and proc() corresponds to ~self. But I don't see where once fn fits in. Perhaps the right thing is to gate once fn on by-value anonymous closures. I think once functions may be able to be made to work as function trait bounds. But implementing once fn right now seems to close off our ability to have closures with the same efficiency as C++11 in the future, unless there's something I'm missing. Patrick Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 12:04 PM, Oren Ben-Kiki wrote: 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 :-) If you decompose into a lambda plus the tupled set of upvars which it's moving out of, then this respects TCP. Patrick ___ 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
On Fri, Nov 29, 2013 at 11:34 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: I find `do` syntax form is vital for DSL-ish code. On Sat, Nov 30, 2013 at 12:26 AM, Patrick Walton pwal...@mozilla.com wrote: The main reason for do's existence is to make task spawning look nice. I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On Sat, Nov 30, 2013 at 7:55 PM, Tony Arcieri basc...@gmail.com wrote: On Fri, Nov 29, 2013 at 11:34 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: I find `do` syntax form is vital for DSL-ish code. On Sat, Nov 30, 2013 at 12:26 AM, Patrick Walton pwal...@mozilla.com wrote: The main reason for do's existence is to make task spawning look nice. I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri I agree actually, I was using do to implement some convenience logic and my code went from: do function { someotherFunction() }; to function(|| someotherFunction()); Maybe I'm abusing something here, but I found the first format more intuitive and elegant... I know there's rumblings about io conditions going away, but the change also makes that more awkward... :/ ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 7:25 PM, Michael Letterle wrote: I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri I agree actually, I was using do to implement some convenience logic and my code went from: do function { someotherFunction() }; to function(|| someotherFunction()); Maybe I'm abusing something here, but I found the first format more intuitive and elegant... I know there's rumblings about io conditions going away, but the change also makes that more awkward... :/ The point of this change was to got rid of closure type inference. With the old rules it was not possible to see whether you were allocating without looking at the type signature of the function you're calling. Moreover the capture rules are extremely different depending on the type of closure it is. It's too much magic for Rust. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 30 Nov 2013, at 5:34 pm, 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 This really is an important point. I would recommend folks look at Shoes (http://shoesrb.com/) for an example of how Ruby’s block syntax can help create beautiful APIs. ~Brendan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 7:35 PM, Brendan Zabarauskas wrote: On 30 Nov 2013, at 5:34 pm, 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 This really is an important point. I would recommend folks look at Shoes (http://shoesrb.com/) for an example of how Ruby’s block syntax can help create beautiful APIs. Ruby is a totally different language without two kinds of closures. The problem is not the sugar, it's the inference. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On Sat, Nov 30, 2013 at 10:28 PM, Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 7:25 PM, Michael Letterle wrote: I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri I agree actually, I was using do to implement some convenience logic and my code went from: do function { someotherFunction() }; to function(|| someotherFunction()); Maybe I'm abusing something here, but I found the first format more intuitive and elegant... I know there's rumblings about io conditions going away, but the change also makes that more awkward... :/ The point of this change was to got rid of closure type inference. With the old rules it was not possible to see whether you were allocating without looking at the type signature of the function you're calling. Moreover the capture rules are extremely different depending on the type of closure it is. It's too much magic for Rust. Maybe `do` can just change from procs to closures. I can't really say how often I've actually wanted a proc. Task bodies are a far minority compared to other uses of do, from the backlash, and I don't find `spawn(proc() { ... })` that unappealing. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 7:43 PM, Corey Richardson wrote: Maybe `do` can just change from procs to closures. I can't really say how often I've actually wanted a proc. Task bodies are a far minority compared to other uses of do, from the backlash, and I don't find `spawn(proc() { ... })` that unappealing. I really don't see do for stack closures as something that makes sense in current Rust. It made sense back when we used it for loops and didn't use RAII (as Ruby does), but the experiment of using blocks in place of RAII for stuff like with_c_str or unkillable has failed: it leads to too much rightward drift. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On Nov 30, 2013, at 7:28 PM, Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 7:25 PM, Michael Letterle wrote: I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri I agree actually, I was using do to implement some convenience logic and my code went from: do function { someotherFunction() }; to function(|| someotherFunction()); Maybe I'm abusing something here, but I found the first format more intuitive and elegant... I know there's rumblings about io conditions going away, but the change also makes that more awkward... :/ The point of this change was to got rid of closure type inference. With the old rules it was not possible to see whether you were allocating without looking at the type signature of the function you're calling. Moreover the capture rules are extremely different depending on the type of closure it is. It's too much magic for Rust. Can we not simply allow `do` to work with both stack closures and heap closures? With the current proc() stuff that would be do spawn proc() { .. } And yes, I know do originally existed to make spawning nicer, but that's not really that ugly, and allows for using `do` with stack closures (which, in code I've seen, has been by far the majority of use-cases for `do`). Also, IMO making the existence of a proc more obvious seems like a good idea (given the effect it has on captured values). Similarly, if this change were made, then a nullary stack closure would be called like do some_func || { .. } which I think is fine, as it makes the stack closure obvious, although the potential confusion of the || with the logical-OR operator is very slightly worrisome (but not terribly so, especially because pushing RAII should mean that functions that take nullary stack closures in tail position shouldn't be common). -Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 7:50 PM, Kevin Ballard wrote: do spawn proc() { .. } That's essentially just as verbose as not having do. And yes, I know do originally existed to make spawning nicer, but that's not really that ugly, and allows for using `do` with stack closures (which, in code I've seen, has been by far the majority of use-cases for `do`). That's because, in the vast majority of cases: (1) We don't use RAII enough. This should be fixed. (2) `do` was being used for stuff like `do v.map { ... }`, which I've always considered something of an abuse. map is a higher order function; it should look like a higher order function and not an iterator. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On Sat, Nov 30, 2013 at 10:50 PM, Kevin Ballard ke...@sb.org wrote: On Nov 30, 2013, at 7:28 PM, Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 7:25 PM, Michael Letterle wrote: I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri I agree actually, I was using do to implement some convenience logic and my code went from: do function { someotherFunction() }; to function(|| someotherFunction()); Maybe I'm abusing something here, but I found the first format more intuitive and elegant... I know there's rumblings about io conditions going away, but the change also makes that more awkward... :/ The point of this change was to got rid of closure type inference. With the old rules it was not possible to see whether you were allocating without looking at the type signature of the function you're calling. Moreover the capture rules are extremely different depending on the type of closure it is. It's too much magic for Rust. Can we not simply allow `do` to work with both stack closures and heap closures? With the current proc() stuff that would be do spawn proc() { .. } And yes, I know do originally existed to make spawning nicer, but that's not really that ugly, and allows for using `do` with stack closures (which, in code I've seen, has been by far the majority of use-cases for `do`). Also, IMO making the existence of a proc more obvious seems like a good idea (given the effect it has on captured values). Similarly, if this change were made, then a nullary stack closure would be called like do some_func || { .. } which I think is fine, as it makes the stack closure obvious, although the potential confusion of the || with the logical-OR operator is very slightly worrisome (but not terribly so, especially because pushing RAII should mean that functions that take nullary stack closures in tail position shouldn't be common). -Kevin I don't understand the point of `do` beyond making zero-parameter closures look a bit better. If it doesn't even do that, why bother? If an editor isn't indenting it properly, that's an editor issue. As far as I can tell, the vim indent file now handles it fine. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 1 Dec 2013, at 1:45 pm, Patrick Walton pcwal...@mozilla.com wrote: the experiment of using blocks in place of RAII for stuff like with_c_str or unkillable has failed: it leads to too much rightward drift. Patrick I guess I can agree with that. I remember when I first started with Rust doing: `some_c_func(“hi”.with_c_str(|s| s))`, which completely negates the safety guarantees of the closure. How would this look with RAII? By ‘rightward drift’ do you mean in terms of multiple nested closures? ~Brendan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On Nov 30, 2013, at 7:54 PM, Daniel Micay danielmi...@gmail.com wrote: On Sat, Nov 30, 2013 at 10:50 PM, Kevin Ballard ke...@sb.org wrote: On Nov 30, 2013, at 7:28 PM, Patrick Walton pcwal...@mozilla.com wrote: On 11/30/13 7:25 PM, Michael Letterle wrote: I've got to say that the do syntax is one of the things that appeals to me about Rust, and will probably appeal to the people that Steve Klabnik is drawing to the language with Rust for Rubyists. It might seem like a small thing but the effects on the type of programs you can write, it actually has a pretty profound effect, IMO. -- Tony Arcieri I agree actually, I was using do to implement some convenience logic and my code went from: do function { someotherFunction() }; to function(|| someotherFunction()); Maybe I'm abusing something here, but I found the first format more intuitive and elegant... I know there's rumblings about io conditions going away, but the change also makes that more awkward... :/ The point of this change was to got rid of closure type inference. With the old rules it was not possible to see whether you were allocating without looking at the type signature of the function you're calling. Moreover the capture rules are extremely different depending on the type of closure it is. It's too much magic for Rust. Can we not simply allow `do` to work with both stack closures and heap closures? With the current proc() stuff that would be do spawn proc() { .. } And yes, I know do originally existed to make spawning nicer, but that's not really that ugly, and allows for using `do` with stack closures (which, in code I've seen, has been by far the majority of use-cases for `do`). Also, IMO making the existence of a proc more obvious seems like a good idea (given the effect it has on captured values). Similarly, if this change were made, then a nullary stack closure would be called like do some_func || { .. } which I think is fine, as it makes the stack closure obvious, although the potential confusion of the || with the logical-OR operator is very slightly worrisome (but not terribly so, especially because pushing RAII should mean that functions that take nullary stack closures in tail position shouldn't be common). -Kevin I don't understand the point of `do` beyond making zero-parameter closures look a bit better. If it doesn't even do that, why bother? If an editor isn't indenting it properly, that's an editor issue. As far as I can tell, the vim indent file now handles it fine. At this point, given that stack closures no longer work with do, it seems to me that do is just Rust's attempt at providing a syntactical nicety analogous to Go's `go` operator. If we can't have `do` working with stack closures, my feeling is we should just remove it. Keeping around special syntax purely for the case of heap closures seems like unnecessary complexity. Although my preference is still for restoring `do`'s ability to work with stack closures. -Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do
On 11/30/13 8:06 PM, Brendan Zabarauskas wrote: On 1 Dec 2013, at 1:45 pm, Patrick Walton pcwal...@mozilla.com wrote: the experiment of using blocks in place of RAII for stuff like with_c_str or unkillable has failed: it leads to too much rightward drift. Patrick I guess I can agree with that. I remember when I first started with Rust doing: `some_c_func(“hi”.with_c_str(|s| s))`, which completely negates the safety guarantees of the closure. How would this look with RAII? Just return a package consisting of either an owned string (if allocation needed to be done) or a borrowed pointer to the original string (if no allocation needed to be done). Then you can put a method on that enum yielding the raw C pointer. Voila, no rightward drift :) By ‘rightward drift’ do you mean in terms of multiple nested closures? Right. I've seen with_c_str six levels deep :( RAII also has the advantage that you can more precisely control the scope of the effect that you're delimiting: you can move it around, destruct it early, and so on. For example, an RAII'd version of task::unkillable would not only have no rightward drift, but the token that makes you killable again could also be destructed on some code paths but not others, moved to other functions, etc. 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
[rust-dev] Do we have shared ports?
Hi! As I know, As I know, we have SharedChan mechanism which can be used for many clients - server communications. But how can I send response from server to many clients? This is not commonly used case, and looks like there is no such mechanism or I've missed something? Best regards, Alexander. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do we have shared ports?
Hi, I am not quite sure whether you are asking for a multi-cast feature (all clients receive a copy of the message) or for a send-to-one-among feature (in which one of the available client would pick up the message). Could you elaborate ? -- Matthieu On Tue, May 28, 2013 at 11:45 AM, Alexander Stavonin a.stavo...@gmail.comwrote: Hi! As I know, As I know, we have SharedChan mechanism which can be used for many clients - server communications. But how can I send response from server to many clients? This is not commonly used case, and looks like there is no such mechanism or I've missed something? Best regards, Alexander. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do we have shared ports?
On 05/28/2013 02:45 AM, Alexander Stavonin wrote: Hi! As I know, As I know, we have SharedChan mechanism which can be used for many clients - server communications. But how can I send response from server to many clients? This is not commonly used case, and looks like there is no such mechanism or I've missed something? There isn't a type defined for this currently. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Do-notation?
Say we want to implement the following function: fn add(x: Optionint, y: Optionint) - Optionint { ... } Some functional languages, like Haskell and Scala offer some sort of a do notation to make unwrapping multiple Option type values easier. add :: Maybe Int - Maybe Int - Maybe Int add mx my = do x - mx y - my return (x + y) Is there an equivalent construct in Rust? -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do-notation?
On 2013-05-23, at 14:28 , Benjamin Striegel wrote: There's no generalized notation, but a while ago I overloaded the + operator on Option such that it automatically unwraps them, adds the contained elements together (for any two types that implement Add), and returns a wrapped result. let foo = Some(1) + Some(4); error!(foo); // Some(5) This behavior seems mostly innocuous, but there's some question as to whether the behavior is correct (and also whether we want to support this sort of overloading at all): https://github.com/mozilla/rust/issues/6002 If this sort of thing is useful, it's feasible that we could overload the other operators as well. I think that's way too specialized and repetitive for the general case. A form of zip/map_zip for option would be better as it'd allow applying arbitrary operations cleanly, something along the lines of fn zipT, U(t: OptionT, u: OptionU) - Option(T, U) And thus you would write something along the lines of: let foo = option::zip(Some(1), Some(2)).map(|(a, b)| { a + b }) zip would be something along the lines of: match (t, u) { (Some t1, Some v1) = Some (t1, v1), _ = None } (well it would require pointer and lifetime powder thing, but you get the idea) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do-notation?
On 23/05/13 16:13, Ziad Hatahet wrote: Say we want to implement the following function: fn add(x: Optionint, y: Optionint) - Optionint { ... } Some functional languages, like Haskell and Scala offer some sort of a do notation to make unwrapping multiple Option type values easier. add :: Maybe Int - Maybe Int - Maybe Int add mx my = do x - mx y - my return (x + y) Is there an equivalent construct in Rust? -- Ziad I just whipped up a very basic do-notation syntax extension[1] (it can't be called do! unfortunately), it was much easier than I was expecting. The following compiles fine: fn main () { let x = do_!(bind a = Some(1); bind b = None; let res = a + b; Some(res)); println(fmt!(%?, x)) } and prints None (or Some(3), if you change the None to Some(2)). It works for anything that defines a method called chain (e.g. Result), but there's no generic return equivalent yet, so that has to be changed for each type. (I chose to use bind rather than - (or similar) for parsing ease.) Huon [1]: https://github.com/huonw/rust/tree/do-notation ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do-notation?
Thanks all for the replies. Niko, could you point out where in the code you defined the macro you mention? Thanks -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Do-notation?
I was thinking of the if_ok! macro, which is intended for use with the Result type: ``` macro_rules! if_ok( ($inp: expr) = ( match $inp { Ok(v) = { v } Err(e) = { return Err(e); } } ) ) ``` It is used like: ``` let foo = if_ok!(something_that_yields_a_result()); ``` Niko On Thu, May 23, 2013 at 09:48:28AM -0700, Ziad Hatahet wrote: Thanks all for the replies. Niko, could you point out where in the code you defined the macro you mention? Thanks -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do we need lambda?
If bind is staying (there was talk of removing it in favour of lambda at some point), I think we can do without lambda. But the concept of shared closures (which is what bind creates) would still be there. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do we need lambda?
On Mon Dec 5 14:27:18 2011, Marijn Haverbeke wrote: If bind is staying (there was talk of removing it in favour of lambda at some point), I think we can do without lambda. But the concept of shared closures (which is what bind creates) would still be there. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev What would be removed exactly? I strongly believe that we need a form of closures, e.g. for registering event callback, whether to a GUI, or for network or system events. Now, of course, as long as we have some ability to pair a data structure and a function pointer, and a standard way to represent functions expecting this kind of data structure, we can always fallback to manual closure conversion, at the expense of some readability. I wonder, what exactly would be gained by removing lambdas? Cheers, David signature.asc Description: OpenPGP digital signature ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do we need lambda?
Ah, I see now that nested functions cannot access upvars. I was under the impression this limitation had been removed. I did not intend to take away access to upvars (as you and Graydon said, crucial to event callbacks) but just the anonymous function syntax. However, I've been thinking it over more since last night and now I think that this is not a very good idea. It'll make the language feel heavy and we want it to feel light. What might be nice, then, is a less ponderous syntax than lambda syntax. In any case, I am still toying with what unique closures ought to be. One problem I have uncovered (and it's already a bug today) is that a unique closure must be very careful what it does with its unique, closed-over state. The problem is that a unique closure can be invoked multiple times. Not so good if you are moving or dropping unique variables. For example, this code crashes today: fn foo(-x: ~int) { } fn main() { let b = bind foo(~3); b(); b(); } The error is that bind needs to re-copy the ~3 each time `b()` is invoked, but it doesn't. In other words, that bind code is equivalent to `let x = ~3 in fn () - foo(x)` (in some weird O'Caml/Rust hybrid) but it would need to be `fn() - let x = ~3 in foo(x)` to be safe. This problem can be addressed in many ways and I am not sure what is best. One option is to say that unique closures cannot move or dispose of their upvars (here, bind is moving its upvar, essentially). Essentially upvars become like a field of a record or other immutable location, which must be accessed via swap. This is safe but somewhat disappointing, because most unique closures will be used to spawn a task and therefore executed only once. Another option is to specify that a unique closure can be invoked only once (calling it consumes itself). This is also limiting if that's not what you want, but it probably is. In particular it does not allow unique closures to become the foundation for a map/reduce library. All in all, I am just not sure that unique closures are the right tool for a user-friendly, simple parallelism API, which I understood to be one of their goals. In other words, if you want to fork off a bunch of tasks to process the various elements in your array and then pull them back in, unique closures don't really give you the guarantees you want. On the other hand, unique closures do serve a useful purpose for spawning off a task and handing it data. This could also be simulated today using a wrapper that creates a channel, starts a new task, passes the value over the channel, and finally invokes your function. Of course this adds overhead for something that (may?) be a common case. But I am not sure if moving one-off data like that *is* a common case. Niko On 12/5/11 8:33 AM, David Rajchenbach-Teller wrote: On Mon Dec 5 14:27:18 2011, Marijn Haverbeke wrote: If bind is staying (there was talk of removing it in favour of lambda at some point), I think we can do without lambda. But the concept of shared closures (which is what bind creates) would still be there. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev What would be removed exactly? I strongly believe that we need a form of closures, e.g. for registering event callback, whether to a GUI, or for network or system events. Now, of course, as long as we have some ability to pair a data structure and a function pointer, and a standard way to represent functions expecting this kind of data structure, we can always fallback to manual closure conversion, at the expense of some readability. I wonder, what exactly would be gained by removing lambdas? Cheers, David ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] do we need lambda?
Hello, I wanted to do a quick straw poll to ask whether we still need a lambda expression, given that we have blocks and named functions? Searching the rust code base, I found that *every* use of lambda was of the form: |let foo = lambda(...) {...}| which would (in my opinion) be better written: |fn foo(...) {...}|. I am not asking because I like stripping out unused expression forms, though I do, but rather because I am thinking about the precise design for unique closures (separate e-mail coming soon) and the fewer ways to declare closures the simpler the job becomes. Niko ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev