[swift-evolution] [Pitch] Named subscripts

Xiaodi Wu xiaodi.wu at gmail.com
Fri Nov 18 03:39:05 CST 2016


Sorry, can you explain what you mean when you say you must have a setter?
Why would you mutate the view and not the array itself (`foo[42] =
.double(42)` as opposed to `foo.double[42] = 42`)?

On Fri, Nov 18, 2016 at 03:25 Adrian Zubarev via swift-evolution <
swift-evolution at swift.org> wrote:

> Thank you guys for all your suggestions so far.
>
> I understand the idea behind the generic subscript here, they are neat and
> highly needed, but even this approach won’t solve my issue of clarity here.
>
> The Array I extend here has an Element of type Value which is an enum
> that wraps other types around (part of BSON).
>
> I’d have to insert a huge pattern matching switch into that generic
> subscript and unwrap every possible type. Don’t get me wrong, this would
> work, because the result type is an optional, where I just can return nil
> if nothing matches.
>
> But again I lose the clarity from the readers prospective, because I don’t
> know by reading code like array[at: 123] = someValue what kind of
> subscript I’m using here.
>
> As already suggested, the view workaround would result in the exact the
> same syntax I look for, but it has it own downsides as I already mentioned
> (+ every time you’d need to instantiate a new view).
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 18. November 2016 um 09:55:00, Haravikk (swift-evolution at haravikk.me)
> schrieb:
>
> Could this be addressed by allowing generic constraints on subscripts?
> For example, with methods we can currently do:
>
> struct Foo {
> var values:[Any] = []
>
> func get<T>(at:Int) -> T? {
> return values.indices.contains(at) ? values[at] as? T : nil
> }
>
> func get<T>(at:Int, as theType:T.Type) -> T? {
> return values.indices.contains(at) ? values[at] as? T : nil
> }
>
> mutating func set<T>(at:Int, to:T) {
> if values.indices.contains(at) { values[at] = to }
> }
> }
>
> let foo = Foo(values: [1.5, 2.5, 3.5, 1, 2, 3])
> let a = foo.get(at: 0, as: Double.self)
> let b:Double = foo.get(at: 1)!
> let c:Int? = foo.get(at: 2)
> let d = foo.get(at: 3, as: Double.self)
> let e:Int = foo.get(at: 4)!
> let f = foo.get(at: 5, as: Int.self)
>
> i.e- the type is inferred from the call-site either with an explicit
> variable type, or by passing in the expected type as the second argument,
> which I think is a pretty neat way to do it.
>
> If we could do the same with subscripts we could do something like:
>
> struct Foo {
> var values:[Any] = []
>
> subscript<T>(_ at:Int) -> T? {
> get { return values.indices.contains(at) ? values[at] as? T : nil }
> set { if values.indices.contains(at) { values[at] = newValue } }
> }
>
> subscript<T>(_ at:Int, as theType:T.Type) -> T? {
> return values.indices.contains(at) ? values[at] as? T : nil
> }
> }
>
> let foo = Foo(values: [1.5, 2.5, 3.5, 1, 2, 3])
> let a = foo[0, as: Double.self]
> let b:Double = foo[1]!
> let c:Int? = foo[2]
> let d = foo[3, as: Double.self]
> let e:Int = foo[4]!
> let f = foo[5, as: Int.self]
>
>
> Are generic constraints on subscripts part of the generics manifesto?
>
> On 17 Nov 2016, at 20:14, Adrian Zubarev via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Dear Swift community,
>
> while building a framework for BSON I had the following idea.
>
> Here is a snippet of some code I do have in my module:
>
> extension Array where Element == Document.Value {
>
>     public func double(at index: Int) -> Double? {
>
>         guard self.startIndex <= index && index < self.endIndex else { return nil }
>
>         if case .double(let double) = self[index] {
>
>             return double
>         }
>         return nil
>     }
>
>> }
>
> This function is used to query the array and check if the element at the
> given index is of a specific type. Now I would like also to implement a
> semi-schema setter.
>
> The problem that I see, is the ugliness of the subscript I’d create.
>
> Currently the code would read nicely let d = array.double(at: 42), but
> after change to a subscript the API would look odd array[doubleAt: 42] =
> 5.0.
>
> Don’t get me wrong here, I also have methods with larger names like public
> func scopedJavaScript(at index: Int) -> …. You can easily imagine that
> such subscripts would look ugly array[scopedJavaScriptAt: 123] = ….
>
> I propose to align the design of subscript with functions where one could
> optionally give subscript a name.
>
> func name(label parameter: Type) -> ReturnType
>
> subscript optionalName(label parameter: Type) -> ReturnType
>
> This change would make my API nice and clean. array.scopedJavaScript[at:
> 213] = …
>
> This also might be the opportunity to rethink the labeling rule on
> subscripts, but this shall not be the main focus of this pitch.
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161118/c4f191f9/attachment.html>


More information about the swift-evolution mailing list