Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
Cool. I was afraid that it will be harder for the compiler to optimize away the enum, but it seems to be doing fine. (If it does turn out that it's harder for the compiler, I don't see a real problem with the approach I suggested, as a runtime failure can only be caused by a bug in the code generator, not by user code) On Thu, Jun 12, 2014 at 2:13 AM, Kevin Cantu m...@kevincantu.org wrote: Matthew Monrocq suggests this improvement, which looks even cleaner to use, although slightly more complicated to implement generation of: On Wed, Jun 11, 2014 at 11:38 AM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: [snip] I do like the idea of the trait, however I would rather do away with all the `get_aa`: why not directly wrap the parameters ? enum AaBbEnum { Aa(int, f64), Bb(f64), } trait AaBb { fn get(self) - AaBbEnum; } impl AaBb for (int, f64) { fn get(self) - AaBbEnum { match *self { (i, f) = Aa(i, f), } } } impl AaBb for (f64) { fn get(self) - AaBbEnum { Bb(*self) } } fn overloadedT: AaBb(x: T) { match x.get() { Aa(i, f) = println!(got Aa: {}, (i, f)), Bb(f) = println!(got Bb: {}, f), } } #[main] fn main() { overloaded((5i, 7.3243)); // prints: got Aa: (5, 7.3243) overloaded((3.5)); // prints: got Bb: 3.5 } Now, there is no runtime failure = you cannot accidentally match on `Bb` and requests `get_aa`! Kevin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
You can achieve overloading which is equivalent to C++ by defining a trait for all the types a specific argument can get: ``` enum IntOrFloatEnum { Int, F64, } trait IntOrFloat { fn get_type(self) - IntOrFloatEnum; fn get_int(self) - int { fail!(); } fn get_f64(self) - f64 { fail!(); } } impl IntOrFloat for int { fn get_type(self) - IntOrFloatEnum { Int } fn get_int(self) - int { self } } impl IntOrFloat for f64 { fn get_type(self) - IntOrFloatEnum { F64 } fn get_f64(self) - f64 { self } } fn overloadedT: IntOrFloat(x: T) { match x.get_type() { Int = println!(got int: {}, x.get_int()), F64 = println!(got f64: {}, x.get_f64()), } } fn main() { overloaded(5i); // prints: got int: 5 overloaded(3.5); // prints: got f64: 3.5 } ``` This is equivalent to having to functions, overloaded(int) and overloaded(f64). From what I see, the compiler even optimizes away the logic, so the generated code is actually equivalent to this: ``` fn overloaded_int(x: int) { println!(got int: {}, x); } fn overloaded_f64(x: f64) { println!(got f64: {}, x); } fn main() { overloaded_int(5i); overloaded_f64(3.5); } ``` (I actually think that if Rust gains one day some support for overloading, it should be syntactic sugar for the above, which will allow you to define a function whose argument can be of multiple types. I don't like the C++ style of defining several different functions with the same name and letting the compiler choose which function should actually be called). Using this method you can solve both the problem of overloading and default arguments. For every possible number of arguments that C++ would allow, define a function funcNT0, T1, TN-1(arg0: T0, arg1: T1, ..., argN-1: TN-1). The function would check the actual types of the arguments and call the right C++ function, filling default arguments on the way. So the only difference between C++ and Rust code would be that you'd have to add the number of arguments to the method name. It would probably not be easy to generate the required code, but I think it would solve the problem perfectly. Cheers, Noam On Thu, May 22, 2014 at 11:27 PM, Alexander Tsvyashchenko n...@endl.ch wrote: Hi All, Recently I was playing with bindings generator from C++ to Rust. I managed to make things work for Qt5 wrapping, but stumbled into multiple issues along the way. I tried to summarize my pain points in the following blog post: http://endl.ch/content/cxx2rust-pains-wrapping-c-rust-example-qt5 I hope that others might benefit from my experience and that some of these pain points can be fixed in Rust. I'll try to do my best in answering questions / acting on feedback, if any, but I have very limited amount of free time right now so sorry in advance if answers take some time. Thanks! -- Good luck! Alexander ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback
Thanks! I looked at http://qt-project.org/doc/qt-4.8/qwidget.html, which has several overloaded functions, and didn't find overloaded functions with different return types. If there are, there are probably rare - I really think that overloaded functions with different return types are an abomination. On Wed, Jun 11, 2014 at 8:23 PM, Kevin Cantu m...@kevincantu.org wrote: Noam, that's awesome. It even works for tuples like so (I didn't think it would): ``` enum AaBbEnum { Aa, Bb, } trait AaBb { fn get_type(self) - AaBbEnum; fn get_aa(self) - (int, f64) { fail!(); } fn get_bb(self) - (f64) { fail!(); } } impl AaBb for (int, f64) { fn get_type(self) - AaBbEnum { Aa } fn get_aa(self) - (int, f64) { self } } impl AaBb for (f64) { fn get_type(self) - AaBbEnum { Bb } fn get_bb(self) - (f64) { self } } #[cfg(not(test))] fn overloadedT: AaBb(x: T) { match x.get_type() { Aa = println!(got Aa: {}, x.get_aa()), Bb = println!(got Bb: {}, x.get_bb()), } } fn overloaded_formatT: AaBb(x: T) - String { match x.get_type() { Aa = format!(got Aa: {}, x.get_aa()), Bb = format!(got Bb: {}, x.get_bb()), } } #[cfg(not(test))] #[main] fn main() { overloaded((5i, 7.3243)); // prints: got Aa: (5, 7.3243) overloaded((3.5)); // prints: got Bb: 3.5 } #[test] fn overloaded_with_same_return_works() { // now with a shared return let x: String = overloaded_format((5i, 7.3243)); let y: String = overloaded_format((3.5)); assert_eq!(x, got Aa: (5, 7.3243).to_string()); assert_eq!(y, got Bb: 3.5.to_string()); } ``` I imagine if the functions being overloaded have different return types, this gets uglier to use, but this is pretty good! Kevin On Wed, Jun 11, 2014 at 4:35 AM, Noam Yorav-Raphael noamr...@gmail.com wrote: You can achieve overloading which is equivalent to C++ by defining a trait for all the types a specific argument can get: ``` enum IntOrFloatEnum { Int, F64, } trait IntOrFloat { fn get_type(self) - IntOrFloatEnum; fn get_int(self) - int { fail!(); } fn get_f64(self) - f64 { fail!(); } } impl IntOrFloat for int { fn get_type(self) - IntOrFloatEnum { Int } fn get_int(self) - int { self } } impl IntOrFloat for f64 { fn get_type(self) - IntOrFloatEnum { F64 } fn get_f64(self) - f64 { self } } fn overloadedT: IntOrFloat(x: T) { match x.get_type() { Int = println!(got int: {}, x.get_int()), F64 = println!(got f64: {}, x.get_f64()), } } fn main() { overloaded(5i); // prints: got int: 5 overloaded(3.5); // prints: got f64: 3.5 } ``` This is equivalent to having to functions, overloaded(int) and overloaded(f64). From what I see, the compiler even optimizes away the logic, so the generated code is actually equivalent to this: ``` fn overloaded_int(x: int) { println!(got int: {}, x); } fn overloaded_f64(x: f64) { println!(got f64: {}, x); } fn main() { overloaded_int(5i); overloaded_f64(3.5); } ``` (I actually think that if Rust gains one day some support for overloading, it should be syntactic sugar for the above, which will allow you to define a function whose argument can be of multiple types. I don't like the C++ style of defining several different functions with the same name and letting the compiler choose which function should actually be called). Using this method you can solve both the problem of overloading and default arguments. For every possible number of arguments that C++ would allow, define a function funcNT0, T1, TN-1(arg0: T0, arg1: T1, ..., argN-1: TN-1). The function would check the actual types of the arguments and call the right C++ function, filling default arguments on the way. So the only difference between C++ and Rust code would be that you'd have to add the number of arguments to the method name. It would probably not be easy to generate the required code, but I think it would solve the problem perfectly. Cheers, Noam On Thu, May 22, 2014 at 11:27 PM, Alexander Tsvyashchenko n...@endl.ch wrote: Hi All, Recently I was playing with bindings generator from C++ to Rust. I managed to make things work for Qt5 wrapping, but stumbled into multiple issues along the way. I tried to summarize my pain points in the following blog post: http://endl.ch/content/cxx2rust-pains-wrapping-c-rust-example-qt5 I hope that others might benefit from my experience and that some of these pain points can be fixed in Rust. I'll try to do my best in answering questions / acting on feedback, if any, but I have very limited amount of free time right now so sorry in advance if answers take some time. Thanks! -- Good luck! Alexander ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org
Re: [rust-dev] Another idea on requiring mut prefix at call site
Just because I still think it might be a good idea -- if it turns out to be a good idea, it will be possible to add such a mut annotation to rust 1.1 and issue a warning if it is not being used, right? Noam On Apr 30, 2014 3:31 PM, Noam Yorav-Raphael noamr...@gmail.com wrote: Actually I realize that my suggestion doesn't solve any real problem. The example at reddit was quite strange, and as Patrick wrote, avoiding autoborrow of ~ to would solve it. The real place where such an annotation would help is where, like in Artella's example, a function gets a mut reference and passes it to another function. Then it's not clear whether the other function expects a non-mutable reference or is it going to mutate the variable. Then a solution might be to require writing mut before the name of a mut reference that can't be replaced with a non-mut reference. That is, in this example: fn mut_it(x: mut int) { *x += 1; } fn print_it(x: int) { println!({}, x); } fn f(x: mut int) { mut_it(x); print_it(x); } fn main() { let mut x = 1i; f(mut x); } You'll have to replace mut_it(x) with mut_it(mut x) On Wed, Apr 30, 2014 at 10:33 AM, Noam Yorav-Raphael noamr...@gmail.com wrote: Hi, I had a bug caused by a function mutating its arguments, and it had occurred to me that it may be a good idea if rust would require a mut prefix in that case. I asked on reddit, and was referred to this thread: https://mail.mozilla.org/pipermail/rust-dev/2014-January/007670.html In the above message, Patrick shows a few examples which show that it's hard to come up with rules on which arguments should be prefixed by mut that will be sound and complete. I have an idea which may be. The idea is to not look at function arguments but at uses of a variable. Here's a rule: Whenever a variable which was declared with let mut is being used in a way that would have been illegal have it not been declared with let mut, it should be prefixed by mut, unless it's obvious from the context that it has to be mutable. I think it's quite simple and says exactly what should be the rules in Patrick's examples. What's not well-defined is the obvious from the context part. Certainly when a variable is on the left hand side of an assignment there would be no need for mut annotation, as well as when it's being prefixed by mut. I don't know if there are other cases. (If you're interested in the bug: I had to use a function solve(A, b) which gets a matrix A and a vector b and returns a vector x such that Ax=b. It does Gauss elimination, and for efficiency it modified A and b instead of allocating new arrays. I used it like x = solve(A, b) and then used A again. It was in Fortran, so the arguments A and b were annotated as being in out, but of course it didn't stop my perfectly looking function from having a hidden bug.) What do you think? Noam ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Another idea on requiring mut prefix at call site
Hi, I had a bug caused by a function mutating its arguments, and it had occurred to me that it may be a good idea if rust would require a mut prefix in that case. I asked on reddit, and was referred to this thread: https://mail.mozilla.org/pipermail/rust-dev/2014-January/007670.html In the above message, Patrick shows a few examples which show that it's hard to come up with rules on which arguments should be prefixed by mut that will be sound and complete. I have an idea which may be. The idea is to not look at function arguments but at uses of a variable. Here's a rule: Whenever a variable which was declared with let mut is being used in a way that would have been illegal have it not been declared with let mut, it should be prefixed by mut, unless it's obvious from the context that it has to be mutable. I think it's quite simple and says exactly what should be the rules in Patrick's examples. What's not well-defined is the obvious from the context part. Certainly when a variable is on the left hand side of an assignment there would be no need for mut annotation, as well as when it's being prefixed by mut. I don't know if there are other cases. (If you're interested in the bug: I had to use a function solve(A, b) which gets a matrix A and a vector b and returns a vector x such that Ax=b. It does Gauss elimination, and for efficiency it modified A and b instead of allocating new arrays. I used it like x = solve(A, b) and then used A again. It was in Fortran, so the arguments A and b were annotated as being in out, but of course it didn't stop my perfectly looking function from having a hidden bug.) What do you think? Noam ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Another idea on requiring mut prefix at call site
Actually I realize that my suggestion doesn't solve any real problem. The example at reddit was quite strange, and as Patrick wrote, avoiding autoborrow of ~ to would solve it. The real place where such an annotation would help is where, like in Artella's example, a function gets a mut reference and passes it to another function. Then it's not clear whether the other function expects a non-mutable reference or is it going to mutate the variable. Then a solution might be to require writing mut before the name of a mut reference that can't be replaced with a non-mut reference. That is, in this example: fn mut_it(x: mut int) { *x += 1; } fn print_it(x: int) { println!({}, x); } fn f(x: mut int) { mut_it(x); print_it(x); } fn main() { let mut x = 1i; f(mut x); } You'll have to replace mut_it(x) with mut_it(mut x) On Wed, Apr 30, 2014 at 10:33 AM, Noam Yorav-Raphael noamr...@gmail.com wrote: Hi, I had a bug caused by a function mutating its arguments, and it had occurred to me that it may be a good idea if rust would require a mut prefix in that case. I asked on reddit, and was referred to this thread: https://mail.mozilla.org/pipermail/rust-dev/2014-January/007670.html In the above message, Patrick shows a few examples which show that it's hard to come up with rules on which arguments should be prefixed by mut that will be sound and complete. I have an idea which may be. The idea is to not look at function arguments but at uses of a variable. Here's a rule: Whenever a variable which was declared with let mut is being used in a way that would have been illegal have it not been declared with let mut, it should be prefixed by mut, unless it's obvious from the context that it has to be mutable. I think it's quite simple and says exactly what should be the rules in Patrick's examples. What's not well-defined is the obvious from the context part. Certainly when a variable is on the left hand side of an assignment there would be no need for mut annotation, as well as when it's being prefixed by mut. I don't know if there are other cases. (If you're interested in the bug: I had to use a function solve(A, b) which gets a matrix A and a vector b and returns a vector x such that Ax=b. It does Gauss elimination, and for efficiency it modified A and b instead of allocating new arrays. I used it like x = solve(A, b) and then used A again. It was in Fortran, so the arguments A and b were annotated as being in out, but of course it didn't stop my perfectly looking function from having a hidden bug.) What do you think? Noam ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why we don't like glob use (use std::vec::*)?
Perhaps it's not that important that it will be able to continue after errors? I think that generally there should not be type errors even while programming is in progress. It means that if I'm referring to something I have to immediately write a stub for it, but I don't think it's that bad. Noam On Wed, Mar 12, 2014 at 10:07 PM, Daniel Micay danielmi...@gmail.comwrote: On 12/03/14 03:52 PM, Clark Gaebel wrote: There is no accurate jump-to-definition, type retrieval, docstring retrieval or semantic completion for Rust. The compiler was not built with support for this kind of tooling in mind, and I seriously doubt that anything but inaccurate hacks will exist for a *long* time. This worries me a lot. It would need to be able to perform type checking/inference even if the file can't be fully parsed, or there are type errors in other places. At the moment, each phase simply assumes all of the previous stages were fully completed, and it bails out immediately on any error by unwinding via failure. It's easy to see this from the error reporting. Rust can report multiple errors within the same phase, but it's unable to report a type error if parsing fails. `clang` was designed with this kind of thing as a central pillar and is able to continue reporting errors or giving useful results to queries from tooling even if there are problems. It's not at all an easy task, and most compilers are not able to do it. A language like Go is simple enough that tooling like completion can be done without help from a compiler. However, Rust has powerful local type inference, which presents a difficult obstacle. Another enormous obstacle is the power of traits - a type can have methods provided by traits, if the trait is in scope and the type is covered by an implementation, which may be generic. ___ 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] bikeshedding println() and friends
On 15 July 2013 23:03, Graydon Hoare gray...@mozilla.com wrote: - format strings with nestable {n} placeholders rather than non-nesting %-placeholders, and simple conditional forms borrowed from the work Java and ICU/CLDR have done in this field. Would {} placeholders work as well (the first means {0}, the second {1}, and so on)? I really miss them in python 2.6 - they were added in python 2.7. Noam ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] The 'for' syntax for iterators
Hello, I want to point something that may be a reason for changing the 'for' syntax for external iterators: list comprehensions. I find list comprehensions (and generator expressions) in Python to be something that makes Python code much more concise, and make Python much more fun for data exploration. For example, without generator expression, I'd have to write instead of this: print mean(person.height for person in people if person.weight 30) something like this: L = [] for person in people: if person.weight 30: L.append(person.height) print mean(L) With rust moving to external iterators, it seems to me that adding list comprehensions is entirely possible. I'm not saying it should be done before 1.0, but it may be worthwhile to prepare for that. If the current syntax is preserved, the list comprehension should look something like this, to preserve consistency: mean(person.height for people |person| if person.weight 30) and even mean(person.height for families |family| for family |person| if person.weight 30) I find it much less readable than mean(person.height for family in families for person in family if person.weight 30) My point is that the choice of syntax may have consequences for more syntax. I'd be very happy to write a script to convert from for y |x| to for x in y, as I believe it would make rust significantly more easy to read and write (I believe it shouldn't be difficult given a tokenizer) One another point for switching the syntax: It may actually help the transition to external iterators. Have 'for x in y' handle only for external iterators and 'for y |x|' only internal iterators. Gradually replace all internal iterators by external ones, and when finished, remove the internal 'for' syntax from the language. I hope you'll pardon me for giving my opinion without being a developer - I just find rust really exciting, and would like it to be as perfect as it could be. Thanks for reading this, and have a great day, Noam ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The 'for' syntax for iterators
I find the code much easier to comprehend that way. Also, I don't know how you can write nested comprehensions with map and filter. Also, with map and filter you have to give names to variables both for map and for filter. Contrast: [name for name. age in zip(names, ages) if age 30] with zip(names, ages).filter(|name, age| age 30).map(|name, age| name) See http://en.wikipedia.org/wiki/List_comprehension - a lot of languages have list comprehensions. They're really useful. On 13 June 2013 19:44, Ziad Hatahet hata...@gmail.com wrote: Shouldn't we just be able to use map() and filter() routines to do the same? -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The 'for' syntax for iterators
Thanks for the answer! As I said, I really don't mean that list comprehensions should be added now - just that they may be added some time later, and that they're likely to use the same 'for' syntax. I believe you're going to find that rust's audience will be much wider than current C/C++ programmers. Say I want to write an application that is not very computationally heavy. Which language should I choose? Java and C# require a big runtime so hard to distribute, C# is windows-only, Java startup time is annoying. Python is slow and too dynamic (hard time refactoring). C/C++ will mean that I'll have to deal with segmentation faults all the time. Rust will be a perfect choice. See for example http://roscidus.com/blog/blog/2013/06/09/choosing-a-python-replacement-for-0install/ - 0install is a package manager that is currently written in Python. The developer is thinking of rewriting it in a different language. C/C++ are not considered (and rightly so), but rust is, and currently it wins the most points in the author's several comparisons! When rust will mature, it will get a lot more points (startup time, dependencies, tracebacks, standard library) and be a very clear winner. So definitely, make the language as simple as you can for the 1.0 release - it should be made as simple as possible, but not simpler. But I have the feeling that I, as a mainly-python programmer (a bit of C too), am going to enjoy rust quite a lot. And I actually think that with a bit of sugar and some good libraries, I may enjoy rust programming more than I enjoy python programming. tl;dr Rust is already gaining a lot of interest from non C/C++ programmers. I think they should be somewhere at the back of your mind when you are designing rust. Cheers. Noam On 13 June 2013 20:25, Tim Chevalier catamorph...@gmail.com wrote: At this point we're focusing on removing features from Rust. We're vanishingly unlikely to add list comprehensions at this point. Rust's audience is C and C++ programmers, who won't necessarily notice their absence anyway. (Personally, I almost never used list comprehensions when I programmed in Haskell -- I found using higher-order functions directly to be much more natural -- but that part is just my opinion.) Cheers, Tim -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt Not a riot, it's a rebellion. -- Boots Riley Attention Bros and Trolls: When I call out your spew, I'm not angry, I'm defiant. -- Reg Braithwaite ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The future of iterators in Rust
Hello, Would you mind going into detail about when you need iterators that mutate containers? I always think of iterators as having no side effects. I ask that because if somehow you can live with only external iterators, having one type of iterators instead of two seems to me like a great simplification of the language. Thanks, Noam On 6 June 2013 07:09, Daniel Micay danielmi...@gmail.com wrote: A quick terminology refresher, for those who aren't familiar with it: * Internal iterator: takes a closure, runs the closure until it asks to break * External iterator: state machine, advanced by the caller in a loop To a caller, external iterators provide the most functionality, because they can be used as an internal iterator. You lose the state of an internal iterator by breaking out of iterator, so generic algorithms like zip, union, intersect and merge can't be implemented for a pair of iterators. # Issues with internal iterators in Rust A few months ago, we only had internal iterators and there were no generic algorithms to use with any iterator - only with BaseIter's `each` method. Rust's internal iterators implement the protocol encoded in Rust's for statement, but it's not possible to give them all a common trait or implement generic methods or functions taking any internal iterator. As a workaround, we can write algorithms assuming internal iterators only take one argument (the closure): fn countT(f: fn(fn(T) - bool) - bool) - uint The caller has to use a partial function to call these adaptors, for which we lack sugar: count(|f| uint::range(0, 10, f)) For simple functions, this is fairly reasonable once you're used to it. It quickly gets out of control though, even for a simple function like filter: filterT(pred: fn(T) - bool, input: fn(fn(T) - bool) - bool, output: fn(T) - bool) - bool {} Sadly, `filter_ref` is also needed to work around closures behaving badly with lifetimes. An example of the problem with `fold_ref`: fn productT: One + MulT, T(iter: fn(f: fn(T) - bool) - bool) - T { fold_ref(One::one::T(), iter, |a, x| *a = a.mul(x)) } Since `product` expects an iterator yielding `T` (a borrowed pointer in any region), it won't work with `fold` because that requires the borrowed pointer to have the same type (and thus lifetime) for every iteration like `'a int`. This issue with borrowed pointers was blocking me from replacing the existing algorithms reimplemented for both `str` and `vec` with the generic ones. Chaining together iteration algorithms is a common use case, but even chaining two together is confusing at first: to_vec(|g| filter(|x| *x 3, |f| xs.each(f), g) Another more alarming issue is that with internal iterators, the `break` and `return` statements don't always work in a `for` loop. If the iterator isn't implemented correctly, the loop will keep going. This also has borrow checking implications, because the compiler can't assume those statements actually cause flow control to leave the loop immediately. # External iterators Based on the above, you might think generic iteration algorithms in Rust are a bleak prospect. However, we already have a nice external iterator library, and they don't suffer from the above issues. All kinds of external iterators implement the following trait, whether they are a fibonacci number generator, a reverse iterator over a vector or iterator over a range in a sorted set: pub trait IteratorA { /// Advance the iterator and return the next value. Return `None` when the end is reached. fn next(mut self) - OptionA; } Generic adaptors are implemented on `Iterator`, and many of them are `Iterator` implementations themselves: use std::iterator::*; fn main() { let mut it = Counter::new(0.0, 1.0) .take_while(|x| *x 1000.0) .transform(|x| x / 2.0) .transform(|x| x + 2.0); println(it.fold(0.0, |a, b| a + b).to_str()) } If you're curious, the optimized LLVM IR: http://ix.io/5Xl Unlike internal iterators, external iterators only run one iteration at a time, so a `for` loop designed for them would always be able to succeed with `break` and `return`. It would also be able to avoid the ugly `advance` wrapper currently required to use external iterators with `for`. // The current situation, wrapping an external iterator as an internal one // // Since the advance method is not known the be correct, borrow checking // still assumes `return` and `break` are imperfect. for xs.zip(ys).advance |x| { ... } // A hypothetical `for` loop using the `Iterator` trait for iterator |x| { ... } // It could also fall back to an `Iterable` trait and obtain an iterator for container |x| { ... } External iterators also avoid the problems with references and closures, because they simply
[rust-dev] Having zip() fail when the two iterators are not the same length
Hello, My name is Noam Yorav-Raphael. I find Rust to be a really exciting language! I have a simple suggestion: the current implementation of zip() returns an iterator which stops whenever one of the two iterators it gets stop. I use zip() in python quite a bit. I always have a few lists, where the i'th value in each corresponds to the same thing. I use zip in python to iterate over a few of those lists in parallel. I think this is the usual use case. In this use case, when the two lists have a different length it means that I have a bug. it seems to me that Python's behavior, and current Rust behavior, is contrary to Errors should never pass silently from the zen of Python. What do you think of changing this, so that zip() will fail in such a case? Another iterator, say, zipcut can implement the current behavior if needed. It will be my pleasure to implement this, if the suggestion is found useful. Thanks, and have a nice day, Noam ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Having zip() fail when the two iterators are not the same length
Indeed you can. But do you think of a useful, common use case? Starting to count from 0 is indeed very useful, but you can use enumerate() for this. It seems to me that in the rare cases where it's useful, a special version like zipcut should be used, so that the usual use case will be checked for errors. Noam On 5 May 2013 23:51, Daniel Micay danielmi...@gmail.com wrote: On Sun, May 5, 2013 at 4:49 PM, Masklinn maskl...@masklinn.net wrote: Now here's the question, to which I don't have an answer but which will tell you whether your suggestion makes sense — at least when compared to existing languages: is it possible to have an infinite vector in Rust, or to zip finite and infinite datastructures (iterators?) together? Yes, you can make infinite generators implementing the Iterator trait. One example of that is `iterator::Counter::new(1, 2)` which is the same as `[1,3..]` in Haskell. ___ 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