Re: [rust-dev] Qt5 Rust bindings and general C++ to Rust bindings feedback

2014-06-12 Thread Noam Yorav-Raphael
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

2014-06-11 Thread Noam Yorav-Raphael
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

2014-06-11 Thread Noam Yorav-Raphael
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

2014-05-01 Thread Noam Yorav-Raphael
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

2014-04-30 Thread Noam Yorav-Raphael
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

2014-04-30 Thread Noam Yorav-Raphael
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::*)?

2014-03-13 Thread Noam Yorav-Raphael
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

2013-07-15 Thread Noam Yorav-Raphael
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

2013-06-13 Thread Noam Yorav-Raphael
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

2013-06-13 Thread Noam Yorav-Raphael
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

2013-06-13 Thread Noam Yorav-Raphael
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

2013-06-11 Thread Noam Yorav-Raphael
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

2013-05-05 Thread Noam Yorav-Raphael
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

2013-05-05 Thread Noam Yorav-Raphael
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