I think Dave has already made these points separately but it probably helps to 
recap more explicitly the behavior we expect from “x…"

Names are just for discussion purposes, exact naming can be left as a separate 
discussion from functionality:

- Informally, one-sided ranges are a thing. Formally, there are lower-bounded 
one-sided ranges, which are created with a postfix ... operator. For now, let’s 
just fully understand them and come back to upper-bounded ranges later.
- Collections will have a subscript that takes a one-sided range and returns a 
SubSequence. The behavior of that subscript is that the collection "fills in" 
the “missing” side with it’s upper/lower bound and uses that two-sided range to 
return a slice.*
- When the Bound type of a lower-bounded range is countable, it will conform to 
Sequence.** The behavior of that sequence’s iterator is that it starts at the 
lower bound, and increments indefinitely.
- One-sided ranges should have ~= defined for use with switch statements, where 
any value above the bound for a lower-bounded range would return true.

* implementation detail: collections would probably have a generic subscript 
taking a type conforming to RangeExpression, and that protocol would have a 
helper extension for filling in the missing range given a collection
**one-sided ranges ought in fact to be infinite Collections… a concept that 
needs a separate thread

With that defined:

> On Feb 1, 2017, at 5:02 AM, Xiaodi Wu via swift-evolution 
> <[email protected]> wrote:
> 
> I entirely agree with you on the desired behavior of `zip(...)`.
> 
> However, if you insist on 0... being notionally an infinite range, then you 
> would have to insist on `for i in 0...` also trapping. Which is not a big 
> deal, IMO, but will surely make the anti-trapping crowd upset.
> 

Certainly, for i in 0… would trap once the iterator needs to increment past 
Int.max. If you break out of the loop before this happens, it won’t trap. The 
statement is the moral equivalent of a C-style for(i = 0; /*nothing*/ ; ++i).

If the anti-trapping crowd are upset, they should be upset with Int, not this 
range type. The range has no opinion on trapping – its iterator just increments 
its Bounds type when asked to.

> The bigger issue is that either you must have a lenient/clamping subscript 
> for `arr[0...]` or it too must trap, which is not desired.

Based on the definition I give above, arr[0…] means “from 0 up to the endIndex 
of arr”. This will not trap.

(there is a legitimate quibble here that this will translate into 
arr[0..<arr.endIndex], but the … kind of implies arr[0…arr.endIndex] which is 
invalid. But 0..< is ugly so we should ignore this quibble for the sake of 
aesthetics)

> However, if `arr[0...]` is clamping, then `[1, 2, 3][100...]` would not trap 
> and instead give you `[]`.
> 

It should trap, because 100..<arr.endIndex is not a valid argument for slicing 
this array.

> If 0... is regarded as an incomplete range, your example of `zip(...)` could 
> still trap as desired. It would trap on the notional attempt to assign 
> someArray.count to IncompleteRange<T>.inferredUpperBound if count exceeds 
> T.max.

It’s unclear to me whether you are trying to formally define 
.inferredUpperBound as a property you expect to exist, or if you’re using it as 
informal shorthand. But there is no implied upper bound to a one-sided 
lower-bounded range, only an actual lower bound. Operations taking 
lower-bounded ranges as arguments can infer their own upper bound from context, 
or not, depending on the functionality they need.

As an example of an alternative inferred upper bound: suppose you want to 
define your own ordering for ranges, for sorting/display purposes. You decide 
on a lexicographic ordering first by lower then upper bound. You want one-sided 
ranges to fit into this ordering. So you infer the upper bound to be infinite, 
for sorting purposes, so: 0…5 < 0… < 1…4 < 1…5 < 1…. This does not mean the 
upper bound is implied to be infinite, just that the sorting predicate infers 
it to be, for the purpose of sorting.

> With such semantics for 0..., [1, 2, 3][0...] would behave as expected 
> without the need for leniency, but [1, 2, 3][100...] would trap as I assume 
> you'd expect.

[1,2,3][0…] is valid because the array has an index of 0, but [100…] isn’t 
because it doesn’t.

It’s worth noting the difference with Python here. In Python, [][2:] is valid 
because [][2:n] is valid (both return []). In Swift, [][2…] should be invalid 
(trap) because [][2..<n] is invalid.

> However, it would make no sense to write `for i in 0...`.
> 

I don’t see how. But regardless, the definition of how countable lower-bounded 
ranges conform to Sequence is just something to be defined in some way that is 
useful and intuitive to users. 0… being an indefinitely increasing sequence 
seems like it’s intuitive to me, as does a[n…] being “a slice from n to the 
end”.

That definition does not need to be unearthed based on some underlying 
principles. Defining behavior based on building upon axioms is a useful 
approach sometimes, but if at any point we are finding they get in the way of 
implementations within the std lib being intuitive or useful, we should stop 
trying to bend over backwards to stick with this approach.


> On Tue, Jan 31, 2017 at 21:39 Dave Abrahams <[email protected] 
> <mailto:[email protected]>> wrote:
> 
> on Tue Jan 31 2017, Xiaodi Wu <xiaodi.wu-AT-gmail.com 
> <http://xiaodi.wu-at-gmail.com/>> wrote:
> 
> > But that's not getting to the biggest hitch with your proposal. If
> > subscript were lenient, then `arr[lenient: 42...]` would also have to give
> > you a result even if `arr.count == 21`.
> >
> > This is not at all what Dave Abrahams was proposing, though (unless I
> > totally misunderstand). He truly doesn't want an infinite range. He wants
> > to use a terser notation for saying: I want x to be the lower bound of a
> > range for which I don't yet know (or haven't bothered to find out) the
> > finite upper bound. It would be plainly clear, if spelled as `arr[from:
> > 42]`, that if `arr.count < 43` then this expression will trap, but if
> > `arr.count >= 43` then this expression will give you the rest of the
> > elements.
> 
> I think you do misunderstand.  Notionally, 0... is an infinite range.
> The basic programming model for numbers in swift is (to a first
> approximation), program as if there's no overflow, and we'll catch you
> by trapping if your assumption is wrong.  It doesn't make sense for the
> semantics of 0... to depend on the deduced type of 0 or the
> representable range of Int
> 
> for example,
> 
>     for x in zip(n..., someArray) {
> 
>     }
> 
> How many iterations should this give you?  If it doesn't process all of
> someArray, I want a trap.
> 
> --
> -Dave
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to