Isn't a[checked: i] just as problematic because the notion of checked/unchecked here is confusing?
(-Ounchecked)
As was also mentioned upthread: people might ask why there is a[checked: i] when a[i] is already checked …
Isn't a[checked: i] just as problematic because the notion of checked/unchecked here is confusing?
(-Ounchecked)
As was also mentioned upthread: people might ask why there is a[checked: i] when a[i] is already checked …
Yeah, and it can also seem like you're saying that you've check i before passing it as an argument. lenient avoids these problems, as does anything that begins if*.
Yes I'm sorry I noticed that afterwards and didn't get to edit.
Your example was fitting but I think it's also more complex to write it that way
(0 ..< count).flatMap({
guard let second = array[checked: $0 + 1] else { return nil }
return (array[$0], second)
})
than doing it forced like
(0 ..< count - 1).map({ (array[$0], array[$0 + 1]) })
It might be worth noting that Array's existing subscript behavior is not that unique after all, if looking at it like this:
let arr: Array<Int> = [1, 2, 3]
let _ = arr[arr.endIndex] // Fatal error
let str: String = "abc"
let _ = str[str.endIndex] // Fatal error
let set: Set<String> = ["a", "bc", "def"]
let _ = set[set.endIndex] // Fatal error
let dic: Dictionary<String, Int> = ["a" : 1, "b": 2]
let _ = dic[dic.endIndex] // Fatal error
What if, instead of adding another subscript for Array's Index, we add a subscript for some new type (FooIndex), similar to how Set and Dictionary have subscripts for not only their Index (trapping if it's out of bounds, as seen above), but also for their Element/Key (returning an Optional)?
Quick question: Isn't the default version also checked in some way? Otherwise, how does it know to throw?
It doesn't throw, it uses precondition. It will crash at runtime unless you compiled with -Ounchecked (where it could lead to worse issues).
Yes, it's done in a function called _checkValidSubscript , which traps on invalid accesses.
I have already told that I don't like the idea, but if it ends up in the standard library, I agree that checked: is confusing as well. From @xwu's suggestions, I can live with some form of if*. How about a[checking: i]?
If you want the keyword to refer to the index, then surely unchecked: is what you want ("this index is unchecked, so be careful when looking in the array").
If you want the keyword to refer to the act of subscripting, then surely checking: is what you want ("…checking the index as you look in the array").
The problem with checked: is that it's supposed to mean "checked result with an unchecked index", which just seems confusing.
I kind of like "unchecked"
I don't like it either, and I agree that some form of a[ifXxx: i] would be less confusing than a[safe: i] and a[checked: i]. I think a[checking: i] is almost as confusing as a[checked: i] (since it sort of implies that a[i] wouldn't be checking the index). Perhaps a[existing: i] ...
And IMHO the current proposal would actually add rather than remove an exception, as explained in my previous post. I think other options should be considered, like:
Using a subscript for a new type (eg SpecialArrayIndexThatIsCorrespondingToDictionarysKeyAndSetsElement, but sensibly named), for consistency with other collection types (again motivated by my previous post).
Using a method, eg a.element(ifExistingFor: Index) -> Element?
I agree. This feels more intuitive because, conventionally in Swift, function labels describes its parameter.
Maybe "nilOr:" would work as a name?
let e = arr[ nilOr: 7 ]
This, in my mind, looks like it will return either nil or 7, instead of the value at index 7.
I read it as "arr subscripted with nil or 7" (which is also confusing).
arr[lenient: 7] is the only one that hasn't been debated for being confusing, and I prefer it even though I, as a non-native english speaker, had to look "lenient" up in a synonyms dictionary.
But again, I don't see any real reason why this should be solved by overloading Array's existing subscript(index: Index), especially since the existing one behaves exactly like it does in the other collection types, eg Dictionary and Set, ie they all trap if the Index value is out of bounds.)
So what are the arguments against giving up these subscript parameter naming attempts in favor of a method like:
let optionalElement = arr.element(ifExistingAt: 7)
or
let optionalElement = arr.element(at: 7)
?
I'm a non native speaker too and should look it up too. I only have a vague idea of the meaning. I'm inclined to look at this word as a little bit obscure internationally…
While we are at bikeshedding. What about failable:? subscript(failable i: Index) reads quite natural for my taste. Looking up this index might fail, but it doesn't crash. Conveying the same notion as failable initializers do.
Anyway. I personally have no opinion if we really need such a failable subscript…
If this would be added however, I think there should be an accompanying setter. I was trying to implement one (on the basis of @Erica_Sadun s original implementation) and failed.
The type of the newValue in the setter matches the return type of the getter. Sounds straight forward. But an Optional<Type> can not be assigned to an array whose elements or of type Type. o_O This could be unwrapped. OK. But if the array itself contains optionals the newValue will be of type Optional<Optional<Type>> and a legal nil value can't be unwrapped, nor assigned to Element, because the compiler does't know that Element is actually an optional…
Well, this should probably go better into the 'using Swift' subsection, but is it actually possible to write a setter in this case? As I said I failed… :(
(Post withdrawn because of the array of optionals issue raised by @torquato)
If a setter is supported, I think it should extend the array until the desired index exists and then set the value (but this would not be compatible with ArraySlice), or it should do nothing (probably the most consistent).
I considered that and then realized this (1) could be bad for memory allocation and (2) there is no default value to fill in for the elements that have not been assigned a value
Good point--so I think the most consistent result would be for setting a non-existent index to do nothing. That seems entirely fair and reasonable.