Rust Ownership Explained with Python
I can’t comment on the general case, but I disagree very strongly with the author’s perspective about generator expressions here.<p>First, a generator is a precise type of data structure that can be exhausted. If you don’t want that, don’t use that structure. It’s foolish to say that just because a data structure superficially satisfies some API (like being passable to min), that it “ought to have” some behavior that the author wants. That’s backwards. If you want certain behavior, choose a data structure that supports it.<p>It would be no different from saying if I have a heap and I call sort() it is faster than if I have the same data in a list and call sort(). They both support sort() so why aren’t they equally fast? It’s obviously the wrong way to think about it. Instead, use the appropriate data structure.<p>And if you’re really worried about the operation being safe, use the provided default argument, or the pattern for versions before 3.4, as in [0], or write a wrapper function that catches whatever exceptions and handles them.<p>This isn’t even the biggest issue though. Generators generally are meant to function as coroutines and for complex generators, you can use send() to set the “returned value” of a yield statement inside the generator for when it resumes, and so a single generator could go through stages of being exhausted and empty, then having a value set again so that on resumption it’s no longer empty, and could build back up a whole iterable of data that way.<p>So you absolutely do want min() or max() to throw errors when trying to consume from an empty generator, and you absolutely do want a generator’s state to become modified by the way values are consumed or added, because it meaningfully represents the state of the generator. Suppose for a more complex generator, someone uses send() to feed it a value between your call to min() and your call to max().<p>Generator expressions that superficially look like list comprehensions are just one use case of the general data structure and in fact one of the “generators 101” pieces of advice you always see is that if you need to iterate the values multiple times, then populate a persistent data structure out of the generator, like by wrapping in list().<p>I bring this up because it frustrates me to see people acting like a type safety or borrow checking idea is somehow aadding something new or solving some type of problem that the dynamic typing approach doesn’t or can’t solve, but this is emphatically incorrect and a severely myopic way to look at it.<p>The dynamic typing approach solves all the same problems, it just facilitates the solution differently: use the default argument or other patterns for safety on functions that can fail on empty containers, and use custom wrappers with exception handling when you need to. Choose a persistent data structure if you need persistence.<p>Again, not saying this has anything to do with people’s big picture reasons for liking static types or borrow checking... just this particular example strikes a chord to me highlighting the super annoying myopia about it.<p>[0]: &lt; <a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;36157995&#x2F;a-safe-max-function-for-empty-lists" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;36157995&#x2F;a-safe-max-func...</a> &gt;