> On Jun 16, 2017, at 3:43 PM, Mark Lacey <[email protected]> wrote:
> 
> 
>> On Jun 16, 2017, at 1:21 PM, Mark Lacey <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>>> 
>>> On Jun 16, 2017, at 11:13 AM, Paul Cantrell via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>>> 
>>>> On Jun 15, 2017, at 7:17 PM, Xiaodi Wu via swift-evolution 
>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>> 
>>>> 
>>>> On Thu, Jun 15, 2017 at 19:03 Víctor Pimentel <[email protected] 
>>>> <mailto:[email protected]>> wrote:
>>>> On 16 Jun 2017, at 01:55, Xiaodi Wu via swift-evolution 
>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>> 
>>>>> On Thu, Jun 15, 2017 at 17:43 David Hart <[email protected] 
>>>>> <mailto:[email protected]>> wrote:
>>>>> 
>>>>> By the way, I’m not attempting to deduce that nobody uses this feature by 
>>>>> the fact I didn’t know about it. But I think it’s one interesting 
>>>>> datapoint when comparing it to SE-0110.
>>>>> 
>>>>> 
>>>>> SE-0110, **in retrospect**, has had impacts on a lot of users; 
>>>>> prospectively, it was thought to be a minor change, even after review and 
>>>>> acceptance.
>>>>> 
>>>>> Keep in mind that this proposed change would also eliminate inline tuple 
>>>>> shuffle. For instance, the following code will cease to compile:
>>>>> 
>>>>> let x = (a: 1.0, r: 0.5, g: 0.5, b: 0.5)
>>>>> func f(color: (r: Double, g: Double, b: Double, a: Double)) {
>>>>>   print(color)
>>>>> }
>>>>> f(color: x)
>>>>> 
>>>>> It is an open question how frequently this is used. But like implicit 
>>>>> tuple destructuring, it currently Just Works(TM) and users may not 
>>>>> realize they’re making use of the feature until it’s gone.
>>>> 
>>>> It's much much less used, by looking at open source projects I doubt that 
>>>> a significant portion of projects would have to change code because of 
>>>> this.
>>>> 
>>>> The reason that I’m urging caution is because, if I recall correctly, that 
>>>> is also what we said about SE-0110 on this list. Then, as now, we were 
>>>> discussing an issue with something left over from the Swift 1 model of 
>>>> tuples. Then, as now, we believed that the feature in question was rarely 
>>>> used. Then, as now, we believed that removing that feature would improve 
>>>> consistency in the language, better both for the compiler and for users. 
>>>> Then, as now, leaving it in was thought to prevent moving forward with 
>>>> other features that could improve Swift.
>>> 
>>> Data:
>>> 
>>> I hacked up a regexp that will catch most uses of labeled tuples in pattern 
>>> matches, e.g. “let (foo: bar) = baz”. That’s what we’re talking about, 
>>> right?
>> 
>> That’s the obvious example that people find confusing.
>> 
>> Less obvious places that labeled tuple patterns show up are ‘case let’ and 
>> ‘case’ (see below).
> 
> Okay, I should have looked at your regex and read further. It looks like you 
> were already trying to match these.

I did walk the grammar for all occurrences of _pattern_.

I’m only matching named tuple patterns that immediately follow one of the 
keywords which a pattern follows (for, case, let, var, and catch). As I 
mentioned, I’m not matching patterns that come later in comma-separated lists. 
I’m also not matching named tuples inside nested patterns, e.g. let ((a: b), 
(c: d)).

But again, if even the most basic form of this construct is so rare, I doubt 
more robust matching would turn up that much more usage.

> I’m surprised you’re not seeing any uses of ‘case’ with labels.

Me too. But I just verified that my pattern does match them.

P

