4 ms·
In Java you can't have a class implement both Iterator<Foo> and Iterator<Bar> (type erasure; or maybe my Java is out of date...). Anyway if you could, the for l
by mmoskal 2y ago
In Java you can't have a class implement both Iterator<Foo> and Iterator<Bar> (type erasure; or maybe my Java is out of date...). Anyway if you could, the for loop would not know which to use.
In Rust you could have both Iterators if it had a type parameter.
- withoutboats3 2y agoYes, this is the actual reason. In Java you're restricted to one implementation of an interface for a type by syntactic construction (classes list their interfaces in their header and each interface can only appear once). In Rust there is a similar restriction (called coherence), but it takes into account all of the parameters to a trait, including its generics. An illustrative example of the difference: `AsRef<T>` and `Deref` have almost identical signatures, except that the target type for `AsRef` is a parameter and for `Deref` is an associated type. `String` implements `AsRef<str>`, `AsRef<Path>`, and so on, but only `Deref<Target = str>`. The blog post's meandering description the difference between static and dynamic dispatch has no relevance whatsoever.
- tsimionescu 2y agoSo basically, Java's generic interfaces are equivalent to Rust's traits with associated types, and Java has no equivalent for a Rust trait with type parameters, at least in terms of this part of the language. I'm not sure how or if Rust traits can be used as function parameters - can I have a function that takes a parameter of type Iter? Can it take any implementation of Iter than, regardless of what item type that returns? How would I define a function that only accepts iterators that return, say, i32 items?
- AlotOfReading 2y agoYou'd write it as a type parameter with a type bound. There's a couple of different ways to write it, but one example: fn foo<I>(it: I) where I : Iterator<Item = i32> {}
- LegionMammal978 2y ago> can I have a function that takes a parameter of type Iter? fn example<I: Iterator>(iter: I) { ... } // or: fn example<I>(iter: I) where I: Iterator { ... } // or: fn example(iter: impl Iterator) { ... } > Can it take any implementation of Iter than, regardless of what item type that returns? Yes, in the above example. Then, the item type can be referred to as "<I as Iterator>::Item", or "I::Item" for short, unless you use the "impl Trait" syntax. You can also give the item type a name by giving it its own type parameter: fn example<T, I: Iterator<Item = T>>(iter: I) { ... } > How would I define a function that only accepts iterators that return, say, i32 items? fn example<I: Iterator<Item = i32>>(iter: I) { ... } // etc., just write Iterator<Item = i32> in place of Iterator
- Someone 2y agoDoes that matter for Iterator? You can have class FooIterator implements Iterator<Foo>{…} class BarIterator implements Iterator<Bar>{…} class MyCollection { public Iterator<Foo> foos { return new FooIterator(this); }; public Iterator<Foo> bars { return new BarIterator(this); }; } It would matter for Iterable. You cannot have this: class MyCollection implements Iterable<Foo>, Iterable<Bar>{…} , but there, there’s a second problem: in Java, you can’t have overloads that only differ in their return type.
- comex 2y agoIt's not useful to have a type implement Iterator for multiple element types. But in Rust, if Iterator took the element type as a generic parameter, it would be possible. The fact that it's not useful is precisely why Rust makes the element type an associated type instead. The benefits of using an associated type (compared to using a generic parameter in Rust, not compared to Java) include clarity, possibly improving type inference, and avoiding issues with crate coherence by requiring that the Iterator impl live in the crate that defines the input type, rather than the one that defines the output type.