Also, can we define iterator/generators?
Hi,
Yes I should add docs on modules.
There are no iterators.
From wiki:
In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements.
V is not an OOP language, and design patterns go against the philosophy of simplicity.
A good talk about the drawbacks and complexity of iterators:
https://accu.org/content/conf2009/AndreiAlexandrescu_iterators-must-go.pdf
Thanks for the slides, although it fails to convince me. I think the slide takes from a purely C++ point of view, but reminber generator can belong to language as simple as Lua. I do not think OOP itself is bad and necessarily complex, it can be just an easy way for human to think about problem.
I was referring to iterators. Missed the generators bit.
Can you give a simple example of a generator?
On 20 Mar 2019, at 18:58, Wei notifications@github.com wrote:
Thanks for the slides, although it fails to convince me. I think the slide takes from a purely C++ point of view, but reminber generator can belong to language as simple as Lua. I do not think OOP itself is bad and necessarily complex, it can be just an easy way for human to think about problem.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/vlang-io/V/issues/36#issuecomment-474959532, or mute the thread https://github.com/notifications/unsubscribe-auth/AAp_fI8ODOPQET3HOHWQfunzG98uIpkYks5vYnbSgaJpZM4b94Rs.
A good example would be from Lua official documentation: https://www.lua.org/pil/7.5.html
I think “for val in vals { }” does the job
On 22 Mar 2019, at 16:36, Wei notifications@github.com wrote:
A good example would be from Lua official documentation: https://www.lua.org/pil/7.5.html https://www.lua.org/pil/7.5.html
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/vlang-io/V/issues/36#issuecomment-475667939, or mute the thread https://github.com/notifications/unsubscribe-auth/AAp_fIRBtups4ODIaqkydkzTqlrPba6Sks5vZPhggaJpZM4b94Rs.
Generators in many languages (C#, Python, JavaScript, and presumably others) have a lot to do with coroutines. This example in C# shows somewhat: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/yield#example
Upcoming C++20 and Rust features also enable this in similar fashions.
Whether it matters for V likely depends a lot on how V's coroutines end up working.
@medvednikov:
There are no iterators.
V is not an OOP language, and design patterns go against the philosophy of simplicity.
Iterator functions are just an interface, it's not OOP, there's no inheritance. The interface can be just two functions to:
A good talk about the drawbacks and complexity of iterators:
https://accu.org/content/conf2009/AndreiAlexandrescu_iterators-must-go.pdf
This talk is a critique of C++ iterators, the main problem with those is that start/end iterators are not paired, so the two might not match up, and by design this is not memory safe. This PDF proposes ranges instead, which are essentially just a pair of [C++] iterators. Andrei is the co-architect of D 2.0 and he designed ranges to be key to D's standard library.
Iterators/ranges allow generic algorithms to be written, which work with any container type, binary tree, linked list, array, hash table, etc.
I think “for val in vals { }” does the job
How do you write a generic algorithm that needs to iterate through two containers, whose types can be different, that needs to step through the first container at different times to stepping through the second, e.g. merge (the examples all use arrays but the function works on any two container types that have a common element type).
I don't have experience of generators/yield, but it looks easy to use - I imagine performance would be worse than normal iterators.
Also another feature I want in loop iteration: I can delete element(s) from the container on which I am currently iterating without any issue (for example, the language ensures it would not go into an infinite loop in this case).
The language has to be small and simple, for now this will not be implemented. Maybe in the future if we figure out a simple way to do this.
Hi @medvednikov , I don't understand why you find it complicated. For generators maybe a bit, maybe you just need to create a thread and have a coroutine in it. For iterators, they are a bit uglier than generators but are extremely simple and good enough as an alternative to generators.
Here's an example iterator struct:
struct Range {
end int
mut:
cur int
}
fn (r Range) has_next() bool {
return r.cur < r.end
}
fn (mut r Range) next() int {
return r.cur++
}
What people are asking for, I believe, is something like:
for i in Range{end: 10} {
println(i)
}
Which the V compiler should translate it to something like:
mut iter := Range{end: 10}
mut i := 0
for iter.has_next() {
i = iter.next()
println(i)
}
Where the iterator struct (e.g. Range) should be checked to have has_next() that returns a bool and next() that returns whatever (but returns something).
A bonus can be adding some syntax to delete elements and use an iterator function, say remove(), to delete elements.
Reopening for discussion.
A critical advantage of iterators for algorithms producing multiple values is that they do not need to allocate to produce output. Instead the output is generated only as it is about to be used (known as lazy evaluation). Allocation can be a major slowdown and is unnecessary with iterators. Here's a generic lazy algorithm:
struct Doubler {
mut:
val int
until int
}
// iterator primitive returning optional
fn (mut it Doubler) next() ?int {
v := it.val
if v > it.until {
return none
}
it.val *= 2
return v
}
fn doubler(start, until int) Doubler {
return Doubler{start, until}
}
mut d := doubler(5, 30)
// print 5, 10, 20
// `for` on an iterator
for e in d {
println(e)
}
// equivalent
for {
e := d.next() or {break}
println(e)
}
Here's an example of chaining generic functions together using a method call order operator. Each function produces an iterator and makes no allocations. It would work with any container type:
iter := container->filter(fn(e){e > 7})->map(fn(e){e * 2})
Most helpful comment
@medvednikov:
Iterator functions are just an interface, it's not OOP, there's no inheritance. The interface can be just two functions to:
This talk is a critique of C++ iterators, the main problem with those is that start/end iterators are not paired, so the two might not match up, and by design this is not memory safe. This PDF proposes ranges instead, which are essentially just a pair of [C++] iterators. Andrei is the co-architect of D 2.0 and he designed ranges to be key to D's standard library.
Iterators/ranges allow generic algorithms to be written, which work with any container type, binary tree, linked list, array, hash table, etc.
How do you write a generic algorithm that needs to iterate through two containers, whose types can be different, that needs to step through the first container at different times to stepping through the second, e.g. merge (the examples all use arrays but the function works on any two container types that have a common element type).
I don't have experience of generators/
yield, but it looks easy to use - I imagine performance would be worse than normal iterators.