> 
> Mark
> 
>> Fortunately we do not appear to allow shuffling in these cases. I’m not sure 
>> if the human disambiguation is easier here because of the context (‘case 
>> let’ and ‘case’), but I don’t recall seeing complain about these being 
>> confusing (having said that it’s entirely possible they are very confusing 
>> the first time someone sees them, in particular ‘cast let’ and the binding 
>> form of ‘case’.
>> 
>> enum X {
>>   case e(i: Int, f: Float)
>> }
>> 
>> let x = X.e(i: 7, f: 12)
>> 
>> if case let X.e(i: hi, f: bye) = x {
>>   print("(i: \(hi), f: \(bye))")
>> }
>> 
>> func test(_ x: X, _ a: Int, _ b: Float) {
>>   switch x {
>>   case .e(i: a, f: b):
>>     print("match values")
>>   case .e(i: let _, f: let _):
>>     print("bind values")
>>   default:
>>     break
>>   }
>> }
>> 
>> test(X.e(i: 1, f: 2), 1, 2)
>> test(X.e(i: 1, f: 2), 3, 4)
>> 
>> 
>>> 
>>> I ran that against all 55 projects in swift-source-compat-suite, comprising 
>>> about over 400,000 lines of Swift code, and found … drumroll … exactly one 
>>> match:
>>> 
>>> 
>>> neota (swift-source-compat-suite)$ find project_cache -name '*.swift' 
>>> -print0 | xargs -0 pcregrep -M 
>>> '(for|case|let|var|catch)\s+\([a-zA-Z0-9_]+\s*:'
>>> project_cache/RxSwift/RxExample/RxExample-iOSTests/TestScheduler+MarbleTests.swift:
>>>                 let (time: _, events: events) = segments.reduce((time: 0, 
>>> events: [RecordedEvent]())) { state, event in
>>> 
>>> 
>>> Caveats about this method:
>>> 
>>> • My regexp won’t match second and third patterns in a comma-separated let 
>>> or case, e.g.:
>>> 
>>>    let a = b, (c: d) = e
>>> 
>>> • It doesn’t match non-ascii identifiers.
>>> 
>>> • This experiment only considers labeled tuples in pattern matches, what I 
>>> took Chris’s original puzzler to be about. Label-based tuple shuffling is a 
>>> separate question.
>>> 
>>> Still, even if it’s undercounting slightly, one breakage in half a million 
>>> lines of code should put to rest concerns about unexpected widespread 
>>> impact.
>>> 
>>> (Anything else I’m missing?)
>>> 
>>> • • •
>>> 
>>> Aside for those who know the tools out there: what would it take to run 
>>> inspections like this against ASTs instead of using a regex? Could we 
>>> instrument the compiler as Brent suggested?
>> 
>> If you want to catch *all* of these cases then the patch below will do it by 
>> failing the AST verifier when it hits a pattern with labels. If you only 
>> want to find the plain let-binding versions of this and not the ‘case let’ 
>> and ‘case’ ones, I’d suggest looking at the parser to see if there’s an easy 
>> place to instrument (I don’t know offhand).
>> 
>> Mark
>> 
>> diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
>> index b59a7ade23..ba4b2a245d 100644
>> --- a/lib/AST/ASTVerifier.cpp
>> +++ b/lib/AST/ASTVerifier.cpp
>> @@ -2772,6 +2772,13 @@ public:
>>      }
>>  
>>      void verifyParsed(TuplePattern *TP) {
>> +      for (auto &elt : TP->getElements()) {
>> +        if (!elt.getLabel().empty()) {
>> +          Out << "Labeled tuple patterns are offensive!\n";
>> +          abort();
>> +        }
>> +      }
>> +
>>        PrettyStackTracePattern debugStack(Ctx, "verifying TuplePattern", TP);
>>        verifyParsedBase(TP);
>>      }
>> 
>> 
>> 
>> 
>>> Or can SourceKit / SourceKitten give a full AST? Or has anybody written a 
>>> Swift parser in Swift?
>>> 
>>> Cheers,
>>> 
>>> Paul
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> [email protected] <mailto:[email protected]>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <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