New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is it really a good idea to support generator function components and iterators/generators as virtual node in general? #127
Comments
According to https://exploringjs.com/es6/ch_generators.html there are:
If we stick to the idea, that elements are static and cannot ever change (or at least use it as a mental model), iterable shouldn't be considered as such. But in all examples I proposed in the issue I have started, I used generator function as a component and form an element before passing it further. When generator function is wrapped as such, as an element It will always represent a sequence of values starting over and over again each time rerendering takes place. |
@thephoenixofthevoid Again, many thanks for your feedback. Here's my response:
I've never said that generators should not be used. I've just said that iterators (aka. generator objects) are mutable and may cause trouble if you pass them around, as iterators mutate as soon as you read them.
Frankly, I really cannot think of anything that can easily be done in Dyo by using generator function components which is much harder to do in React. Do you have an exemple by any chance? The rule of thumb is (at least this is what I always propagate regarding the iterator design pattern in general): "If you use iterators locally/internally that's perfectly fine, but in a higher-level API don't pass iterators around, instead pass corresponding iterables around as these are no troublemakers and will not mutate when someoe will read them".
I've always talked about "iterators as children", would have been better to talk about "iterators as virtual nodes" - therefore I've changed the title of this issue. And by the way - if you have a look at my examples above (all working properly in Dyo): If the way |
@mcjazzyfunky React supports iterators/iterables as children, how is React's implementation different from your suggestion?
Can you post examples that post issues with iterators. On a secondary note iterators that implement the iterator protocol can a [Symbol.iterator] that would always allow you to re-start the iterator a-fresh, all JS built-in iterators implement this. |
Again as definition, to prevent misunderstandings: With An React actually does NOT support iterators as children (in newer version). Instead you'll get a warning:
Regarding your comment
I'm quite sure that's not true (at least not for the usual ECMAScript iterators) .. where does this information come from? Please have a look at the following demo: |
The main reason I've started this discussion is because this See for example this issue: Like I've said: At least for children, If I've understood @thephoenixofthevoid correctly you could argue that even if And last but not least, please compare virtual nodes and virtual elements in React with Dyo: In React virtual nodes and elements are completely immutable (at least React will not mutate them), now compare with Dyo's virtual nodes and elements: Not only that they are NOT immutable (as Dyo will modify them and so they only can be used once - I guess this is for performance reasons), with this "generator function components" feature you even have a case (maybe just subtle) where also not even reading is safe any longer ... this is really quite different to React. |
A generator object is both iterator and iterable
Do you have any use cases in mind? I can get behind removing iterables for element children i.e not supporting But we'd need a good good enough reason to create that disconnect, and wether as @thephoenixofthevoid has mentioned there are likewise cases where you would want them to be supported as it is. |
That is obviously true but that does not necessarily imply the following:
Or am I just missing something? ... I still claim that if you only have a usual ECMAScript iterator that the corresponding data can only be traversed once - which is the main problem I am talking about. The root of all evil is that in ECMAScript an iterator is also an iterable - this is really unusual and a big PITA IMHO, but what do I know....
To be clear: I am 100000% of the opinion that both |
Like said, I do not know a real-world example where Anyway, even if not a real-world use case, I think it's not easily understandable why in the following (React) demo that And to repeat my argument against |
That has nothing to do with generator functions and is solely related to the virtual node |
[Edit]: Maybe I did not understand correctly and my response below may not really about what you've meant: Still the problem is that generator functions return iterators and exact that iterator is the main problem here, so this has indeed something to do with the generator function (or any other component function that returns an iterator). No that's not really true: If React would allow The fact that Dyo does not allow virtual elements to be used several times (like React) is not the important point in my example.... |
Are there really use cases for function SomeSuperfancyAndForWhateverReasonsKindaLazyComponent(props) {
// do some fancy stuff here and use as many hook functions as you like
const generateContent = function* () {
// yield whatever you like but do not use hook functions here
}
return { [Symbol.iterator]: generateContent }
// // Unlazy aka strict alternative (btw: maybe missing keys could be a minor challange
// // in the above return pattern):
// return h(Fragment, ...generateContent())
}
Maybe I just don't see it .... |
The issue(on the example posted) is not with generators/iterators but with the way react/dyo deals with shared/immutable virtual nodes, thus a separate issue and not a point of contention for/against iterables/generators. Per this previous question:
Yes you can still always re-start the generator as demonstrated in the example on the page, but of course you can also create a custom iterable that intentionally does not work like built-in generators but that is another issue. However generators are always correct because we always re-excute them regardless because they are treated as components. |
@thysultan Sorry, but I really have to be blind ... where exactly on that page is mentioned that you can "always restart the generator" if the generator (aka "generator object" , which is an "iterator" aka "iterator object") itself is the only thing you have? let aGeneratorObject = function* () {
yield 1
yield 2
yield 3
}()
console.log([...aGeneratorObject]) // working => [1, 2, 3]
// would be good to kinda "restart" the generator object here
console.log([...aGeneratorObject]) // not working => [] |
Yes your right, i was mistaken on that point. i.e |
Okay, then to come to an end:
[Edit: No need to discuss the following ... just saying that maybe it would be nice if the documentation said what's allowed and what's not regarding generators] function DoNotKnowWhetherAllowedOrNot1() {
// Do I have to use keys here (like for other iterables)
// or are keys completely ignored in this special case?
yield (<X>1</X>)
yield (<X>2</X>)
yield (<X>3</X>)
}
function* DoNotKnowWhetherAllowedOrNot2() {
yield 1
// Are hooks allowed in future after first yield?
const [two] = useState(2)
yield two
yield 3
}
function DoNotKnowWhetherAllowedOrNot3() {
// Should this also be allowed in future? (IMHO it should not, but anyway....)
// do something fancy here
function* generateOutput() {
const [whatever] = useState('whatever') // IMHO hooks should not be allowed here any longer
yield whatever
// [...]
}
return { [Symbol.iterator]: generateOutput }
} |
You only need to use keys for computed children i.e
Yes.
It probably already is, given that resembles what generators do when you do
I ok with this, though in it's current iteration the implementation that handles both is more streamlined or simpler that the proposed. |
This is just to open a discussion about the question whether Dyo should really continue to support generator function components and generators (aka. iterators) as children in general.
For this issue, let's define an
Iterable
as an object that has a special property[Symbol.iterator]
whose value is a function that returns something that we callIterator
and that satisfies the corresponding ECMAScript iterator protocol (I think we all know the nature of that protocol).It's important to know that ECMAScript iterators themselves have a property
[Symbol.iterator]
whose value is a function that returns an iterator (each time the same (= identical) iterator will be returned!).That makes a iterator look and behave like a iterable (for example it can be used in a for-of loop).
But there's an important difference between ECMAScript iterators and "normal" ECMAScript iterables:
An iterator can only be traversed once ... while "normal" ECMAScript iterables can be traversed multiple times (virtually infinite times).
Dyo supports iterables as children (which is a really great feature and shall not be changed).
As Dyo currently traverse those iterable children only once it's not a problem that Dyo treats children that are iterators the same way as if they were "normal" iterables.
Therefore without any special logic, Dyo out of the box supports iterators as children as well.
Let's assume somewhere in future Dyo will be splitted into a DEV and a PRODUCTION package to allow additional checks on DEV system like some kind of uniqueness check for keys.
Or maybe a future Dyo will allow its API to be intercepted, similar to what you can do in Preact with this
options
object and someone wants to add some React-likeprop-types
validation in userland.In all such cases, children which are iterators will cause a lot of trouble as soon as the children need to be traversed twice and not just once. Some special userland extensions will not even be possible to be implemented because of that iterator issue.
If Dyo did not allow iterators as children in the first place, nobody would really miss that "feature" (would anyone?) and the win would be that there will be no trouble with iterators any longer and things would be better prepared for future extensions.
Here are a few example of iterators as children which currently are supported by Dyo but should not be supported in Dyo any longer in my opinon:
This behaves exactly the same as the following
Which behaves similar to:
Even if this looks quite unusual, the following example is currently working and should also be working in future, as the component returns an iterable, not an iterator, and therefore will never cause trouble:
The text was updated successfully, but these errors were encountered: