[swift-evolution] [Pitch] Named subscripts
Rien
Rien at Balancingrock.nl
Fri Nov 18 05:38:08 CST 2016
> On 18 Nov 2016, at 11:45, Adrian Zubarev via swift-evolution <swift-evolution at swift.org> wrote:
>
> The reason here is because the setter acts like semi-schema setter.
Ah, ok.
Just wondered because I had a similar case in SwifterJSON. Eventually I settled for the absence of user-supplied type information while creating the JSON object. On read however, type information must be specified for safety (semi-schema read).
>
> For the given array example:
>
> array.double[at: 42] // would return a nil, if the index is out of bounds, or if the wrapped `Value` instance at the given index is not `.double(Double)`
>
> array.double[at: 42] = 2.0 // would update the value iff the wrapped `Value` instance is `.double(Double)`, otherwise the setter will do nothing
>
> This is a semi-schema approach and different from overriding any existing value at the given index like array[42] = .double(2.0)
>
> About the mutation problem you can find the short talk here, right at the bottom.
>
> If there is no setter for your view, array.double[at: 42] = 2.0 simply won’t work.
>
> Please proof me wrong here, if there is a better way to solve the problem. :)
>
> I appreciate any suggestions.
>
> So far we had no concrete arguments agains optionally named subscripts. Anything you dislike about that?
>
No, in fact +1
Regards,
Rien
Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl
> Personally I don’t think they hurt any Swiftiness at all.
>
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 18. November 2016 um 10:39:17, Xiaodi Wu (xiaodi.wu at gmail.com) schrieb:
>
>> 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
>
> _______________________________________________
> 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