[swift-evolution] [Pitch] Named subscripts

Rien Rien at Balancingrock.nl
Fri Nov 18 03:45:05 CST 2016


> On 18 Nov 2016, at 10: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. 
> 

Is that necessary?
Either the user knows the type of his ‘someValue’ or he does not. If not then I assume that he does not need to know. If he needs to know then inspection functions can make the discovery process simple.
In general I try to hide implementation details that do not matter to the user.

Rien.

> 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





More information about the swift-evolution mailing list