on Sat Feb 04 2017, Jonathan Hull <[email protected]> wrote:
>> On Feb 2, 2017, at 2:19 PM, Dave Abrahams <[email protected]> wrote: >> >> >> on Thu Feb 02 2017, Jonathan Hull <jhull-AT-gbis.com> wrote: >> >>> Just out of curiosity, what are the use-cases for an infinite sequence >>> (as opposed to a sequence which is bounded to the type’s representable >>> values)? >> >> 1. The type may not have an inherent expressible bound (see BigInt, >> UnsafePointer, and *many* real-life Index types). > > If I understand what you are saying, this is why I was arguing that > these partial ranges should not, by themselves, conform to Sequence. > In cases where you do have a natural expressible bound, then it should > conditionally conform to sequence. I'm sorry, I don't understand that last sentence. The only way to conditionally conform in one particular case is to make the conformance condition include detection of that case. I could guess at what you mean but I'd rather you explain yourself. Specifically, which partial ranges should conform to Sequence, and which shouldn't, in your view? > In other cases, you should have to write that conformance yourself if > you want it. You've asserted that things should be a certain way (which I don't fully understand but I hope you'll explain), but you haven't said anything to clarify *why* you think they should be that way. >> 2. I keep repeating variants of this example: >> >> func listElements< >> S: Sequence, N: Number >>> (of s: S, numberedFrom start: N) { >> for (n, e) in zip(start..., s) { >> print("\(n). \(e)") >> } >> } >> >> which avoids incorrect behavior when N turns out to be a type that >> can't represent values high enough to list everything in s—**if and >> only if** `start...` is an unbounded range, rather than one that >> implicitly gets its upper bound from its type. > > I really worry about the possibility of long-term foot-gunning in this > case. I showed this to a friend who maintains old/abandoned codebases > for a living, and he said “Oh god, that isn’t going to actually crash > until 5 years in, when it gets passed some rare type of file… and by > then the original programmer will have left.” Then either he's using the wrong language, or he needs to come to grips with the realities of software that's both reliable and efficient. Swift explicitly acknowledges that in efficient code there are inherent representational limitations that force a choice between stopping the program and continuing with incorrect behavior. Swift explicitly chooses to stop the program in these cases. Practically speaking, every program written in Swift is full of checks for these conditions, and this is nothing new. > He hit on exactly what I had been feeling as well (but hadn’t been > able to put into words until I heard his). The thought is that this > will help the programmer find an error by trapping, It will also prevent a program from wandering off into unpredictable/broken behavior in the hands of a user. If your software keeps running but writes a corrupted file, that's usually much worse than a hard stop. > but because it is dependent on the interactions of two subsystems, it > will often create one of those crashes where the stars have to align > for it to happen (which are my least favorite type of bug/crash to > debug). You could look at it that way, but even in a programming language such as Python, whose integers are effectively all BigInts, a similar “stars-have-to-align” scenario occurs when you run out of memory. On modern opeerating systems that effectively means your whole system grinds to a halt. It is no better than a crash, and often leads to a crash (sorry, you have no stack space left with which to make this function call!) These things are a fact of life. > I think this example also shows how my suggestion of requiring an > extra protocol for conformance to Sequence would actually be much more > effective in preventing the programmer error… > > You would not have been able to write the function the way you did, > because writing ‘start…’ as a sequence would have required the > addition of ‘where N:FiniteComparable’ (or whatever we call the > protocol providing natural bounds). In having to write that N needs > bounds, you are much more likely to be thinking of what those bounds > might be. I explicitly *don't want* N to need to have expressible bounds. When we get a BigInt type, it will be especially effective in these scenarios. > The problem here is really with the design of the listElements > function in allowing/encouraging that error, as opposed to the > caller... and the trap is more likely to make you look at the call > site because of the context of when it happens. I think if you diligently apply that line of reasoning to large systems, you'll quickly find that writing them becomes impossible ;-) > Having to write the ‘where’ statement makes you reconsider the design > of the function, again because of the context of when it happens. -- -Dave _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
