Re: [swift-evolution] [Review] SE-0194: Derived Collection of Enum Cases

2018-01-11 Thread Gwendal Roué via swift-evolution

> Le 12 janv. 2018 à 06:42, Brent Royal-Gordon via swift-evolution 
>  a écrit :
> 
> Basically, having `ValueEnumerable` be a formal protocol means we can extend 
> this small automatic behavior into larger automatic behaviors. I can imagine, 
> for instance, building a fuzzer which, given a list of `WritableKeyPath`s 
> whose types are all `ValueEnumerable`, automatically generates random 
> instances of a type and feeds them into a test function. If we get read-write 
> reflection, we might be able to do this automatically and recursively. That'd 
> be pretty cool.

Yes! This is an argument for ValueEnumerable (vs. CaseEnumerable), ins't it ?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0194: Derived Collection of Enum Cases

2018-01-11 Thread Gwendal Roué via swift-evolution
Hello,

> Le 12 janv. 2018 à 02:36, Paul Cantrell via swift-evolution 
>  a écrit :
> 
> The question I was weighing on it — what I thought Chris and Brent were 
> discussing — was whether this new protocol should be used narrowly for cases 
> of enums without associated types (which Chris favors), or whether it should 
> find more broad use to mean “type which can enumerate all of its possible 
> values” (which Brent finds interesting with caveats). This question has a 
> bearing on whether the protocol’s name should be CaseEnumerable or 
> ValueEnumerable.

A classic mantra on this mailing list is that stdlib protocols ought to come 
with generic use cases and algorithms.

Is there any such use case, for either CaseEnumerable or ValueEnumerable, that 
are not already covered by sequence and the various collection protocols?

Did I miss them in the proposal? Did I miss Xiaodi's post about the lack of 
such use cases?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] 100% bikeshed topic: DictionaryLiteral

2018-01-09 Thread Gwendal Roué via swift-evolution

> Le 9 janv. 2018 à 18:18, Nate Cook <natec...@apple.com> a écrit :
> 
>> On Jan 9, 2018, at 11:00 AM, Gwendal Roué via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>>> 
>>> Le 9 janv. 2018 à 17:16, Zach Waldowski via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>> 
>>> I'm not sure a valid use case by a third party makes it hold its weight for 
>>> inclusion in the stdlib.
>> 
>> You're definitely right, and that's why I wrote with the most humble tone I 
>> could.
>> 
>> Yet, the design of the stdlib *requires* some speculation about use cases, 
>> and speculation is *helped* by the exposition of actual uses. I'm not sure 
>> readers of the mailing list had any idea of the use cases of the current 
>> DictionaryLiteral, and maybe I helped a little.
>> 
>>> Reproducing its feature set is extremely trivial, and would probably allow 
>>> you to hint the implementation details better for your use case.
>> 
>> Please define "trivial”.
>> 
>> In case anybody would wonder, in the line below the `row` variable is of 
>> type Row which happens to adopt ExpressibleByDictionaryLiteral. It is not of 
>> type DictionaryLiteral. The use case here is the ability to express a row 
>> with a dictionary literal that accepts duplicated keys and preserves 
>> ordering:
>> 
>>  XCTAssertEqual(row, ["a": 1, "a": 2])
> 
> That’s great! In this case you aren’t using the DictionaryLiteral type, but a 
> “dictionary literal”, which no one is suggesting we remove.

You're right ! I was almost sure that ExpressibleByDictionaryLiteral 
initializer would eat a DictionaryLiteral, but it doesn't!

extension Row : ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (String, 
DatabaseValueConvertible?)...) { ... }
}

This code has been written too long ago. I have been mislead, I'd like to 
apologize.

> If I’m understanding what you wrote, this is another case where the terrible 
> name is making it super hard to discuss what we’re talking about. “Dictionary 
> literals” and the ExpressibleByDictionaryLiteral protocol are safe!

Yes, I have been bitten hard by the names! Time for bikeshedding indeed :-)

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] 100% bikeshed topic: DictionaryLiteral

2018-01-09 Thread Gwendal Roué via swift-evolution

> Le 9 janv. 2018 à 17:16, Zach Waldowski via swift-evolution 
> <swift-evolution@swift.org> a écrit :
> 
> I'm not sure a valid use case by a third party makes it hold its weight for 
> inclusion in the stdlib.

You're definitely right, and that's why I wrote with the most humble tone I 
could.

Yet, the design of the stdlib *requires* some speculation about use cases, and 
speculation is *helped* by the exposition of actual uses. I'm not sure readers 
of the mailing list had any idea of the use cases of the current 
DictionaryLiteral, and maybe I helped a little.

> Reproducing its feature set is extremely trivial, and would probably allow 
> you to hint the implementation details better for your use case.

Please define "trivial".

In case anybody would wonder, in the line below the `row` variable is of type 
Row which happens to adopt ExpressibleByDictionaryLiteral. It is not of type 
DictionaryLiteral. The use case here is the ability to express a row with a 
dictionary literal that accepts duplicated keys and preserves ordering:

XCTAssertEqual(row, ["a": 1, "a": 2])

I don't see how anything could better fit this use case than the current 
DictionaryLiteral. This is not *my* use case, but the use case of anyone that 
wants to model database rows beyond the traditional (and ill-advised) 
dictionary.

Some other users may come with other use cases that may also help the stdlib 
designers choose the best solution.

Gwendal

> 
> Zach
> z...@waldowski.me <mailto:z...@waldowski.me>
> 
> 
> On Tue, Jan 9, 2018, at 2:12 AM, Gwendal Roué via swift-evolution wrote:
>> 
>>> Le 9 janv. 2018 à 08:06, Gwendal Roué via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>> 
>>> 
>>>> Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>>> 
>>>> The ulterior question of whether preserving “DictionaryLiteral” is 
>>>> worthwhile, is apparently out of scope. Personally, I have a hard time 
>>>> imagining a compelling use-case outside of the standard library, and I 
>>>> doubt it’s being used “in the wild” (I checked several projects in the 
>>>> source-compatibility suite and found zero occurrences).
>>> 
>>> DictionaryLiteral is worthwhile. The SQLite library GRDB uses 
>>> DictionaryLiteral in order to build database rows (which may have 
>>> duplicated column names, and whose column ordering is important). This is 
>>> mostly useful for tests:
>>> 
>>> let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
>>> XCTAssertEqual(row, ["a": 1, "a": 2])
>>> 
>>> Gwendal
>> 
>> Chris Lattner's wrote:
>> 
>>> why is maintaining duplicate keys a feature?
>> 
>>> Since it is immutable, why not sort the keys in the initializer, allowing 
>>> an efficient binary search to look up values?
>> 
>> 
>> I really wish both duplicated keys and key ordering would be preserved, 
>> since both are needed for the above sample code.
>> 
>> Should those features be lost, the sky wouldn't fall, that's sure. But we'd 
>> have to write something much less easy to wrote and read:
>> 
>> XCTAssertEqual(row.map { $0 }, [("a", 1), ("a", 2)])
>> 
>> Gwendal
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] 100% bikeshed topic: DictionaryLiteral

2018-01-08 Thread Gwendal Roué via swift-evolution

> Le 9 janv. 2018 à 08:06, Gwendal Roué via swift-evolution 
> <swift-evolution@swift.org> a écrit :
> 
> 
>> Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>> 
>> The ulterior question of whether preserving “DictionaryLiteral” is 
>> worthwhile, is apparently out of scope. Personally, I have a hard time 
>> imagining a compelling use-case outside of the standard library, and I doubt 
>> it’s being used “in the wild” (I checked several projects in the 
>> source-compatibility suite and found zero occurrences).
> 
> DictionaryLiteral is worthwhile. The SQLite library GRDB uses 
> DictionaryLiteral in order to build database rows (which may have duplicated 
> column names, and whose column ordering is important). This is mostly useful 
> for tests:
> 
> let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
> XCTAssertEqual(row, ["a": 1, "a": 2])
> 
> Gwendal

Chris Lattner's wrote:

> why is maintaining duplicate keys a feature?

> Since it is immutable, why not sort the keys in the initializer, allowing an 
> efficient binary search to look up values?

I really wish both duplicated keys and key ordering would be preserved, since 
both are needed for the above sample code.

Should those features be lost, the sky wouldn't fall, that's sure. But we'd 
have to write something much less easy to wrote and read:

XCTAssertEqual(row.map { $0 }, [("a", 1), ("a", 2)])

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] 100% bikeshed topic: DictionaryLiteral

2018-01-08 Thread Gwendal Roué via swift-evolution

> Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution 
>  a écrit :
> 
> The ulterior question of whether preserving “DictionaryLiteral” is 
> worthwhile, is apparently out of scope. Personally, I have a hard time 
> imagining a compelling use-case outside of the standard library, and I doubt 
> it’s being used “in the wild” (I checked several projects in the 
> source-compatibility suite and found zero occurrences).

DictionaryLiteral is worthwhile. The SQLite library GRDB uses DictionaryLiteral 
in order to build database rows (which may have duplicated column names, and 
whose column ordering is important). This is mostly useful for tests:

let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
XCTAssertEqual(row, ["a": 1, "a": 2])

Gwendal___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-05 Thread Gwendal Roué via swift-evolution

> Le 5 janv. 2018 à 10:33, Goffredo Marocchi  a écrit :
> 
> Fair concerns Gwendal, but why can’t the default in these cases be just 
> exhaustive / frozen unless the library developer explicitly marks it as 
> “unfrozen/non exhaustive” and the compiler can warn the users when they 
> switch over it instead of throwing an error by default (the user can still 
> treat warnings as errors if they want and suppress this warning if they 
> wanted to in this vision)?

The proposal suggests default non-frozen enums. If I remember well, that's 
because it's easier to switch from non-frozen to frozen than the opposite.

I buy this ABI-based argument very well, since 1. I'm not an ABI expert, and 2. 
as a library author I will scratch my head for each of my public enums anyway.

Now I still think that the choice is really uneasy. I've given some GRDB 
examples. And I'd also like to know how ABI experts would have introduced and 
evolved SKPaymentTransactionState in a hypothetic Swift 5+ world.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-05 Thread Gwendal Roué via swift-evolution

> Le 5 janv. 2018 à 09:11, Goffredo Marocchi via swift-evolution 
>  a écrit :
> 
> I feel like this change will make the life easier for library authors, but 
> risks making it easier and easier to make mistakes in apps using the 
> libraries: exhaustive switching over enums is a good important feature that 
> risks going away (the default matters) for not a huge effective benefit to 
> app developers.

I agree that life is made worse for a library user that meets a non-frozen 
enum. And I don't know if it makes the life easier for library authors, because 
library authors not only throw code in the wild, but also try to prevent 
library users from making the mistakes you talk about.

To take GRDB.swift as an example, it currently has 15 public enums. What are my 
options?

More than half of those enums mirror SQLite C enums, or sets of related SQLite 
values. SQLite is still a living piece of sofware, and it may adds new cases or 
values in the future. It is then likely that GRDB has to be updated as well. It 
thus looks like I can make those enums @frozen. But then it looks like I betray 
the proposal's goal. What's the correct choice?

Some enums are like SKPaymentTransactionState: there's no way the user could 
infer a proper behavior in a mandatory default/unknown switch case. I thus also 
want to make them @frozen, and avoid headaches to the library users. Will I pay 
for it later?

Some other enums are positively non-frozen. I may want to replace some of them 
with a struct with a limited set of pre-built values. This would, IMHO, improve 
the library UX because it would again prevent headaches for the library users 
about scary "future" cases. In the struct with a limited set of values, there 
is no future cases. Instead, there are a limited set of named values. Which is 
a very different way to say the same thing.

This last paragraph draws a strong parallel between non-frozen enums and 
structs:

// non-frozen enum:
public enum E {
case a, b
}

// equivalent struct:
public struct S: Equatable {
private let value: Int
private init(_ value: Int) { self.value = value }
public static let a = S(1)
public static let b = S(2)
public static func == (lhs: S, rhs: S) -> Bool {
return lhs.value == rhs.value
}
}

func f(_ s: S) {
// S can be switched over just like a struct:
switch s {
case .a: print("a")
case .b: print("b")
default: print("unknown")
}
}

BTW, did anybody think about importing C enums as such structs?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-04 Thread Gwendal Roué via swift-evolution
May I ask two questions?

Would StoreKit be written in Swift 5+, do you think that 
SKPaymentTransactionState should have been introduced as a @closed enum?

If so, what would have then been the consequences of adding the new .deferred 
state (assuming this would even be possible)?

Gwendal

> Le 5 janv. 2018 à 01:38, Jordan Rose via swift-evolution 
>  a écrit :
> 
> Hi, Dave. You're right, all these points are worth addressing. I'm going to 
> go in sections.
> 
>> This whole “unexpected case” thing is only a problem when you’re linking 
>> libraries that are external to/shipped independently of your app. Right now, 
>> the *only* case where this might exist is Swift on the server. We *might* 
>> run in to this in the future once the ABI stabilizes and we have the Swift 
>> libraries shipping as part of iOS/macOS/Linux. Other than this, unexpected 
>> enum cases won’t really be a problem developers have to deal with.
> 
> 
> I wish this were the case, but it is not. Regardless of what we do for Swift 
> enums, we are in dire need of a fix for C enums. Today, if a C enum doesn't 
> have one of the expected values, the behavior is undefined in the C sense (as 
> in, type-unsafe, memory-unsafe, may invoke functions that shouldn't be 
> invoked, may not invoke functions that should be invoked, etc).
> 
> Obviously that's an unacceptable state of affairs; even without this proposal 
> we would fix it so that the program will deterministically trap instead. This 
> isn't perfect because it results in a (tiny) performance and code size hit 
> compared to C, but it's better than leaving such a massive hole in Swift's 
> safety story.
> 
> The trouble is that many enums—maybe even most enums—in the Apple SDK really 
> are expected to grow new cases, and the Apple API authors rely on this. Many 
> of those—probably most of them—are the ones that Brent Royal-Gordon described 
> as "opaque inputs", like UIViewAnimationTransition, which you're unlikely to 
> switch over but which the compiler should handle correctly if you do. Then 
> there are the murkier ones like SKPaymentTransactionState.
> 
> I'm going to come dangerously close to criticizing Apple and say I have a lot 
> of sympathy for third-party developers in the SKPaymentTransactionState case. 
> As Karl Wagner said, there wasn't really any way an existing app could handle 
> that case well, even if they had written an 'unknown case' handler. So what 
> could the StoreKit folks have done instead? They can't tell themselves 
> whether your app supports the new case, other than the heavy-handed "check 
> what SDK they compiled against" that ignores the possibility of embedded 
> binary frameworks. So maybe they should have added a property 
> "supportsDeferredState" or something that would have to be set before the new 
> state was returned.
> 
> (I'll pause to say I don't know what consideration went into this API and I'm 
> going to avoid looking it up to avoid perjury. This is all hypothetical, for 
> the next API that needs to add a case.)
> 
> Let's say we go with that, a property that controls whether the new case is 
> ever passed to third-party code. Now the new case exists, and new code needs 
> to switch over it. At the same time, old code needs to continue working. The 
> new enum case exists, and so even if it shouldn't escape into old code that 
> doesn't know how to handle it, the behavior needs to be defined if it does. 
> Furthermore, the old code needs to continue working without source changes, 
> because updating to a new SDK must not break existing code. (It can introduce 
> new warnings, but even that is something that should be considered carefully.)
> 
> So: this proposal is designed to handle the use cases both for Swift library 
> authors to come and for C APIs today, and in particular Apple's Objective-C 
> SDKs and how they've evolved historically.
> 
> 
> There's another really interesting point in your message, which Karl, Drew 
> Crawford, and others also touched on.
> 
>> Teaching the compiler/checker/whatever about the linking semantics of 
>> modules. For modules that are packaged inside the final built product, there 
>> is no need to deal with any unexpected cases, because we already have the 
>> exhaustiveness check appropriate for that scenario (regardless of whether 
>> the module is shipped as a binary or compiled from source). The app author 
>> decides when to update their dependencies, and updating those dependencies 
>> will produce new warnings/errors as the compiler notices new or deprecated 
>> cases. This is the current state of things and is completely orthogonal to 
>> the entire discussion.
> 
> This keeps sneaking into discussions and I hope to have it formalized in a 
> proposal soon. On the library side, we do want to make a distinction between 
> "needs binary compatibility" and "does not need binary compatibility". Why? 
> Because we can get much better performance if we know a 

Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-04 Thread Gwendal Roué via swift-evolution
Thanks for this extended rationale.

I would pin this post if I could. Or extend the "motivation" section of the 
proposal with it.

Gwendal

> Le 5 janv. 2018 à 01:38, Jordan Rose via swift-evolution 
>  a écrit :
> 
> Hi, Dave. You're right, all these points are worth addressing. I'm going to 
> go in sections.
> 
>> This whole “unexpected case” thing is only a problem when you’re linking 
>> libraries that are external to/shipped independently of your app. Right now, 
>> the *only* case where this might exist is Swift on the server. We *might* 
>> run in to this in the future once the ABI stabilizes and we have the Swift 
>> libraries shipping as part of iOS/macOS/Linux. Other than this, unexpected 
>> enum cases won’t really be a problem developers have to deal with.
> 
> 
> I wish this were the case, but it is not. Regardless of what we do for Swift 
> enums, we are in dire need of a fix for C enums. Today, if a C enum doesn't 
> have one of the expected values, the behavior is undefined in the C sense (as 
> in, type-unsafe, memory-unsafe, may invoke functions that shouldn't be 
> invoked, may not invoke functions that should be invoked, etc).
> 
> Obviously that's an unacceptable state of affairs; even without this proposal 
> we would fix it so that the program will deterministically trap instead. This 
> isn't perfect because it results in a (tiny) performance and code size hit 
> compared to C, but it's better than leaving such a massive hole in Swift's 
> safety story.
> 
> The trouble is that many enums—maybe even most enums—in the Apple SDK really 
> are expected to grow new cases, and the Apple API authors rely on this. Many 
> of those—probably most of them—are the ones that Brent Royal-Gordon described 
> as "opaque inputs", like UIViewAnimationTransition, which you're unlikely to 
> switch over but which the compiler should handle correctly if you do. Then 
> there are the murkier ones like SKPaymentTransactionState.
> 
> I'm going to come dangerously close to criticizing Apple and say I have a lot 
> of sympathy for third-party developers in the SKPaymentTransactionState case. 
> As Karl Wagner said, there wasn't really any way an existing app could handle 
> that case well, even if they had written an 'unknown case' handler. So what 
> could the StoreKit folks have done instead? They can't tell themselves 
> whether your app supports the new case, other than the heavy-handed "check 
> what SDK they compiled against" that ignores the possibility of embedded 
> binary frameworks. So maybe they should have added a property 
> "supportsDeferredState" or something that would have to be set before the new 
> state was returned.
> 
> (I'll pause to say I don't know what consideration went into this API and I'm 
> going to avoid looking it up to avoid perjury. This is all hypothetical, for 
> the next API that needs to add a case.)
> 
> Let's say we go with that, a property that controls whether the new case is 
> ever passed to third-party code. Now the new case exists, and new code needs 
> to switch over it. At the same time, old code needs to continue working. The 
> new enum case exists, and so even if it shouldn't escape into old code that 
> doesn't know how to handle it, the behavior needs to be defined if it does. 
> Furthermore, the old code needs to continue working without source changes, 
> because updating to a new SDK must not break existing code. (It can introduce 
> new warnings, but even that is something that should be considered carefully.)
> 
> So: this proposal is designed to handle the use cases both for Swift library 
> authors to come and for C APIs today, and in particular Apple's Objective-C 
> SDKs and how they've evolved historically.
> 
> 
> There's another really interesting point in your message, which Karl, Drew 
> Crawford, and others also touched on.
> 
>> Teaching the compiler/checker/whatever about the linking semantics of 
>> modules. For modules that are packaged inside the final built product, there 
>> is no need to deal with any unexpected cases, because we already have the 
>> exhaustiveness check appropriate for that scenario (regardless of whether 
>> the module is shipped as a binary or compiled from source). The app author 
>> decides when to update their dependencies, and updating those dependencies 
>> will produce new warnings/errors as the compiler notices new or deprecated 
>> cases. This is the current state of things and is completely orthogonal to 
>> the entire discussion.
> 
> This keeps sneaking into discussions and I hope to have it formalized in a 
> proposal soon. On the library side, we do want to make a distinction between 
> "needs binary compatibility" and "does not need binary compatibility". Why? 
> Because we can get much better performance if we know a library is never 
> going to change. A class will not acquire new dynamic-dispatch members; a 
> stored property will not turn into a computed 

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-07 Thread Gwendal Roué via swift-evolution
>>> I’m talking specifically about fatalError not precondition. fatalError is 
>>> something that goes out with production code while precondition is used for 
>>> debugging. I think you would agree a shipped program that has many states 
>>> of being unrecoverable is not a good design?
>> 
>> When a question is framed so that there is only one possible answer, the 
>> question is flawed.
>> 
>> The question is not whether one likes dynamism or not (the answer is pretty 
>> obvious for many people here, and we don't learn much).
> 
> One might call that a rhetorical question :) Which is probably not 
> appropriate here so I apologies for that.

It's difficult to avoid sometimes ;-)

>> It isn't if one would use the discussed features if the proposals were 
>> accepted (many here would swear they wouldn't, even if many of them will 
>> lick those dynamic features like candy, whenever appropriate, as every sane 
>> person would).
>> 
> I’m not sure anyone here ever said they wouldn’t use it. There’s just a 
> concern about how much it would be used.

Yes. And we all share this concern. Or, to put it better, I think : many Swift 
users are sold to the static safety of Swift.

Long gone are the early days when early Swift users were missing ObjC dynamism.

I may live in an echo chamber, but most Swift news I read are about strongly 
typed patterns, and the immense progress in the implementation of the Generics 
Manisfesto, which will bring even more type-safe goodness!

I thus see no threat in Chris's proposal. He even slightly obfuscates the 
identifiers so that no one jumps in by mistake.

>> Currently, it's a static vs. dynamic debate. But we should talk about a 
>> precise proposal, and a good one after that, which comes with plenty of 
>> information, and even playgrounds to look at!
> 
> I’m not taking sides on which is better (each to their own use cases). I am 
> talking about the proposals current design.

+1

> The current design says that dynamic and static calls are on equal footing. 
> This implies to the programmer that either way of doing things is correct. A 
> programmer from a dynamic environment is usually going to choose the dynamic 
> way because it’s more powerful and easier to use. I just merely want the 
> design to have a way of showing the programmer that they should think twice 
> about using it in an implicitly failing way. Whether that be renaming the 
> protocol to something like UnsafeDynamicMemberLookup or something else along 
> the lines of what Swift currently does.

I though the current design was all about easing the use of good libraries that 
are currently only available in dynamic languages.

Do you aim at a particular paragraph in 
https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438#motivation-and-context
 ?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-07 Thread Gwendal Roué via swift-evolution

> Le 7 déc. 2017 à 16:33, C. Keith Ray via swift-evolution 
>  a écrit :
> 
> Let's see what disasters were created by people abusing NSProxy, the ObjC 
> moral equivalent of a dynamic member lookup type.
> 
> I'm not aware of anything.


I'm sure you are ;-)

I'm not expert at all of early ObjC... But wasn't NSProxy the base of 
good-old-times RPC?

OK, in 2017 we know that RPC is dangerous. For example, when `() -> Int` relies 
on a network call, it's almost impossible to handle errors.

But still, is it because an API can be used for bad things that an API is bad?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-07 Thread Gwendal Roué via swift-evolution

> Le 7 déc. 2017 à 16:15, Letanyan Arumugam via swift-evolution 
>  a écrit :
> 
> 
> 
>> On 07 Dec 2017, at 17:02, Xiaodi Wu > > wrote:
>> 
>> 
>> On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution 
>> > wrote:
>> 
>>> This seems marginally tolerable, but excessive.
>>> 
>>> Do we mark every usage of a type that can generate precondition failures or 
>>> fatal errors for reasons other than “no such method?” No, we don’t.
>>> 
>> 
>> fatalError shouldn’t be used excessively. API surface areas for these types 
>> are going to be massive (infinite technically). I assume many people are 
>> going to be writing a lot of code would these types and calling many methods 
>> and properties which would all essentially have a fatalError. Would you 
>> consider it good code if the majority of all your types had methods defined 
>> with fatalError calls.
>> 
>> What is the basis for this claim? Probably the majority of standard library 
>> methods check preconditions and trap on failure. That is how I write my code 
>> as well.
>> 
> 
> I’m talking specifically about fatalError not precondition. fatalError is 
> something that goes out with production code while precondition is used for 
> debugging. I think you would agree a shipped program that has many states of 
> being unrecoverable is not a good design?

When a question is framed so that there is only one possible answer, the 
question is flawed.

The question is not whether one likes dynamism or not (the answer is pretty 
obvious for many people here, and we don't learn much).

It isn't if one would use the discussed features if the proposals were accepted 
(many here would swear they wouldn't, even if many of them will lick those 
dynamic features like candy, whenever appropriate, as every sane person would).

Currently, it's a static vs. dynamic debate. But we should talk about a precise 
proposal, and a good one after that, which comes with plenty of information, 
and even playgrounds to look at!

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-07 Thread Gwendal Roué via swift-evolution

> Le 7 déc. 2017 à 13:59, Benjamin G  a écrit :
> 
> 
> 
> On Thu, Dec 7, 2017 at 1:45 PM, Gwendal Roué  > wrote:
> 
>> Le 7 déc. 2017 à 11:00, Benjamin G via swift-evolution 
>> > a écrit :
>> 
>> Until, and if, the “resistance” presents some conceptual explanation of how 
>> this could cause harm (I’m not asking for anything concrete, just a logical 
>> series of events that causes a plausible problem in practice), my belief is 
>> that the Swift community will see this as unwarranted fear.
>> 
>> On the server side : 
>> automatically generate an administration api for your model based on 
>> introspection. Since swift doesn't provide anything convenient, and people 
>> may simply try to "port" approach from python framework (like django), 
>> they'll resort on recreating some kind of BaseDynamicObject that you'll have 
>> to extend for all your base classe, using some "properties()" and 
>> "methods()" functions to define your properties and methods for your model.
>> 
>> Or :
>> Automatically generate a database schema based on your model. Same idea.
> 
> The explicit harm that Chris is looking for is yet to be shown. 
> 
> The harm isn't in generating the database schema, or the administration api. 
> it's in abandonning all kind of compile-time safety in your model layer (and 
> such by extension in almost every part of your stack) in order to accomplish 
> this. Dynamic language obviously don't have this concern, but thankfully 
> Swift isn't a dynamic language.

Yes, yes, but this has been said dozens of time already in this thread. Chris's 
question is *how*, not *what*. It's much harder to answer, I agree.

>>  You should not assume that everybody feels an horror thrill by reading such 
>> applications of dynamism. As a matter of fact, users of dynamic languages 
>> *live* and *enjoy* this. Python and Ruby users, obviously (Rails + Django), 
>> but also ours close cousins, the Objective-C developers, who rely on 
>> Key-Value coding or validation methods. Those use cases are, I'm sorry to 
>> say it, *compelling* use cases for dynamism.
> 
> 
> Not sure what field you're working in, but at least on the server the general 
> trend toward more compile-time safety has been pretty obvious for some time 
> now.

I'm not sure you really care about my answer.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-11-30 Thread Gwendal Roué via swift-evolution

> Le 1 déc. 2017 à 08:38, Gwendal Roué  a écrit :
> 
> In this context, I too am concerned with retroactive conformance. If it were 
> forbidden, it would make it very clear where the dynamic scope starts and 
> ends:


In Chris's playground, it is very clear that you have to import PythonGlue in 
order to activate the retroactive conformance on Int, Double, etc.

This is very fine to me. Sorry for expressing a useless concern.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-11-30 Thread Gwendal Roué via swift-evolution

> Le 1 déc. 2017 à 00:54, Xiaodi Wu via swift-evolution 
>  a écrit :
> 
> As I wrote in the earlier thread, I think this is the wrong way to reason 
> about the use case--and a counterproductive one that effectively rejects the 
> legitimacy of dynamic language interop support instead of working towards an 
> optimal solution for it. Along those lines, some replies to your message 
> literally question whether the user case is worthwhile to support at all, 
> which I think entirely misses the mark.
> 
> As Chris writes in his proposal, there are several areas (such as data 
> science) where, to put it plainly, Python or another dynamic language is 
> significantly better than Swift due to a much larger ecosystem of libraries, 
> tools, and user communities, with sometimes decades of lead time. It is 
> nonsensical to talk about how Swift is "supposed to be better" in any way 
> whatsoever in that context. As diehard Swift users, we may be confident that 
> the virtues of Swift's syntax, static typing, compiler smarts, protocol-based 
> design, or whatever else offer opportunities for, say, data science libraries 
> and tools to be better in the future, eventually. But to make this even 
> possible involves first making Swift a viable language in which to work with 
> current data science tools. Your top bullet point here reasons that one key 
> flaw of Chris's proposal is that he has not somehow figured out how to make 
> dynamic Python calls give compile-time Swift errors. If this is the minimum 
> bar for Python interop, then as far as I can tell, it seems isomorphic to 
> rejecting interop with dynamic languages altogether.

Hello, I agree with this reasoning.

Unless I miss the point, I see C. Lattner's proposals, function calls and 
member lookup,  as a very restricted interface to dynamic languages. They do 
not aim at embedding dynamic languages into Swift at all, and let users write 
long Python/Ruby/JS programs in Swift.

For example, "real" python would need list comprehension, generators, 
async/await, etc. Such features are clearly out of scope of the proposals.

We can thus expect serious programs that use those features to process in three 
steps: 1 turn Swift values in foreign values, 2. process foreign values with a 
restricted foreign API, 3. turn computed foreign values into Swift values. It's 
all about using good tools when needed.

In this context, I too am concerned with retroactive conformance. If it were 
forbidden, it would make it very clear where the dynamic scope starts and ends:

// Input
let swiftInt: Int = 12

// Enter Python
let pyInt = Python.Value(swiftInt)

// Python code
let pyResult = pyInt.someFunc()

// Back to Swift
if let swiftResult = Int(pyResult) {
// proceed
}

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Random Unification

2017-11-17 Thread Gwendal Roué via swift-evolution

> Le 17 nov. 2017 à 16:04, Alejandro Alonso via swift-evolution 
>  a écrit :
> 
> If we go back to your example, you never call FixedWidthInteger.random 
> either, you call range.random. Does this mean integer types shouldn’t have 
> .random? No, because it means get a random number from it’s internal range 
> (alias to (min ... max).random). I think we can all agree that Integer.random 
> is a nicer api than making a range of its bounds. The same goes for 
> Date.random and Color.random.
> 
> - Alejandro

Hello,

I'm not random expert, but it has never happened in my developer life (backend 
& frontend app developer) that I have used a pure random value from the full 
domain of the random type. In this life:

- Int.random is _always_ followed by % modulo. Unless the better 
arc4random_uniform(max) is used.
- Color.random is _never_ used, because random colors look bad.
- Date.random is _never_ used, because time is a physical unit, and random 
points in time do not match any physical use case.

This does not mean that random values from the full domain are useless. Of 
course not: math apps, fuzzers, etc. need them.

Yet a range-based API would be much welcomed by regular app developers. And 
also Array.randomElement(), Array.shuffled(), etc, because there are plenty 
naive and bad algorithms for those simple tasks.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Accepted and Focused Re-review] SE-0187: Introduce Sequence.filterMap(_:)

2017-11-16 Thread Gwendal Roué via swift-evolution

> Le 16 nov. 2017 à 11:06, Brent Royal-Gordon via swift-evolution 
>  a écrit :
> 
>> On Nov 15, 2017, at 4:36 PM, Greg Parker via swift-evolution 
>> > wrote:
>> 
>> "compactMap" is okay if "compact" is added. Is "compact" a common enough 
>> operation in practice to pull its own weight?
> 
> Lines containing code like `flatMap { $0 }`—which could be compacting 
> optionals or flattening nested sequences—appear 89 times in the source 
> compatibility suite. (I happen to have it on my hard drive right now.)
> 
> My main concern about adding a compacting method is…well, am I missing a 
> better implementation than the slightly gross one I cooked up in a playground 
> just now?
> 
>   protocol _OptionalProtocol {
>   associatedtype _Wrapped
>   var _optional: _Wrapped? { get }
>   }


Welcome to the club :-) 
https://github.com/search?q=OptionalProtocol+language%3Aswift=Code=✓

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Accepted and Focused Re-review] SE-0187: Introduce Sequence.filterMap(_:)

2017-11-16 Thread Gwendal Roué via swift-evolution

> The optional itself will stand for the boolean needed by the filtering 
> operation.

What I meant here is that "filterMap" can only click in a developer's mind if 
the the developer uses Optional as a Bool. When the closure returns nil, that 
nil stands for false in the filtering operation. When the closure returns a 
`some`, that some stands for true in the filtering operation.

Put in another way: to properly explain "filterMap" to someone who already 
knows "filter", then you have to explain that optionals are used as booleans.

Now if one has to answer the canonical question "Does this proposal fit well 
with the feel and direction of Swift?", then one has to admit that the 
confusion of Optional with Bool has been rejected a long time ago as not 
fitting well with the direction of Swift.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Accepted and Focused Re-review] SE-0187: Introduce Sequence.filterMap(_:)

2017-11-16 Thread Gwendal Roué via swift-evolution
Yes, you are right. I was too fast.

I've been thinking why filterMap has such a traction in the community, despite 
the fact that this precise "filter" is a tiny subset of the "filter" generally 
used by the language.

I think "filterMap" clicks well in many readers because of this trend of 
thought:

1. I need to transform some values and only keep some of them. But I don't want 
to use `seq.filter { ... }.map { ... }` or `seq.map { ... }.filter { ... }`. I 
don't even want to think about the ordering of the filter and mapping 
operations: that's not interesting. I want a versatile filter+map operation 
that I'll call "filterMap".
2. Now I need a closure that returns a two-state value: either (in+value), or 
(out).
3. Which existing Swift type fits such a requirement? Optional, of course. The 
optional itself will stand for the boolean needed by the filtering operation. 
The wrapped value will give the mapped value. Pretty efficient.

This trend of thought starts from an actual need (I don't know how to call it) 
and builds a rationale for it to use the words "filter", "map", and the 
Optional type. It uses optionals as booleans, which is a venial sin. It happens 
to build a 100% compatible replacement for the old "flatMap".

The "compact" trend of thought introduces a new operation which filter out 
nils. It happens to build a 100% compatible replacement for the old "flatMap".

The previous trend of thought (flatMap) did consider optionals as collections. 
It happens to confuse people, and has been rejected.

The three ways of thinking build the same function. I've been pushing "compact" 
has a way to better explore the subject. But I really don't know how the Swift 
community prefers to wire the developer's brains.

Gwendal



> Le 16 nov. 2017 à 09:12, Anders Ha <and...@andersha.com> a écrit :
> 
> It does not use `Optional`, but it is semantically equivalent to `filterMap` 
> in CwlSignal and ReactiveSwift, and the `filterMap` proposed for `Sequence` 
> (but in the time domain instead).
> 
> 
> 
> Regards,
> Anders
> 
> 
> 
>> On 16 Nov 2017, at 2:07 PM, Gwendal Roué via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>>> Le 16 nov. 2017 à 06:29, Matt Gallagher via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>> 
>>> My opinion is that filterMap is the right choice of name.
>>> 
>>> I'm completely biased, given that I already have a Swift library that uses 
>>> filterMap, in exactly this context, for a Reactive Programming library:
>>> 
>>> 
>>> https://github.com/mattgallagher/CwlSignal/blob/22f1d47895896d7b55bc59a4ee5394071f3c84cf/Sources/CwlSignal/CwlSignalReactive.swift#L453?ts=3
>>>  
>>> <https://github.com/mattgallagher/CwlSignal/blob/22f1d47895896d7b55bc59a4ee5394071f3c84cf/Sources/CwlSignal/CwlSignalReactive.swift#L453?ts=3>
>> 
>> Another popular Reactive Programming Library uses filterMap with a different 
>> signature, and a different meaning: 
>> https://github.com/RxSwiftCommunity/RxSwiftExt/blob/3.0.0/Source/RxSwift/filterMap.swift#L32
>>  
>> <https://github.com/RxSwiftCommunity/RxSwiftExt/blob/3.0.0/Source/RxSwift/filterMap.swift#L32>
>> 
>> There are already different interpretations on "filter" in "filterMap" in 
>> the wild.
>> 
>> Gwendal Roué
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Accepted and Focused Re-review] SE-0187: Introduce Sequence.filterMap(_:)

2017-11-15 Thread Gwendal Roué via swift-evolution

> Le 16 nov. 2017 à 06:29, Matt Gallagher via swift-evolution 
>  a écrit :
> 
> My opinion is that filterMap is the right choice of name.
> 
> I'm completely biased, given that I already have a Swift library that uses 
> filterMap, in exactly this context, for a Reactive Programming library:
> 
>   
> https://github.com/mattgallagher/CwlSignal/blob/22f1d47895896d7b55bc59a4ee5394071f3c84cf/Sources/CwlSignal/CwlSignalReactive.swift#L453?ts=3
>  
> 

Another popular Reactive Programming Library uses filterMap with a different 
signature, and a different meaning: 
https://github.com/RxSwiftCommunity/RxSwiftExt/blob/3.0.0/Source/RxSwift/filterMap.swift#L32

There are already different interpretations on "filter" in "filterMap" in the 
wild.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Accepted and Focused Re-review] SE-0187: Introduce Sequence.filterMap(_:)

2017-11-15 Thread Gwendal Roué via swift-evolution

> Le 16 nov. 2017 à 06:29, Matt Gallagher via swift-evolution 
>  a écrit :
> 
> On the topic of a method that "compacts" without also mapping... I think this 
> encourages poor designs that should be using lazy transformations instead of 
> aggregate processing. There is almost always a way around a bare flatten. The 
> obvious quirkiness of `filterMap { $0 }` (or whatever the name ends up being) 
> should be seen as a nudge to re-think the algorithm leading up to that point.

I can hear the argument, but it errs in the side of premature optimization. 
Besides, seq.lazy.compacted() still has a meaning.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

2017-11-11 Thread Gwendal Roué via swift-evolution

> Le 11 nov. 2017 à 16:48, Joe Groff via swift-evolution 
>  a écrit :
> 
> That'd be great, but Swift violates Gilad Bracha's golden rule by having 
> static overloading, and throws bidirectional type inference on top, so our 
> static name resolution can't be treated as a specialization of a dynamic name 
> lookup mechanism in all cases.

I didn't know of Gilad Bracha, so you made me curious. 

I guess that the "golden rule" you refer to is here, for anyone curious: 
https://gbracha.blogspot.fr/2009/09/systemic-overload.html 


Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0187: Introduce Sequence.filterMap(_:)

2017-11-11 Thread Gwendal Roué via swift-evolution
Hello,

>   • What is your evaluation of the proposal?

I'm neutral. My humble contribution is about the name of the method, since many 
reactions so far have a problem with the proposed filterMap name.

I'm found of Ruby's `compact` method. Its role is to filter out nils:

[1, 2, nil, 4].compact # => [1, 2 3]

This is not exactly what our discussed flatMap does, I know. Ruby's compact 
does not take a mapping closure. Swift's flatMap removes only one level of 
nils, as many contributors have reminded us. I know, I know.

I'd suggest `compactMap` as an alternative name, should `filterMap` find too 
much resistance:

[1, 2, nil, 4].compactMap { $0 } // [1, 2, 4]
["1", "foo"]..compactMap { Int($0) } // [1]

I'd even suggest adding `compact()` as a shorthand for `compactMap { $0 }`, 
since filtering out nils as a very common operation.

"Compact" has the advantage of being a short word. "Compacting" a collection 
would just mean removing its nils, a concept that could easily stick in 
developers' minds, as Ruby has shown.

>   • Is the problem being addressed significant enough to warrant a change 
> to Swift?

No. I too am guilty of having used flatMap when map was enough. Another name 
would not have changed this. It was just part of my learning phase.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Adding Result to the Standard Library

2017-11-09 Thread Gwendal Roué via swift-evolution

> Le 9 nov. 2017 à 08:57, Chris Lattner via swift-evolution 
>  a écrit :
> 
> 
>> On Nov 6, 2017, at 4:13 AM, Jon Shier > > wrote:
>> 
>>  This consideration is further complicated by the possible addition of 
>> typed throws in the future. However, the most commonly suggested 
>> implementation fo typed throws keeps the ability for throws to be untyped. 
>> Additionally, the feature usually allows multiple types to be thrown from a 
>> single function. Result can handle all of these scenarios automatically, 
>> since it reduces all errors down to Error. A Result however, would 
>> either lose the ability to encapsulate any function with multiple error 
>> types, or otherwise have to wrap those cases in something like AnyError, in 
>> additional to having to do so in the untyped case. 
> 
> As I mentioned up-thread, this proposal isn’t going to go anywhere without a 
> proper discussion of typed throws.  There are two possible designs that have 
> strong rationale:
> 
> 1. Never add typed throws.
> 2. Add the ability to specify a single type thrown (typically an enum, but 
> could be a struct), which defaults to Error if unspecified.
> 
> In contrast, I don’t see any reason to add an arbitrary *list* of thrown 
> types, and I can’t imagine such a design happening.  Swift already has ways 
> to specify alternatives (enums) and this would encourage exactly the behavior 
> from APIs that we want to avoid.
> 
> This choice between 1/2 needs to be decided before introducing result, 
> because #1 means it should be Result, and #2 means it should be 
> Result. If this is important to you, I’d suggest starting a dedicated 
> discussion thread about the topic.

Hello,

I wish that the Swift-Evolution discussion around typed / untyped throws would 
avoid three traps:

- a bloodshed between pro and anti typed-throws
- a pro-typed-throws echo chamber (since untyped throws is the passive status 
quo, and typed throws the energetic challenger)
- even less average-joe-programmers than ever (on a topic that immensely 
impacts their everyday job)

Shouldn't the community elect a benevolent dictator that would settle this 
subject? The final choice has of course to be sensible, but also strong and 
sharp.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Abstract methods

2017-11-02 Thread Gwendal Roué via swift-evolution

> Le 3 nov. 2017 à 04:29, Brent Royal-Gordon via swift-evolution 
>  a écrit :
> 
> I think we should beef up protocols a little bit so that they can serve the 
> role of abstract classes. 

That would be great.

Back in the day, the proposal SE-0026 "Abstract classes and methods" was 
deferred, with the following rationale: 
https://lists.swift.org/pipermail/swift-evolution-announce/2016-March/56.html

This rationale is great because it lists a few use cases for abstract class 
that protocols can't mimic today.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] stack classes

2017-10-27 Thread Gwendal Roué via swift-evolution
Hello,

It looks like you want compiler guarantees that an object will be "deinited" at 
the end of a syntactic block:

func f() {
let a = Object()
...
// <- guarantee that a.deinit is called here
}

Currently, Swift does not grant such guarantee. If the object gets retained 
somewhere, its deallocation is postponed:

var storage: [Object] = []
func f() {
let a = Object()
storage.append(a)
// <- a.deinit is not called here
}

With your proposal, the code above would not compile.

The current Swift way to guarantee "cleanup" tasks is the `defer` statement:

func f() {
let a = Object()
defer { a.cleanup() }
...
}

But this has several defects: object is not fully responsible of its state, and 
one can get "zombie" values that stay around:

var storage: [Object] = []
func f() {
let a = Object()
defer { a.cleanup() } // <- can be forgotten
storage.append(a) // <- storage will contain "zombie" object
}

So I understand how it looks like Swift does not currently support what C++ 
programmers are used to when they mix RAII with guaranteed stack allocation. 
Note, though, that in C++ guaranteed stack allocation comes for the declaration 
of a value, not from its type.

Is it the correct context of your pitch? Given the immense C++ experience of 
Swift designers, this is surely something they know pretty well. I don't know 
why they did not bring this to Swift. This question itself is an interesting 
topic!

Gwendal


> Le 27 oct. 2017 à 15:27, Mike Kluev via swift-evolution 
>  a écrit :
> 
> if it wasn't already discussed here is the preliminary proposal, if it was 
> then my +1 to the feature.
> 
> i propose we have an explicit apparatus to denote classes having stack 
> storage.
> 
> stack class StackObject { // guaranteed to be on stack
> }
> 
> class NonStackObject { // is not guaranteed to be on stack, can be on heap as 
> well
> }
> 
> this is for performance reasons. sometimes what we need is “structs with 
> deinit” and as this is not going to happen the next best thing could be 
> “lightweight” classes. this shall be self obvious, here are few examples:
> 
> stack class StackObject {
> var variable = 0
> 
> func foo() {
> print(“i am ok to live on stack”)
> }
> }
> 
> stack class BadObject {
> var variable = 0
> 
> func foo() {
> DispatchQueue.main.async {  // error: can’t be a stack class
> self.variable = 1
> }
> }
> }
> 
> class NonStackObject {
> …
> }
> 
> foo() {
> let stackObject = StackObject()
> 
> DispatchQueue.main.async {
> stackObject.foo()  // error: can’t use a stack object in this context
> }
> }
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Draft] Rename Sequence.elementsEqual

2017-10-17 Thread Gwendal Roué via swift-evolution
Oops, I apologize for the buggy implementation of the 
Collection.anyElement(notEqualTo:) method I did provide.

My point was just to show that there are useful generic algorithms that can use 
the observable ordering of sets and dictionaries, despite the fact that those 
ordering can not be controlled by the programmer.

Gwendal

> Le 17 oct. 2017 à 09:03, Gwendal Roué via swift-evolution 
> <swift-evolution@swift.org> a écrit :
> 
>>> Modeling is, by definition, imperfect. The question is, what imperfect 
>>> model is most useful _to Swift_. The idea is that conforming Set and 
>>> Dictionary to Collection is on balance more useful than not doing so; that 
>>> having two protocols, Sequence and Collection, is on balance more useful 
>>> than having one or three, and that the set of semantic guarantees of 
>>> Collection are on balance more useful than other possible sets of semantic 
>>> guarantees.
>> 
>> That is your idea which is disputed and underlined with arguments whereas 
>> you keep repeating that Set behaves as dictated by its conformance without 
>> giving use cases why this should be useful.
> 
> Hello,
> 
> You can't *control* the ordering of a set or a dictionary, but you can still 
> *rely* on it.
> 
> For example, to find a key in a dictionary that is associated a given value, 
> you can rely on the fact that a dictionary's order is guaranteed to be 
> stable, and that on top of that its indexes can address the dictionary 
> itself, but also its keys and values sequences. The code below has no bug;
> 
> let dict = ["a": "foo", "b": "bar", "c": "needle"]
> 
> // Find a key associated with "needle"
> if let index = dict.values.index(of: "needle") {
> let key = dict.keys[index]
> print(key) // prints "c"
> }
> 
> It's more difficult to find a use case for set's ordering and indexes. But 
> since you ask, here is an example. The goal is to find any element which is 
> not equal to another value, in any collection:
> 
> extension Collection where Element: Equatable {
> /// Returns any element which is not equal to the given element
> func anyElement(notEqualTo v: Element) -> Element? {
> if let i = index(of: v) {
> if let alt = index(i, offsetBy: 1, limitedBy: endIndex), alt != 
> endIndex {
> return self[alt]
> }
> if i == startIndex {
> return nil
> }
> return first
> }
> return first
> }
> }
> 
> Set([1, 2, 3]).anyElement(notEqualTo: 1) // 2 or 3
> Set([1, 2]).anyElement(notEqualTo: 1)// 2
> Set([1]).anyElement(notEqualTo: 1)   // nil
> Set([2]).anyElement(notEqualTo: 1)   // 2
> Set([]).anyElement(notEqualTo: 1)// nil
> 
> That *can* be useful, isn't it?
> 
> Gwendal Roué
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Draft] Rename Sequence.elementsEqual

2017-10-17 Thread Gwendal Roué via swift-evolution
>> Modeling is, by definition, imperfect. The question is, what imperfect model 
>> is most useful _to Swift_. The idea is that conforming Set and Dictionary to 
>> Collection is on balance more useful than not doing so; that having two 
>> protocols, Sequence and Collection, is on balance more useful than having 
>> one or three, and that the set of semantic guarantees of Collection are on 
>> balance more useful than other possible sets of semantic guarantees.
> 
> That is your idea which is disputed and underlined with arguments whereas you 
> keep repeating that Set behaves as dictated by its conformance without giving 
> use cases why this should be useful.

Hello,

You can't *control* the ordering of a set or a dictionary, but you can still 
*rely* on it.

For example, to find a key in a dictionary that is associated a given value, 
you can rely on the fact that a dictionary's order is guaranteed to be stable, 
and that on top of that its indexes can address the dictionary itself, but also 
its keys and values sequences. The code below has no bug;

let dict = ["a": "foo", "b": "bar", "c": "needle"]

// Find a key associated with "needle"
if let index = dict.values.index(of: "needle") {
let key = dict.keys[index]
print(key) // prints "c"
}

It's more difficult to find a use case for set's ordering and indexes. But 
since you ask, here is an example. The goal is to find any element which is not 
equal to another value, in any collection:

extension Collection where Element: Equatable {
/// Returns any element which is not equal to the given element
func anyElement(notEqualTo v: Element) -> Element? {
if let i = index(of: v) {
if let alt = index(i, offsetBy: 1, limitedBy: endIndex), alt != 
endIndex {
return self[alt]
}
if i == startIndex {
return nil
}
return first
}
return first
}
}

Set([1, 2, 3]).anyElement(notEqualTo: 1) // 2 or 3
Set([1, 2]).anyElement(notEqualTo: 1)// 2
Set([1]).anyElement(notEqualTo: 1)   // nil
Set([2]).anyElement(notEqualTo: 1)   // 2
Set([]).anyElement(notEqualTo: 1)// nil

That *can* be useful, isn't it?

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-13 Thread Gwendal Roué via swift-evolution
>> If I take on my free time exposing issues, it's because I hope that maybe 
>> some reader will consider them with proper attention, then maybe agree that 
>> there is an issue worth investigating, and then many conclude that a made 
>> decision has to be reverted. That's a multi-step process. And that process 
>> starts with a proper read of the issues that have been exposed.
> 
> Keep in mind that by posting to this list, you are also demanding other 
> people spend their free time on the issue. And again, these issues have 
> already been discussed. If a point is made once but doesn't carry the day, 
> repeating it again and again doesn't make it more convincing.

The fact that you fail at evaluating the relevance of an issue, as exemplified 
by the fact that you never answer directly to the described problems, does not 
make that issue moot. Instead, it may well end in the ears of people who have 
been more engaged in the subject: Tony Allevato as the author of SE-0185, and 
Chris Lattner the review manager.

Their feedback would be especially appreciated, considering that the SE-0185 
acceptance rationale 
(https://lists.swift.org/pipermail/swift-evolution-announce/2017-August/000400.html)
 doesn't address the issues I'm please to repeat for the interested readers:

> For reference, here are some issues with implicit synthesis:
> 
> - 
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039704.html
> - 
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039710.html

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-12 Thread Gwendal Roué via swift-evolution

> Le 13 sept. 2017 à 06:28, Xiaodi Wu  a écrit :
> 
> 
> On Tue, Sep 12, 2017 at 23:26 Gwendal Roué  > wrote:
> 
> > Le 13 sept. 2017 à 04:05, Xiaodi Wu  > > a écrit :
> >
> > On Tue, Sep 12, 2017 at 2:30 PM, Gwendal Roué  > > wrote:
> > >> In none of those cases, the compiler emits any warning. It's thus easy 
> > >> to forget or miss the problem, and uneasy to fix it (you'll need a 
> > >> runtime failure to spot it, or a thorough code review).
> > >>
> > >> I hope you agree with this last sentence. This unbalance between the 
> > >> easiness of the mistake and the easiness of the fix should ring a bell 
> > >> to language designers.
> > >
> > > Suppose instead this were about a protocol named Fooable and a 
> > > requirement called foo() that has a default implementation. Everything 
> > > you just talked about would apply equally. Am I to understand that you 
> > > are opposed to default implementations in general? If so, then that’s got 
> > > nothing to do with synthesized Equatable conformance. If not, then you’ll 
> > > have to justify why.
> >
> > Sounds like a good argument, until one realises that if a protocol does not 
> > provide a default implementations for a method, it may be because a default 
> > implementations is impossible to provide (the most usual case), or because 
> > it would be unwise to do so.
> >
> > And indeed, the topic currently discussed is not if we should remove or not 
> > default implementations. Instead, the question is: is it wise or not to 
> > provide an *implicit* default Equatable/Hashable/XXX implementation?
> >
> > Right, _that_ is the question. It was asked during review for the proposal, 
> > and the agreed upon answer is _yes_.
> 
> Wrong. This whole thread is about *explicit* synthetic behavior;. If an 
> agreed proposal has to be invalidated in the way, _so be it_.
> 
> Gwendal
> 
> Explicit (e.g., "AutoEquatable") and implicit synthetic behavior were both 
> considered during the proposal which approved the implicit behavior. This 
> question has been asked and answered.

We're in a new thread now, which may drive the core team into reconsidering a 
previous decision.

It happens. You may remember a funny debate about SE-0110. In the end a 
question that had been asked and answered got a whole new answer.

We're all here to improve the language. That's why I sometimes participate in 
this mailing list.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-12 Thread Gwendal Roué via swift-evolution

> Le 13 sept. 2017 à 04:05, Xiaodi Wu  a écrit :
> 
> On Tue, Sep 12, 2017 at 2:30 PM, Gwendal Roué  wrote:
> >> In none of those cases, the compiler emits any warning. It's thus easy to 
> >> forget or miss the problem, and uneasy to fix it (you'll need a runtime 
> >> failure to spot it, or a thorough code review).
> >>
> >> I hope you agree with this last sentence. This unbalance between the 
> >> easiness of the mistake and the easiness of the fix should ring a bell to 
> >> language designers.
> >
> > Suppose instead this were about a protocol named Fooable and a requirement 
> > called foo() that has a default implementation. Everything you just talked 
> > about would apply equally. Am I to understand that you are opposed to 
> > default implementations in general? If so, then that’s got nothing to do 
> > with synthesized Equatable conformance. If not, then you’ll have to justify 
> > why.
> 
> Sounds like a good argument, until one realises that if a protocol does not 
> provide a default implementations for a method, it may be because a default 
> implementations is impossible to provide (the most usual case), or because it 
> would be unwise to do so.
> 
> And indeed, the topic currently discussed is not if we should remove or not 
> default implementations. Instead, the question is: is it wise or not to 
> provide an *implicit* default Equatable/Hashable/XXX implementation?
> 
> Right, _that_ is the question. It was asked during review for the proposal, 
> and the agreed upon answer is _yes_.

Wrong. This whole thread is about *explicit* synthetic behavior;. If an agreed 
proposal has to be invalidated in the way, _so be it_.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-12 Thread Gwendal Roué via swift-evolution
>> In none of those cases, the compiler emits any warning. It's thus easy to 
>> forget or miss the problem, and uneasy to fix it (you'll need a runtime 
>> failure to spot it, or a thorough code review).
>> 
>> I hope you agree with this last sentence. This unbalance between the 
>> easiness of the mistake and the easiness of the fix should ring a bell to 
>> language designers.
> 
> Suppose instead this were about a protocol named Fooable and a requirement 
> called foo() that has a default implementation. Everything you just talked 
> about would apply equally. Am I to understand that you are opposed to default 
> implementations in general? If so, then that’s got nothing to do with 
> synthesized Equatable conformance. If not, then you’ll have to justify why.

Sounds like a good argument, until one realises that if a protocol does not 
provide a default implementations for a method, it may be because a default 
implementations is impossible to provide (the most usual case), or because it 
would be unwise to do so.

And indeed, the topic currently discussed is not if we should remove or not 
default implementations. Instead, the question is: is it wise or not to provide 
an *implicit* default Equatable/Hashable/XXX implementation?

The tenant of explicit synthesis attempt to say that it would be unwise to do 
so. Please don't have us repeat again, that would be disrespectful.

BTW, Happy Keynote to everybody!
Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-12 Thread Gwendal Roué via swift-evolution

> Le 12 sept. 2017 à 17:26, Tony Allevato  a écrit :
> 
> Since your game involves the specific question of a property that should not 
> be considered for Equatable synthesis, and since SE-0185 explicitly calls out 
> the notion of transient properties as a future direction to solve that 
> specific problem, then my solution is "I declare the property as transient."
> 
> Surely this is an acceptable solution? It achieves the goal you set, and more 
> concisely/quickly than the ways you proposed in that post. It doesn't require 
> me to go fishing through code; the act of adding the property and making it 
> transient is completely localized to one place (it's one line!). If there's a 
> synthesized implementation of Equatable, then the property gets ignored as 
> desired. If there's a handwritten implementation, then the new property is 
> already ignored because it wasn't there to begin with, but the transient 
> declaration still provides valuable information to the reader of the code 
> about the intention.
> 
> If the rebuttal to that is going to be "a developer may not know about 
> transient", then where do we draw the line at expecting users to know how to 
> use the features their language? It's a significant leap to go from 
> "developers might do the wrong thing" to "so this specific approach is the 
> only right way to fix it."

Your answer is totally valid in a world where properties can be declared 
transient.

So you may now be aware that in a world where there are no transient 
properties, implicit synthesis of Equatable and Hashable conformance has 
problems that explicit synthesis has not. Making more people aware of this is 
my only goal in this thread.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-12 Thread Gwendal Roué via swift-evolution
>> There is this sample code by Thorsten Seitz with a cached property which is 
>> quite simple and clear : 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039684.html
>> 
>> This is the sample code that had me enter the "worried" camp.'
>> 
> I really like Thorsten's example, because it actually proves that requiring 
> explicit derivation is NOT the correct approach here. (Let's set aside the 
> fact that Optionals prevent synthesis because we don't have conditional 
> conformances yet, and assume that we've gotten that feature as well for the 
> sake of argument.)
> 
> Let's look at two scenarios:
> 
> 1) Imagine I have a value type with a number of simple Equatable properties. 
> In a world where synthesis is explicit, I tell that value type to "derive 
> Equatable". Everything is fine. Later, I decide to add some cache property 
> like in Thorsten's example, and that property just happens to also be 
> Equatable. After doing so, the correct thing to do would be to remove the 
> "derive" part and provide my custom implementation. But if I forget to do 
> that, the synthesized operator still exists and applies to that type. If 
> you're arguing that "derive Equatable" is better because its explicitness 
> prevents errors, you must also accept that there are possibly just as many 
> cases where that explicitness does *not* prevent errors.

It looks like it is true, but it is not. The implicit world is harder to deal 
with. And this is because in the implicit world, you never know if conformance 
has been synthesized or not. In the explicit world, you know: it's plain 
written down.

To see this point, please play the game I've proposed to Xiaodi at 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039710.html

> 2) Imagine I have a value type with 10 Equatable properties and one caching 
> property that also happens to be Equatable. The solution being proposed here 
> says that I'm better off with explicit synthesis because if I conform that 
> type to Equatable without "derive", I get an error, and then I can provide my 
> own custom implementation.

Yes.

> But I have to provide that custom implementation *anyway* to ignore the 
> caching property even if we don't make synthesis explicit. Making it explicit 
> hasn't saved me any work—it's only given me a compiler error for a problem 
> that I already knew I needed to resolve.

Oh, so compiler errors and warnings bring no information to you? :-) I'm 
impressed, but I'll keep on focusing on designing a language for average 
developpers, not only geniuses.

Replay your argument and imagine that compiler outputs are useful to you. This 
will change your conclusion.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-12 Thread Gwendal Roué via swift-evolution

> Le 12 sept. 2017 à 12:01, Xiaodi Wu  a écrit :
> 
>> There is this sample code by Thorsten Seitz with a cached property which is 
>> quite simple and clear : 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039684.html
>> 
>> This is the sample code that had me enter the "worried" camp.
> 
> Sorry, I fail to see what the problem is in that example. A method was 
> invoked that changed a stored property of one instance. Therefore, it’s no 
> longer equal to the other instance. If you want a custom notion of equality, 
> you should implement it yourself. In the absence of such, the _default_ 
> notion of equality is pretty clear.

Yes, I agree with you. As long as you reason in this way, there is no problem 
at all, just a programmer error.

I'll try to show that you need to play some moves further before problems 
appear. Don't look at the code as a static thing, but as a living thing.

Please follow me: will you play a little programmer game? Here is a snippet of 
code. It is embedded in this Xcode project which, as you can see, contains 
hundreds of files. Your mission is to add an extra property which should not be 
considered for Equatable adoption. How do you do that?

struct S : Equatable {
var x: Int
}

The answer is:

1. Find if there is an extension somewhere that implements Equatable 
conformance.
2. If you are eventually sure that there is no explicit conformance yet, write 
the correct one.

You may know that proving that something does not exist is harder than the 
opposite, and the step 1 above seems dubious to you. You are right. You thus 
use this smarter technique:

1. Write a dummy explicit conformance to Equatable, compile.
2. If compiler does not complain about duplicate implementation, conclude that 
there is no explicit conformance yet, and write the correct one.

Problem solved. And nice display of smartness and funny little compiler tricks. 




No. Please look at the topic from above, and look at how developers are 
working. Troubles in synthesized conformance can happen for several reasons:

1. Lack of knowledge. As you tend to day, nobody is supposed to ignore the law, 
and the bug is the fault of the programmer.
2. The developper creates the type, plans to add specific implementation, and 
forgets.
3. The developper eventually adds a property and misses the fact that a 
synthesized conformance exists (and is now incorrect).
4. The developper eventually adds a property and misses the fact that the 
synthesized conformance is now incorrect.
5. The developper eventually adds a property, plans to fix the synthesized 
conformance, and forgets.

Cases 2, 3 and 5 are examples of good faith mistakes.

In none of those cases, the compiler emits any warning. It's thus easy to 
forget or miss the problem, and uneasy to fix it (you'll need a runtime failure 
to spot it, or a thorough code review).

I hope you agree with this last sentence. This unbalance between the easiness 
of the mistake and the easiness of the fix should ring a bell to language 
designers.

Beyond that, it's very hard to improve one's skills in face of those programmer 
errors. They have not much value beyond blind punishment. You can't learn from 
them. I'm the last one who wishes to see a weird cultural paranoia against 
Equatable: look at how "smart" and versed in Swift subtleties you need to be to 
just add a simple property to an innocuous struct!

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-11 Thread Gwendal Roué via swift-evolution
> 
>> This doesn't align with how Swift views the role of protocols, though. One 
>> of the criteria that the core team has said they look for in a protocol is 
>> "what generic algorithms would be written using this protocol?" 
>> AutoSynthesize doesn't satisfy that—there are no generic algorithms that you 
>> would write with AutoEquatable that differ from what you would write with 
>> Equatable.
> 
> And so everybody has to swallow implicit and non-avoidable code synthesis and 
> shut up?
> 
> That's not what I said. I simply pointed out one of the barriers to getting a 
> new protocol added to the language.
> 
> Code synthesis is explicitly opt-in and quite avoidable—you either don't 
> conform to the protocol, or you conform to the protocol and provide your own 
> implementation. What folks are differing on is whether there should have to 
> be *two* explicit switches that you flip instead of one.

No. One does not add a protocol conformance by whim. One adds a protocol 
conformance by need. So the conformance to the protocol is a *given* in our 
analysis of the consequence of code synthesis. You can not say "just don't 
adopt it".

As soon as I type the protocol name, I get synthesis. That's the reason why the 
synthesized code is implicit. The synthesis is explicitly written in the 
protocol documentation, if you want. But not in the programmer's code.

I did use "non-avoidable" badly, you're right: one can avoid it, by providing 
its custom implementation.

So the code synthesis out of a mere protocol adoption *is* implicit.

> Let's imagine a pie. The whole pie is the set of all Swift types. Some slice 
> of that pie is the subset of those types that satisfy the conditions that 
> allow one of our protocols to be synthesized. Now that slice of pie can be 
> sliced again, into the subset of types where (1) the synthesized 
> implementation is correct both in terms of strict value and of business 
> logic, and (2) the subset where it is correct in terms of strict value but is 
> not the right business logic because of something like transient data.

Yes.

> What we have to consider is, how large is slice (2) relative to the whole 
> pie, *and* what is the likelihood that developers are going to mistakenly 
> conform to the protocol without providing their own implementation, *and* is 
> the added complexity worth protecting against this case?

That's quite a difficult job: do you think you can evaluate this likelihood?

Explicit synthesis has big advantage: it avoids this question entirely.

Remember that the main problem with slide (2) is that developers can not 
*learn* to avoid it.

For each type is slide (2) there is a probability that it comes into existence 
with a forgotten explicit protocol adoption. And this probability will not go 
down as people learn Swift and discover the existence of slide (2). Why? 
because this probability is driven by unavoidable human behaviors:
- developer doesn't see the problem (a programmer mistake)
- the developper plans to add explicit conformance later and happens to forget 
(carelessness)
- a developper extends an existing type with a transient property, and doesn't 
add the explicit protocol conformance that has become required.

Case 2 and 3 bite even experienced developers. And they can't be improved by 
learning.

Looks like the problem is better defined as an ergonomics issue, now.

> If someone can show me something that points to accidental synthesized 
> implementations being a significant barrier to smooth development in Swift, 
> I'm more than happy to consider that evidence. But right now, this all seems 
> hypothetical ("I'm worried that...") and what's being proposed is adding 
> complexity to the language (an entirely new axis of protocol conformance) 
> that would (1) solve a problem that may not exist to any great degree, and 
> (2) does not address the fact that if that problem does indeed exist, then 
> the same problem just as likely exists with certain non-synthesized default 
> implementations.

There is this sample code by Thorsten Seitz with a cached property which is 
quite simple and clear : 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039684.html
 


This is the sample code that had me enter the "worried" camp.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-11 Thread Gwendal Roué via swift-evolution

> Le 11 sept. 2017 à 23:37, Tony Allevato via swift-evolution 
>  a écrit :
> 
> All this is a subtle, but important, distinction. One day, when Swift has the 
> ability to introspect metadata about a type and its properties, someone may 
> want to use a hypothetical "transient" attribute for something wholly 
> unrelated to synthesis.

My thoughts exactly. The language is not ready yet for exclusion of some 
members in synthetic code.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-11 Thread Gwendal Roué via swift-evolution

> Le 11 sept. 2017 à 23:41, Gwendal Roué  a écrit :
> 
> Doesn't it escalate pretty quickly into complex and ad-hoc language 
> constructs?
> 
> Like everybody I like code synthesis. Like some, I'm worried that implicit 
> synthesis would hide a few bugs that are hard to debunk. I also agree that 
> developers who complain about those bugs would rightfully get the "behaves as 
> expected" and "RTFM" classical answers. The problem with those deserved 
> answers is that there's not much lesson to learn. Being bitten one, two, 
> three times does not reduce the probability of being bitten another time. 
> Programmer errors due to carelessness are the most difficult errors to 
> prevent, don't you all agree?
> 
> People who use Sourcery are quite happy with AutoEquatable and AutoHashable. 
> I don't know of anybody who complains of those. People are happy. Nobody 
> types `AutoEquatable` by mistake: they get synthesis where they ask for it, 
> and move on their next task without thinking much more about it. Sounds like 
> a developer's dream, isn't it?
> 
>> This doesn't align with how Swift views the role of protocols, though. One 
>> of the criteria that the core team has said they look for in a protocol is 
>> "what generic algorithms would be written using this protocol?" 
>> AutoSynthesize doesn't satisfy that—there are no generic algorithms that you 
>> would write with AutoEquatable that differ from what you would write with 
>> Equatable.
> 
> And so everybody has to swallow implicit and non-avoidable code synthesis and 
> shut up?

Sorry Tony, I didn't quote your sentence properly.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-11 Thread Gwendal Roué via swift-evolution
Doesn't it escalate pretty quickly into complex and ad-hoc language constructs?

Like everybody I like code synthesis. Like some, I'm worried that implicit 
synthesis would hide a few bugs that are hard to debunk. I also agree that 
developers who complain about those bugs would rightfully get the "behaves as 
expected" and "RTFM" classical answers. The problem with those deserved answers 
is that there's not much lesson to learn. Being bitten one, two, three times 
does not reduce the probability of being bitten another time. Programmer errors 
due to carelessness are the most difficult errors to prevent, don't you all 
agree?

People who use Sourcery are quite happy with AutoEquatable and AutoHashable. I 
don't know of anybody who complains of those. People are happy. Nobody types 
`AutoEquatable` by mistake: they get synthesis where they ask for it, and move 
on their next task without thinking much more about it. Sounds like a 
developer's dream, isn't it?

> This doesn't align with how Swift views the role of protocols, though. One of 
> the criteria that the core team has said they look for in a protocol is "what 
> generic algorithms would be written using this protocol?" AutoSynthesize 
> doesn't satisfy that—there are no generic algorithms that you would write 
> with AutoEquatable that differ from what you would write with Equatable.

And so everybody has to swallow implicit and non-avoidable code synthesis and 
shut up?

Gwendal

> Le 11 sept. 2017 à 23:05, Vladimir.S via swift-evolution 
>  a écrit :
> 
> On 11.09.2017 21:55, Thorsten Seitz via swift-evolution wrote:
>> I think I do understand Haravikk's argument (actually it seems quite 
>> straightforward to me).
>> An example should be:
>> struct Foo : Equatable {
>> var x: Int
>> var cachedLabel: String? = nil
>> init(x: Int) {
>> self.x = x
>> }
>> mutating func label() {
>> if let label = cachedLabel {
>> return label
>> }
>> let label = calculateLabel()
>> cachedLabel = label
>> return cachedLabel
>> }
>> }
>> var foo1 = Foo(x: 1)
>> var foo2 = Foo(x: 1)
>> foo1 == foo2 // true
>> var label = foo1.label()
>> foo1 == foo2 // now false, due to cachedString being falsely included in the 
>> comparison
>> The problem is that the developer was not required to implement the protocol 
>> and so might forget it.
>> The difference to other default implementations is that those use the 
>> protocol itself as building blocks and so are correct with regards to the 
>> protocol's semantics, whereas the synthesized equality reaches deeply into 
>> the private innards of a struct and therefore is much more likely to be 
>> wrong as in the example above.
>> Why not just write
>> *struct* Foo : *deriving* Equatable {...}
>> to request the synthesized implementation?
> 
> FWIW, +100. The same should be required for Codable. I support the opinion 
> that 'synthesized' methods differs from protocol-default-implementation in 
> what 'kind' of data they use: defined by protocol itself or internals of the 
> conformed type. And this can lead to more un-expected problems.
> 
> If protocol is able to synthesize its requirements, it should require a 
> 'deriving'-like marker when type conforms to it to make it absolutely clear 
> what happens here. It would be not a confusion point, but clarify the 
> intention to better understand the code.
> 
> Thinking about *future* custom protocols that could implement requirements in 
> default implementation by using macros/reflection, for me it seems like such 
> protocol should *also* somehow explicitly state that some requirements are 
> auto-synthesized, probably by conforming(derive) to some compiler-magic 
> protocol 'AutoSynthesize'.
> (i.e. 'protocol MySynthesizeable: AutoSynthesize {...}')
> 
> So each built-in protocol like Equatable/Hashable/Codable will conform to it, 
> and also, each custom "auto-synthesizeable" protocol - also should explicitly 
> conform to AutoSynthesize. So, when type conforms to it - such type should 
> use 'deriving'-like marker if auto-generation of methods is expected.
> 
> I also have a question regarding future direction of 'exclusion' of fields 
> from being included into auto-generated implementation of 
> Equatable/Hashable/Codable/other.
> 
> If we'll have this 'deriving'-like marker, it seems naturally if we mark some 
> member with some kind of '@noderiving' marker, like here:
> 
> struct Foo : deriving Equatable {
>  var x: Int
>  var y: Int
>  var z: Int
>  @noderiving var cachedLabel: String? = nil
> }
> 
> this @noderiving directive will work for protocols based on AutoSynthesize 
> magic protocol. I.e., if you construct your own protocol with 
> auto-synthesizeable methods, to be able to *know* which members should be 
> 'excluded' for your implementation, you should base your protocol on 
> AutoSynthesize protocol.
> 
> I hope this makes any 

Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-09 Thread Gwendal Roué via swift-evolution
All right, I'll be more positive: our science, IT, is a *constructive* science, 
by *essence*. If there is a problem, there must be a way to show it.

It you can't, then there is no problem.

Gwendal

> Le 9 sept. 2017 à 15:26, Gwendal Roué  a écrit :
> 
> Hello Haravikk,
> 
> I'lm worried that you fail at preventing a real problem. May I suggest a 
> change in your strategy?
> 
> Sometimes, sample code greatly helps turning subtle ideas into blatant 
> evidence. After all, subtleties are all about corner cases, and corner cases 
> are the blind spots of imagination. What about giving that little something 
> that would help your readers grasp your arguments?
> 
> I don't quite know what example you will provide, but I could suggest the 
> exhibition of a practical problem with Equatable synthesis. We'll know better 
> if the problem can arise in the Standard lib, in third-party libraries, at 
> application level, or at several scales at the same time. It would also be 
> nice to see your solution to the problem, that is to say an alternative that 
> still provides code synthesis for developers that want to opt in the feature, 
> but avoids the caveat of the initial example. I hope this would greatly help 
> the discussion move forward.
> 
> Last general comment about the topic: if Haravikk is right, and that code 
> synthesis should indeed be explicit, then that wouldn't be such a shame.
> 
> My two cents,
> Gwendal Roué
> 
> 
>> Le 9 sept. 2017 à 13:41, Haravikk via swift-evolution 
>> > a écrit :
>> 
>>> 
>>> On 9 Sep 2017, at 09:33, Xiaodi Wu >> > wrote:
>>> 
>>> 
>>> On Sat, Sep 9, 2017 at 02:47 Haravikk via swift-evolution 
>>> > wrote:
>>> 
 On 9 Sep 2017, at 02:02, Xiaodi Wu > wrote:
 
 On Fri, Sep 8, 2017 at 4:00 PM, Itai Ferber via swift-evolution 
 > wrote:
 
 
> On Sep 8, 2017, at 12:46 AM, Haravikk via swift-evolution 
> > wrote:
> 
> 
>> On 7 Sep 2017, at 22:02, Itai Ferber > > wrote:
>> 
>> protocol Fooable : Equatable { // Equatable is just a simple example
>> var myFoo: Int { get }
>> }
>> 
>> extension Fooable {
>> static func ==(_ lhs: Self, _ rhs: Self) -> Bool {
>> return lhs.myFoo == rhs.myFoo
>> }
>> }
>> 
>> struct X : Fooable {
>> let myFoo: Int
>> let myName: String
>> // Whoops, forgot to give an implementation of ==
>> }
>> 
>> print(X(myFoo: 42, myName: "Alice") == X(myFoo: 42, myName: "Bob")) // 
>> true
>> This property is necessary, but not sufficient to provide a correct 
>> implementation. A default implementation might be able to assume 
>> something about the types that it defines, but it does not necessarily 
>> know enough.
> 
> Sorry but that's a bit of a contrived example; in this case the protocol 
> should not implement the equality operator if more information may be 
> required to define equality. It should only be implemented if the 
> protocol is absolutely clear that .myFoo is the only part of a Fooable 
> that can or should be compared as equatable, e.g- if a Fooable is a 
> database record and .myFoo is a primary key, the data could differ but it 
> would still be a reference to the same record.
> 
> To be clear, I'm not arguing that someone can't create a regular default 
> implementation that also makes flawed assumptions, but that 
> synthesised/reflective implementations by their very nature have to, as 
> they cannot under every circumstance guarantee correctness when using 
> parts of a concrete type that they know nothing about.
 
 You can’t argue this both ways:
 If you’re arguing this on principle, that in order for synthesized 
 implementations to be correct, they must be able to — under every 
 circumstance — guarantee correctness, then you have to apply the same 
 reasoning to default protocol implementations. Given a default protocol 
 implementation, it is possible to come up with a (no matter how contrived) 
 case where the default implementation is wrong. Since you’re arguing this 
 on principle, you cannot reject contrived examples.
 If you are arguing this in practice, then you’re going to have to back up 
 your argument with evidence that synthesized examples are more often wrong 
 than default implementations. You can’t declare that synthesized 
 implementations are by nature incorrect but allow default implementations 
 to slide because in 

Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-09 Thread Gwendal Roué via swift-evolution
Hello Haravikk,

I'lm worried that you fail at preventing a real problem. May I suggest a change 
in your strategy?

Sometimes, sample code greatly helps turning subtle ideas into blatant 
evidence. After all, subtleties are all about corner cases, and corner cases 
are the blind spots of imagination. What about giving that little something 
that would help your readers grasp your arguments?

I don't quite know what example you will provide, but I could suggest the 
exhibition of a practical problem with Equatable synthesis. We'll know better 
if the problem can arise in the Standard lib, in third-party libraries, at 
application level, or at several scales at the same time. It would also be nice 
to see your solution to the problem, that is to say an alternative that still 
provides code synthesis for developers that want to opt in the feature, but 
avoids the caveat of the initial example. I hope this would greatly help the 
discussion move forward.

Last general comment about the topic: if Haravikk is right, and that code 
synthesis should indeed be explicit, then that wouldn't be such a shame.

My two cents,
Gwendal Roué


> Le 9 sept. 2017 à 13:41, Haravikk via swift-evolution 
>  a écrit :
> 
>> 
>> On 9 Sep 2017, at 09:33, Xiaodi Wu > > wrote:
>> 
>> 
>> On Sat, Sep 9, 2017 at 02:47 Haravikk via swift-evolution 
>> > wrote:
>> 
>>> On 9 Sep 2017, at 02:02, Xiaodi Wu >> > wrote:
>>> 
>>> On Fri, Sep 8, 2017 at 4:00 PM, Itai Ferber via swift-evolution 
>>> > wrote:
>>> 
>>> 
 On Sep 8, 2017, at 12:46 AM, Haravikk via swift-evolution 
 > wrote:
 
 
> On 7 Sep 2017, at 22:02, Itai Ferber  > wrote:
> 
> protocol Fooable : Equatable { // Equatable is just a simple example
> var myFoo: Int { get }
> }
> 
> extension Fooable {
> static func ==(_ lhs: Self, _ rhs: Self) -> Bool {
> return lhs.myFoo == rhs.myFoo
> }
> }
> 
> struct X : Fooable {
> let myFoo: Int
> let myName: String
> // Whoops, forgot to give an implementation of ==
> }
> 
> print(X(myFoo: 42, myName: "Alice") == X(myFoo: 42, myName: "Bob")) // 
> true
> This property is necessary, but not sufficient to provide a correct 
> implementation. A default implementation might be able to assume 
> something about the types that it defines, but it does not necessarily 
> know enough.
 
 Sorry but that's a bit of a contrived example; in this case the protocol 
 should not implement the equality operator if more information may be 
 required to define equality. It should only be implemented if the protocol 
 is absolutely clear that .myFoo is the only part of a Fooable that can or 
 should be compared as equatable, e.g- if a Fooable is a database record 
 and .myFoo is a primary key, the data could differ but it would still be a 
 reference to the same record.
 
 To be clear, I'm not arguing that someone can't create a regular default 
 implementation that also makes flawed assumptions, but that 
 synthesised/reflective implementations by their very nature have to, as 
 they cannot under every circumstance guarantee correctness when using 
 parts of a concrete type that they know nothing about.
>>> 
>>> You can’t argue this both ways:
>>> If you’re arguing this on principle, that in order for synthesized 
>>> implementations to be correct, they must be able to — under every 
>>> circumstance — guarantee correctness, then you have to apply the same 
>>> reasoning to default protocol implementations. Given a default protocol 
>>> implementation, it is possible to come up with a (no matter how contrived) 
>>> case where the default implementation is wrong. Since you’re arguing this 
>>> on principle, you cannot reject contrived examples.
>>> If you are arguing this in practice, then you’re going to have to back up 
>>> your argument with evidence that synthesized examples are more often wrong 
>>> than default implementations. You can’t declare that synthesized 
>>> implementations are by nature incorrect but allow default implementations 
>>> to slide because in practice, many implementations are allowable. There’s a 
>>> reason why synthesis passed code review and was accepted: in the majority 
>>> of cases, synthesis was deemed to be beneficial, and would provide correct 
>>> behavior. If you are willing to say that yes, sometimes default 
>>> implementations are wrong but overall they’re correct, you’re going to have 
>>> to provide hard evidence to back up the opposite case for synthesized 
>>> 

Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-07 Thread Gwendal Roué via swift-evolution

> Le 7 sept. 2017 à 19:53, Tony Allevato  a écrit :
> 
> Again, this is not the issue that Haravikk is describing in this thread.

Yes, I better understand now. Please forgive the pollution.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-07 Thread Gwendal Roué via swift-evolution

> Le 7 sept. 2017 à 14:45, Tony Allevato  a écrit :
> 
> Right, let's make sure we're talking about the right thing here. Gwendal, 
> your issue isn't with synthesis in the form of Codable or the new additions 
> to Equatable/Hashable which are opt-in-by-conformance, it's with the specific 
> case of raw value enums or enums without associated values where the 
> synthesis is implicit with no way to opt-out. That's a big difference.

Yes.

> I can definitely see the latter being an issue if it were more widespread, 
> and I'd be supportive of those enums being required to declare their 
> conformance for consistency (though it would be source breaking).

Yes, unfortunately.

> However, I still haven't seen a real issue that has come up because of the 
> distinction being drawn here between default implementations vs. 
> implementations that can access other parts of the concrete type. It sounds 
> like this discussion is trying to protect against a hypothetical problem that 
> hasn't happened yet and may not happen; it would be helpful to show some 
> motivating real-world cases where this is indeed a severe problem.

Yes. I'm not talking about implementation itself. I know this has been the main 
topic until I have tried to bring in the topic of the consequences of 
non-avoidable synthesis (extra methods that may conflict with userland methods).

If you ask me for a real-world case, then I think I gave one. Let me rephrase 
it:

it's impossible to define a value-backed enum without getting free Equatable 
conformance. This free conformance is sometimes unwanted, and I gave the 
example of DSLs. Now this problem is not *severe*. It's more a blind spot in 
the language, and finally just an unwanted side-effect of a compiler 
convenience,

This example gives a little argument, but still an argument, for "explicit 
synthetic behavior", the topic of this thread.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-07 Thread Gwendal Roué via swift-evolution

> Le 7 sept. 2017 à 14:37, Matthew Johnson  a écrit :
> 
> I don't understand what this has to do with synthesized Equatable.  Wouldn't 
> manually implemented Equatable have the same impact?  The design of a DSL 
> should be able to accommodate conformance to basic protocols without 
> ambiguity.


I'll explain you:

The problem with synthesized Equatable is that it adds an unwanted == operator 
that returns a Bool.

This operator is unwanted because it conflicts with the == operator defined by 
the DSL which does not return a Bool.

// Without synthesised Equatable
let r = (a == b) // the type defined by the DSL

// With synthesised Equatable
let r = (a == b) // ambiguous

This is the same kind of conflict that happen when a function is overloaded 
with two return types:

func f() -> Int { ... }
func f() -> String { ... }
f() // ambiguous

Without the synthesized Equatable, the type would not have any == operator that 
returns a Bool, and thus no conflict with the == operator defined by the DSL 
(the one that returns an SQL expression, in our particular context).

I hope that I have explained how synthesized conformance may impact code by the 
mere fact that they define methods. I'm not talking about the correctness of 
the synthesized code. I'm talking about its mere existence.

> We generally want as many types to be Equatable and Hashable as possible.  
> Synthesized conformance means more types will have these conformance and 
> that's a good thing in all cases (so long as the implementation is correct).  

Sure, of course. I'm with you. I'm not talking against code synthesis. Again, 
I'm not talking about the correctness either.

I'm talking about the consequences of implicit and non-avoidable synthesis. 
Exactly the theme of this thread, unless I'm totally mistaken.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-07 Thread Gwendal Roué via swift-evolution
Hello,

I'm interested in this debate because I've been bitten by automatic synthesis 
recently.

I'm reading your discussion, but I don't have a strong opinion. I only have an 
anecdote: implicit, automatic, and unavoidable code synthesis code can make it 
difficult to write some DSLs (aka Domain-Specific Languages).

I did stumble against undesired Equatable synthesis while developping a 
library[1] that generates SQL snippets. In this library, the `==` operator does 
not return a Bool: it returns an SQL expression:

// SELECT * FROM players WHERE bestScore = 1000
Player.filter(bestScore == 1000)

Since the library is free to define == as an operator that returns an SQL 
expression, this works quite well. Even when both operands have the same type:

// SELECT * FROM players WHERE lastScore = bestScore
Player.filter(lastScore == bestScore)

However, as soon as the type is (also) Equatable, an ambiguity occurs, and the 
DSL is basically broken:

Player.filter(lastScore == bestScore) // which == please?

In this case, the == from synthesized Equatable conformance is not welcome at 
all. It prevents the library from controlling the return type of the == 
operator. Equatable conformance is unavoidable for enums based on String or 
generally any raw value type that adopts Equatable. The consequence is that my 
library can't allow its users to define an enum of table columns.

This is not a deal breaker. Everybody can live with this little caveat, and I 
guess I'm the only one who wishes things had been more *consistent*. But still: 
this story helps realizing that code synthesis can bite in plenty of unexpected 
ways.

Thanks for reading,
Gwendal Roué
[1] http://github.com/groue/GRDB.swift

> Le 7 sept. 2017 à 12:20, Haravikk via swift-evolution 
>  a écrit :
> 
>> 
>> On 7 Sep 2017, at 00:11, Brent Royal-Gordon > > wrote:
>> 
>>> On Sep 5, 2017, at 1:02 PM, Haravikk via swift-evolution 
>>> > wrote:
>>> 
>>> This proposal idea is essentially for a new attribute @synthetic (name is 
>>> up for debate). This attribute is required for any default implementation 
>>> that includes reflective type compiler magic, use of the reflection API 
>>> against `self` or, in future, any native Swift macros within the method 
>>> (possibly limited to specific features, will depend on the macro language 
>>> and its capabilities).
>> 
>> 
>> "Use of the reflection API against `self`"? `String(describing:)` and 
>> `String(reflecting:)` sometimes do that.
>> 
>> I see zero justification for having @synthetic cover all of these random 
>> things, but not ordinary default implementations—they have the same amount 
>> of dangerous implicitness.
> 
> Actually they don't; the problem here is that through reflection you are 
> accessing and manipulating concrete types. A non-reflective default 
> implementation only has access to what the protocol itself has defined. The 
> synthetic alternatives are instead diving into parts of a concrete type that 
> may have nothing to do with the protocol at all, and must therefore make 
> assumptions that cannot be guaranteed to be correct, this is what makes them 
> dangerous.
> 
>> On 6 Sep 2017, at 23:43, Nevin Brackett-Rozinsky 
>> > 
>> wrote:
>>> On Wed, Sep 6, 2017 at 5:42 PM, Haravikk via swift-evolution 
>>> > wrote:
>>> the issue I'm trying to raise is that when those, and similar features, are 
>>> used in synthesised behaviour (default implementations based upon the 
>>> concrete type), that these behaviours should be opted into explicitly, 
>>> otherwise they open up potential for all kinds of bugs, even when the 
>>> assumptions being made about the concrete type are simple such as in the 
>>> case for Equatable/Hashable. There's just too much potential for this kind 
>>> of reflective protocol implementation to overreach; to me it feels very 
>>> much like going into a restaurant and the waiter coming across and 
>>> force-feeding me something I don't want instead of taking my order.
>> 
>> I might suggest that instead it is like you have gone into a pizza shop and 
>> said, “I’d like a large veggie pizza please.” And they made you a pizza with 
>> their standard dough and their standard sauce and their standard cheese and 
>> their standard selection of vegetables.
> 
> Actually I don't think that's quite it either; to strain the analogy even 
> further, I'd say it's more like going into a pizza shop and saying "I'd like 
> a pizza" and the staff looking at you and deciding you look like a vegetarian 
> and giving you a vegetarian pizza.
> 
> The crux of the issue here are the assumptions that are being made; for a 
> standard default implementation there are no 

Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-04 Thread Gwendal Roué via swift-evolution

> Le 4 sept. 2017 à 16:28, Wallacy via swift-evolution 
>  a écrit :
> 
> Hello,
> 
> I have a little question about the actors.
> 
> On WWDC 2012 Session 712 one of the most important tips (for me at least) 
> was: Improve Performance with Reader-Writer Access
> 
> Basically:
> • Use concurrent subsystem queue: DISPATCH_QUEUE_CONCURRENT
> • Use synchronous concurrent “reads”: dispatch_sync()
> • Use asynchronous serialized “writes”: dispatch_barrier_async()
> 
> [...]
> 
> With this will it be composed using actors? I see a lot of discussion about 
> using serial queues, and I also have not seen any mechanism similar to 
> dispatch_barrier_async being discussed here or in other threads.

I tend to believe that such read/write optimization could at least be 
implemented using the "Intra-actor concurrency" described by Chris Lattner at 
https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782#intra-actor-concurrency
 
.

But you generally ask the question of reader vs. writer actor methods, that 
could be backed by dispatch_xxx/dispatch_barrier_xxx. I'm not sure it's as 
simple as mutating vs. non-mutating. For example, a non-mutating method can 
still cache the result of some expensive computation without breaking the 
non-mutating contract. Unless this cache is itself a read/write-safe actor, 
such non-mutating method is not a real reader method.

That's a very interesting topic, Wallacy!

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] typed throws

2017-08-18 Thread Gwendal Roué via swift-evolution
Hello all,

I'm also on the "side" of untyped errors, but I can imagine how other 
developers may like a stricter error hierarchy. It surely fits some situations.

Enter Result and Result:

Since Swift "native" errors don't fit well with asynchronous APIs, various ways 
to encapsulate them have emerged, most of them eventually relying on some kind 
of variant of those `Result` type:

// Untyped errors
enum Result {
case success(T)
case failure(Error)
}

// Typed errors
enum Result {
case success(T)
case failure(E)
}

The first Result fits well people who like untyped errors. And Result 
fits people who prefer typed errors. Result is objectively closer to the 
"spirit" of Swift 2-4. Yet Result has the right to live as well.

When Swift 5 brings sugar syntax around async/await/etc, most needs for 
Result will naturally vanish.

However, the need for Result will remain. The debate about "typed 
throws", for me, sums up to this question: will the typed folks be able to take 
profit from the syntax sugar brought by async/await/etc of Swift 5? Or will 
they have to keep on carrying Result with them?

Gwendal Roué



> Le 18 août 2017 à 10:23, John McCall via swift-evolution 
>  a écrit :
> 
>> On Aug 18, 2017, at 3:28 AM, Charlie Monroe > > wrote:
>>> On Aug 18, 2017, at 8:27 AM, John McCall via swift-evolution 
>>> > wrote:
 On Aug 18, 2017, at 12:58 AM, Chris Lattner via swift-evolution 
 > wrote:
 Splitting this off into its own thread:
 
> On Aug 17, 2017, at 7:39 PM, Matthew Johnson  > wrote:
> One related topic that isn’t discussed is type errors.  Many third party 
> libraries use a Result type with typed errors.  Moving to an async / 
> await model without also introducing typed errors into Swift would 
> require giving up something that is highly valued by many Swift 
> developers.  Maybe Swift 5 is the right time to tackle typed errors as 
> well.  I would be happy to help with design and drafting a proposal but 
> would need collaborators on the implementation side.
 
 Typed throws is something we need to settle one way or the other, and I 
 agree it would be nice to do that in the Swift 5 cycle.
 
 For the purposes of this sub-discussion, I think there are three kinds of 
 code to think about: 
 1) large scale API like Cocoa which evolve (adding significant 
 functionality) over the course of many years and can’t break clients. 
 2) the public API of shared swiftpm packages, whose lifecycle may rise and 
 fall - being obsoleted and replaced by better packages if they encounter a 
 design problem.  
 3) internal APIs and applications, which are easy to change because the 
 implementations and clients of the APIs are owned by the same people.
 
 These each have different sorts of concerns, and we hope that something 
 can start out as #3 but work its way up the stack gracefully.
 
 Here is where I think things stand on it:
 - There is consensus that untyped throws is the right thing for a large 
 scale API like Cocoa.  NSError is effectively proven here.  Even if typed 
 throws is introduced, Apple is unlikely to adopt it in their APIs for this 
 reason.
 - There is consensus that untyped throws is the right default for people 
 to reach for for public package (#2).
 - There is consensus that Java and other systems that encourage lists of 
 throws error types lead to problematic APIs for a variety of reasons.
 - There is disagreement about whether internal APIs (#3) should use it.  
 It seems perfect to be able to write exhaustive catches in this situation, 
 since everything in knowable. OTOH, this could encourage abuse of error 
 handling in cases where you really should return an enum instead of using 
 throws.
 - Some people are concerned that introducing typed throws would cause 
 people to reach for it instead of using untyped throws for public package 
 APIs.
>>> 
>>> Even for non-public code.  The only practical merit of typed throws I have 
>>> ever seen someone demonstrate is that it would let them use contextual 
>>> lookup in a throw or catch.  People always say "I'll be able to 
>>> exhaustively switch over my errors", and then I ask them to show me where 
>>> they want to do that, and they show me something that just logs the error, 
>>> which of course does not require typed throws.  Every.  Single.  Time.
>> 
>> The issue I see here with non-typed errors is that relying on 

Re: [swift-evolution] Why you can't make someone else's class Decodable: a long-winded explanation of 'required' initializers

2017-08-03 Thread Gwendal Roué via swift-evolution

> Le 3 août 2017 à 19:10, Itai Ferber  a écrit :
> 
> I just mentioned this in my other email, but to point out here: the reason 
> this works in your case is because you adopt these methods as static funcs 
> and can reasonably rely on subclasses of NSData, NSNumber, NSString, etc. to 
> do the right thing because of work done behind the scenes in the ObjC 
> implementations of these classes (and because we’ve got established 
> subclassing requirements on these methods — all subclasses of these classes 
> are going to look approximately the same without doing anything crazy).
> 
> This would not work for Codable in the general case, however, where 
> subclasses likely need to add additional storage, properties, encoded 
> representations, etc., without equivalent requirements, either via additional 
> protocols or conventions.

Thaks for your explanation why a static method in a protocol is able to 
instantiate non final classes like NSData, NSDate, NSNumber, NSDecimalNumber, 
NSString, etc.

Is this "privilege" stable? Can I rely on it to be maintained over time? Or 
would it be a better idea to drop support for those low-level Foundation 
classes, because they'll eventually become regular classes without any specific 
support? This would not harm that much: Data, Date, String are there for a 
reason. NSDecimalNumber is the only one of its kind, though.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Why you can't make someone else's class Decodable: a long-winded explanation of 'required' initializers

2017-08-03 Thread Gwendal Roué via swift-evolution

> Le 3 août 2017 à 02:09, Jordan Rose via swift-evolution 
>  a écrit :
> 
> P.S. There's a reason why Decodable uses an initializer instead of a 
> factory-like method on the type but I can't remember what it is right now. I 
> think it's something to do with having the right result type, which would 
> have to be either 'Any' or an associated type if it wasn't just 'Self'. (And 
> if it is 'Self' then it has all the same problems as an initializer and would 
> require extra syntax.) Itai would know for sure.

For anyone interested, factory methods *can* retroactivaly be added to existing 
classes. This is how the SQLite library GRDB.swift is able to decode classes 
hierarchies like NSString, NSNumber, NSDecimalNumber, etc. from SQLite values:

The protocol for types that can instantiate from SQLite values has a factory 
method:

public protocol DatabaseValueConvertible {
/// Returns a value initialized from *dbValue*, if possible.
static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self?
}

Having Foundation classes implement it uses various techniques:

1. "Casting" (Data to NSData, or NSDate to Date, depending on which type 
provides the root conformance)

// Workaround Swift inconvenience around factory methods of non-final 
classes
func cast(_ value: T) -> U? {
return value as? U
}

extension NSData : DatabaseValueConvertible {
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? 
{
// Use Data conformance
guard let data = Data.fromDatabaseValue(dbValue) else {
return nil
}
return cast(data)
}
}

// Derives Date conformance from NSDate, for example
extension ReferenceConvertible where Self: DatabaseValueConvertible, 
Self.ReferenceType: DatabaseValueConvertible {
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? 
{
return ReferenceType.fromDatabaseValue(dbValue).flatMap { cast($0) }
}
}


2. Using magic Foundation initializers (magic because the code below compiles 
even if those are not *required* initializers). Works for NSNumber, 
NSDecimalNumber, NSString:

extension NSNumber : DatabaseValueConvertible {
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? 
{
switch dbValue.storage {
case .int64(let int64):
return self.init(value: int64)
case .double(let double):
return self.init(value: double)
default:
return nil
}
}
}

extension NSString : DatabaseValueConvertible {
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? 
{
// Use String conformance
guard let string = String.fromDatabaseValue(dbValue) else {
return nil
}
return self.init(string: string)
}
}

The magic about Foundation initializers above makes me doubt that this 
technique is general enough for Decodable to profit from it, though. Yes it 
runs on Linux, so I'm not even sure if objc runtime is required or not. I'm 
clueless ???

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Core team] Addressing the SE-0110 usability regression in Swift 4

2017-06-20 Thread Gwendal Roué via swift-evolution
A plain, simple, but very deep THANK YOU!

Gwendal Roué

> Le 20 juin 2017 à 01:40, Douglas Gregor via swift-evolution 
>  a écrit :
> 
> Hello Swift community,
> 
> Swift 3’s SE-0110 
> 
>  eliminated the equivalence between function types that accept a single type 
> and function types that take multiple arguments. However, for various 
> implementation reasons 
> ,
>  the implementation of SE-0110 (as well as the elimination of tuple “splat” 
> behavior in SE-0029 
> )
>  was not fully completed.
> 
> Swift 4 implemented more of SE-0110, which caused a fairly serious usability 
> regression, particularly with closures. Here are a few simple examples 
> involving closures that worked in Swift 3 but do not work in Swift 4:
> 
> // #1: Works in Swift 3, error in Swift 4
> myDictionary.forEach {
>   print("\($0) -> \($1)")
> }
> 
> // #2: Works in Swift 3, error in Swift 4
> myDictionary.forEach { key, value in
>   print("\(key) -> \(value)")
> }
> 
> // #3: Works in Swift 3, error in Swift 4
> myDictionary.forEach { (key, value) in
>   print("\(key) -> \(value)")
> }
> 
> Similar issues occur with passing multi-argument functions where a tuple 
> argument is expected:
> 
> // #4: Works in Swift 3, error in Swift 4
> _ = zip(array1, array2).map(+)
> 
> In all of these cases, it is possible to write a closure that achieves the 
> desired effect, but the result is more verbose and less intuitive:
> 
> // Works in both Swift 3 and Swift 4
> myDictionary.forEach { element in
>   let (key, value) = element
>   print("\(key) -> \(value)")
> }
> 
> The Swift core team feels that these usability regressions are unacceptable 
> for Swift 4. There are a number of promising solutions that would provide a 
> better model for closures and address the usability regression, but fully 
> designing and implementing those are out of scope for Swift 4.  Therefore, we 
> will “back out” the SE-0110 change regarding function arguments from Swift 4.
> 
> Specifically, when passing an argument value of function type (including 
> closures) to a parameter of function type, a multi-parameter argument 
> function can be passed to a parameter whose function type accepts a single 
> tuple (whose tuple elements match the parameter types of the argument 
> function). Practically speaking, all of the examples #1-#4 will be accepted 
> in both Swift 3 and Swift 4.
> 
> We will revisit the design in this area post-Swift 4.
> 
>   - Doug
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Change Void meaning

2017-06-12 Thread Gwendal Roué via swift-evolution
"Discussing" with Xiaodi is a special experience, isn't it?

He will bite and misrepresent you and your ideas until you get tired and your 
idea has been exhausted to death and diluted in dozens of useless messages. 
Don't feed him.

Gwendal


> Le 12 juin 2017 à 23:10, Jérémie Girault via swift-evolution 
>  a écrit :
> 
> 
> —
> very short reply expected - vsre.info 
> Jérémie Girault
> 
> On 12 juin 2017 at 22:34:45, Xiaodi Wu (xiaodi...@gmail.com 
> ) wrote:
> 
>> On Mon, Jun 12, 2017 at 3:16 PM, Jérémie Girault > > wrote:
>> I invite you to read the proposal rules again with a fresh mindset and 
>> benevolence spirit.
>> It’s my first one and may not be very clear but the rules are 
>> straightforward.
>> 
>> Especially try to forget that Void is a tuple or anything. 
>> Void is Nothing in the programmer’s mind. An instance of Void shouldn’t even 
>> exist.
>> 
>> Sorry, that's not correct. Void is what's called Unit in other languages. It 
>> exists. That is why functions with "no return value" return Void. OTOH, 
>> Never does not exist. This discussion was had in great detail during the 
>> naming debate over Never.
> 
> Let’s put facts in front of correctness assertions. Is Void = Unit in C or 
> c++ ? can you create instances of void in java ? you have Void for generics. 
> https://en.wikipedia.org/wiki/Unit_type 
> 
> And if you look at assembly, sending void or returning void actually means 
> "nothing to push on the stack / nothing to pop”. Seems like having this 
> stripping on signatures at compile-time could be great !
> 
> Actually, in my opinion we could discuss naming when we agree that the 
> mechanism works, using this name is just a way to not impact the developer 
> with code changes.
> 
> So either we agree on the fact that the mechanism works and we can move on to 
> naming, or we get back on the topic : do you see a flaw in the proposal rules 
> ? It elegantly transforms signature arity and provides the programmer a 
> natural syntax to express it’s code.
> 
>> 
>>  
>> The proposed meaning of Void is to be a “lack” of arguments. It means that 
>> each “Void” argument reduces the arity of the function by one, at its exact 
>> position. Especially look at the canonical signature definition, and the 
>> proposed rules of reduction.
>> 
>> I don't understand why you propose to name this new idea "Void". You're 
>> proposing something that's not even a lack of an argument, but an 
>> anti-argument, like anti-matter! I'm not sure I understand why this is 
>> necessary. It seems to be a very strange workaround for one specific issue 
>> arising from disallowing implicit tuple splatting.
> 
> 
> Look at other languages, when you put Void in functions in C or java, do you 
> need to add a value ? Ease of use is important. 
> 
> You imply that I disagree with splatting were I don’t, let’s not make it 
> personal. This proposal is even compatible with tuple splatting !
> 
> The proposal rules seem to work and provides great user value. Let’s try to 
> consider this !
> 
>> 
>>  
>> That proposal, if implemented, would effectively allow `Callback` to 
>> be called without arguments in the context of swift4.
>> 
>> —
>> very short reply expected - vsre.info 
>> Jérémie Girault
>> 
>> On 12 juin 2017 at 22:06:54, Xiaodi Wu (xiaodi...@gmail.com 
>> ) wrote:
>> 
>>> On Mon, Jun 12, 2017 at 2:56 PM, Jérémie Girault >> > wrote:
>>> @Xiaodi Wu
>>> Disagree, and we would need the original designer here to help us, but my 
>>> understanding of the original meaning of tuples-as-arguments is that when I 
>>> define:
>>> `func foo(_ arg0: Any, _ arg1: Any) {}`
>>> I can afterwards “apply” a tuple to a function named `foo` and therefore 
>>> execute the function on this tuple.
>>> Calling a function syntax was equivalent to put a tuple next to a function 
>>> name:
>>> `foo(42, “hello")` the left-hand is `foo`, the right-hand is `(42, 
>>> “hello")` is the tuple.
>>> 
>>> The same way if I have
>>> `func foo()`
>>> `foo()` means calling `foo` with argument `()` and there we have our 
>>> original `Void`
>>> 
>>> That meaning changed recently due to multiple SE implementations actually.
>>> 
>>> Tuples-as-arguments never shipped in any version of Swift, and the ability 
>>> to "apply" a tuple like that was removed by SE-0029--the original goal was 
>>> to implement this change in time for Swift 2.2.
>>>  
>>> The parenthesis around the call don't have a tuple meaning anymore. 
>>> Therefore it breaks a lot of code relying on this feature of the language, 
>>> which was quite elegant, but could not handle advanced functions features.
>>> 
>>> Yes, this is an intentional and approved part of SE-0029. The drawbacks 
>>> were 

Re: [swift-evolution] History and future of Swift's parentheses

2017-06-09 Thread Gwendal Roué via swift-evolution

> Le 9 juin 2017 à 17:12, Gor Gyolchanyan via swift-evolution 
>  a écrit :
> 
>> 
>> So I wonder if any of you have had any thoughts about what Swift's 
>> parentheses-related future (or evolutionary baggage) will be?
>> 
> 
> I really wish swift used the concept of tuples **exclusively** for all 
> purposes that involve parentheses, as well as dividing tuples into two 
> categories:
> - Bare tuples, which do not have labels.
> - Rich tuples, which do.
> As a consequence, here's a list of statements that would become true:
> - All functions take exactly one parameter, which is a tuple.
> - All closures (a.k.a. function pointers) take exactly one parameter, which 
> is a bare tuple.
> - All functions return exactly one parameter, which is a tuple.
> - Pattern matching is done on a single bare tuple using a single bare tuple 
> pattern.
> 
> The currently ongoing proposal to make a single-element tuple auto-flatten 
> would work extremely well with this idea, by making all these changes 
> completely backward-compatible.

If I have well understood, Swift has evolved away from this.

If what you describe were true, added to the fact that there is no such thing 
as a one-element tuple in the language, then (A,B) -> C and ((A, B)) -> C could 
not be distinguished, for the simple reason that ((A, B)) -> C could not be 
defined.

For ((A, B)) -> C to be defined, we'd need a function that takes exactly one 
parameter, which is a tuple (your idea), whose single element is a tuple (oops, 
there is no single-valued tuples).

No opinion here, just they way I have understood recent Swift history.
Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-09 Thread Gwendal Roué via swift-evolution
> Le 9 juin 2017 à 10:07, Mark Lacey  a écrit :
> 
> I’m not trying to argue that it’s impossible to do. I don’t think it’s a good 
> idea at all. That’s subjective. Me saying “that really should be an error” is 
> a subjective statement. I don’t have to say “This is a subjective statement” 
> to make a subjective statement.

Yes, sorry: It's so easy to sound assertive even when we just want to share and 
communicate opinions.

>> I *do* suggest a specific handling of { _ ... }. I have shown how it can be 
>> implemented in a non-ambiguous fashion. 
> 
> Your own comment says this should be considered ambiguous. It’s unambiguous 
> now. What I am asking is how is that an improvement?

I suggest { _ in ... } is ambiguous only in case of function overloading. In 
this case, you have { (_) in ... } and { (_,_) in ... } for disambiguation:

func overloaded(_ closure: (Int, Int) -> Int) -> String { return 
"overloaded 1" }
func overloaded(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { 
return "overloaded 2" }
overloaded { _ in 1 }  // error: ambiguous use of ‘overloaded'
overloaded { (_) in 1 }// "overloaded 1”
overloaded { (_, _) in 1 } // "overloaded 2”

When a function is not overloaded, then { _ in ... } would always mean "I don't 
care", and is always accepted except for closures that take no argument at all:

func f1(_ closure: () -> Int) -> String { return "f1" }
func f2(_ closure: (Int) -> Int) -> String { return "f2" }
func f3(_ closure: (Int, Int) -> Int) -> String { return "f3" }
func f4(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { return "f4" }

f1 { _ in 1 }  // error

f2 { _ in 1 }  // OK, you don't care

f3 { _ in 1 }  // OK, you don't care
f3 { (_, _) in 1 } // OK, just what I expected!

f4 { _ in 1 }  // OK, you don't care
f4 { (_) in 1 }// OK, just what I expected!
f4 { (_, _) in 1 } // OK, maybe you use tuple splatting somewhere else and 
want to be consistent

All this is *possible*. And I don't see how it breaks anything. On the other 
side, it eases everyday life, reduces clutter, and avoids useless punctuation.
Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-09 Thread Gwendal Roué via swift-evolution

> Le 9 juin 2017 à 09:41, Mark Lacey  a écrit :
> 
> 
>> On Jun 9, 2017, at 12:12 AM, Gwendal Roué > > wrote:
>> 
 func notOverloaded1(_ closure: (Int, Int) -> Int) -> String { return 
 "notOverloaded1" }
 func notOverloaded2(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> 
 String { return "notOverloaded3" }
 
 func overloaded(_ closure: (Int, Int) -> Int) -> String { return 
 "overloaded 1" }
 func overloaded(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { 
 return "overloaded 2" }
 
 // not overloaded => not ambiguous
 notOverloaded1 { x, y in x + y }
 notOverloaded1 { (x, y) in x + y }
 notOverloaded1 { _ in 1 }
 notOverloaded2 { x, y in x + y }
 notOverloaded2 { (x, y) in x + y }
 notOverloaded2 { _ in 1 }
 
 // overloaded => resolve ambiguity on closure argument, when possible
 overloaded { x, y in x + y }// "overloaded 1"
 overloaded { (x, y) in x + y }  // "overloaded 1"
 overloaded { t in t.lhs + t.rhs }   // "overloaded 2"
 overloaded { (t) in t.lhs + t.rhs } // "overloaded 2”
>>> 
>>> This is exactly what happens today as a result of SE-0110 since the first 
>>> two calls take two arguments, and the next two take a single argument.
>> 
>> No, as a playground quickly reveals:
> 
> I was specifically referring to the last four statements but could have made 
> that more clear.
> 
>> func notOverloaded1(_ closure: (Int, Int) -> Int) -> String { return 
>> "notOverloaded1" }
>> func notOverloaded2(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String 
>> { return "notOverloaded3" }
>> 
>> // not overloaded => not ambiguous
>> notOverloaded1 { x, y in x + y }
>> notOverloaded1 { (x, y) in x + y }
>> notOverloaded1 { _ in 1 }  // Swift 4 error
> 
> This really should be an error.

I argue this is a subjective statement, and my own subjective statement is that 
it should not to be an error. So that { _ in ... } would always mean "I don't 
care".

> It’s one thing to say that { x, y in } should work as it used to in the case 
> where a closure taking a tuple is expected, but something else entirely to 
> say that _ should work in any case, regardless of whether a closure taking N 
> arguments or a closure taking an N-tuple is expected for any N. I can see a 
> desire to make _ work for any tuple, and _, _ work for a two-tuple based on 
> context if e.g. “x, y in” also works, but not for _ working where a closure 
> requiring N independent arguments is expected.

Yes. That's why it's subjective. You argue that you don't like it, not that 
it's impossible to do. Because you can't prove it's impossible to do. Because I 
have shown that it is. In a nice manner that is easy to developers.

> 
>> notOverloaded2 { x, y in x + y }   // Swift 4 error
>> notOverloaded2 { (x, y) in x + y } // Swift 4 error
> 
> In these cases using the tuple labels works as well (as it does in your 
> examples where the overloaded function is involved). I’m not arguing that 
> it’s as good as being able to do the apparent destructuring, but just want to 
> point out that it works. I didn’t get the sense from your email that you 
> found that objectionable in the cases involving overloads, but perhaps you do.
> 
>> notOverloaded2 { _ in 1 }
>> 
>> Those errors are the famous regressions we want to fix.
>> 
 overloaded { _ in 1 }   // error: ambiguous use of 
 ‘overloaded'
>>> 
>>> With SE-0110 in its current form, this calls the tuple version since there 
>>> is a single closure parameter listed.
>> 
>> It would be nicer if. { _ in ... } would always mean "I don't care". With an 
>> ambiguity in the sample code we're looking at, and a compiler error.
> 
> How does making something that is unambiguous today actually be ambiguous 
> improve things?

I *do* suggest a specific handling of { _ ... }. I have shown how it can be 
implemented in a non-ambiguous fashion. Please don't act as if I did not.

Now the specific case of { _ ... } is interesting, but I wouldn't make it as 
important as the other regressions.

I should make an exhaustive compilation of Swift 4 regressions, so that you 
opponents can see how *far* things have changed, fixing a few corner cases, and 
breaking tons of valid code. At least we could discuss each case in isolation.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-09 Thread Gwendal Roué via swift-evolution
>> func notOverloaded1(_ closure: (Int, Int) -> Int) -> String { return 
>> "notOverloaded1" }
>> func notOverloaded2(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String 
>> { return "notOverloaded3" }
>> 
>> func overloaded(_ closure: (Int, Int) -> Int) -> String { return 
>> "overloaded 1" }
>> func overloaded(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { 
>> return "overloaded 2" }
>> 
>> // not overloaded => not ambiguous
>> notOverloaded1 { x, y in x + y }
>> notOverloaded1 { (x, y) in x + y }
>> notOverloaded1 { _ in 1 }
>> notOverloaded2 { x, y in x + y }
>> notOverloaded2 { (x, y) in x + y }
>> notOverloaded2 { _ in 1 }
>> 
>> // overloaded => resolve ambiguity on closure argument, when possible
>> overloaded { x, y in x + y }// "overloaded 1"
>> overloaded { (x, y) in x + y }  // "overloaded 1"
>> overloaded { t in t.lhs + t.rhs }   // "overloaded 2"
>> overloaded { (t) in t.lhs + t.rhs } // "overloaded 2”
> 
> This is exactly what happens today as a result of SE-0110 since the first two 
> calls take two arguments, and the next two take a single argument.

No, as a playground quickly reveals:

func notOverloaded1(_ closure: (Int, Int) -> Int) -> String { return 
"notOverloaded1" }
func notOverloaded2(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { 
return "notOverloaded3" }

// not overloaded => not ambiguous
notOverloaded1 { x, y in x + y }
notOverloaded1 { (x, y) in x + y }
notOverloaded1 { _ in 1 }  // Swift 4 error
notOverloaded2 { x, y in x + y }   // Swift 4 error
notOverloaded2 { (x, y) in x + y } // Swift 4 error
notOverloaded2 { _ in 1 }

Those errors are the famous regressions we want to fix.

>> overloaded { _ in 1 }   // error: ambiguous use of 
>> ‘overloaded'
> 
> With SE-0110 in its current form, this calls the tuple version since there is 
> a single closure parameter listed.

It would be nicer if. { _ in ... } would always mean "I don't care". With an 
ambiguity in the sample code we're looking at, and a compiler error.

The { (_, _) in ... } form is arguably cluttered, and it would be nicer it is 
was required only for disambiguition.

>> overloaded { (_) in 1 } // "overloaded 1”
> 
> With SE-0110 in its current form, this calls the tuple version since there is 
> a single closure parameter listed. I don’t understand why you would suggest 
> this should call the two-argument version since that’s inconsistent with the 
> other closures above that have a single argument.
> 
>> overloaded { (_, _) in 1 }  // "overloaded 2”
> 
> With SE-0110 in its current form, this calls the two-argument version since 
> there are two listed arguments.

I was wrong, sorry. I meant what you replied.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-09 Thread Gwendal Roué via swift-evolution

> Le 9 juin 2017 à 07:56, Vladimir.S via swift-evolution 
>  a écrit :
> 
> Yes, we are discussing the *potential* solutions for Swift 4 that can 
> decrease the pain of migration of *some* Swift3 code, given (Int,Int)->() and 
> ((Int,Int))->() are different types in Swift 4.
> 
> But, as was said by Mark Lacey in this thread later, there is an "overload" 
> problem for such solution, when closure of kind {x, y in ..} can be sent to 
> overloaded func like here:
> 
> func overloaded(_ fn: (Int, Int) -> Int) { fn(1,2) }
> func overloaded(_ fn: ((Int, Int)) -> Int) { fn((3,4)) }
> 
> overloaded { x, y in x + y }
> overloaded { (x, y) in x + y }
> 
> Compiler is not able to determinate which type of closure do you want in each 
> case. For ((Int,Int))->Int you still need some 'specific' syntax which 
> disambiguate the call. So we *still* need some good syntax to destructure 
> tuple argument in closure to use in place of ((Int,Int))->Int closure.
> 
> This means that there is no sense to allow very 'magic' {x,y in ..} syntax 
> and compiler-detected type of closure if we still need good syntax 
> for destructuring tuple argument in ((Int,Int))->().

Yes, Mark was very right asking about overloads. But is it a problem that does 
not have a solution which preserves ergonomics?

func notOverloaded1(_ closure: (Int, Int) -> Int) -> String { return 
"notOverloaded1" }
func notOverloaded2(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { 
return "notOverloaded3" }

func overloaded(_ closure: (Int, Int) -> Int) -> String { return 
"overloaded 1" }
func overloaded(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { 
return "overloaded 2" }

// not overloaded => not ambiguous
notOverloaded1 { x, y in x + y }
notOverloaded1 { (x, y) in x + y }
notOverloaded1 { _ in 1 }
notOverloaded2 { x, y in x + y }
notOverloaded2 { (x, y) in x + y }
notOverloaded2 { _ in 1 }

// overloaded => resolve ambiguity on closure argument, when possible
overloaded { x, y in x + y }// "overloaded 1"
overloaded { (x, y) in x + y }  // "overloaded 1"
overloaded { t in t.lhs + t.rhs }   // "overloaded 2"
overloaded { (t) in t.lhs + t.rhs } // "overloaded 2"
overloaded { _ in 1 }   // error: ambiguous use of 'overloaded'
overloaded { (_) in 1 } // "overloaded 1"
overloaded { (_, _) in 1 }  // "overloaded 2"

See the error on `overloaded { _ in 1 }`, because _ means "I don't care". Well, 
here you have to care because of overloading. Ambiguity is resolved with 
parenthesis. This is a specific behavior for `_`.

Gwendal

---

PS, I had a little look at how Swift 3 currently behave with overloading ? 
Badly, actually:

// SWIFT 3

func f(_ closure: (Int, Int) -> Int) -> String { return "two arguments" }
// error: invalid redeclaration of 'f'
// func f(_ closure: ((Int, Int)) -> Int) -> String { return "one anonymous 
tuple argument" }
func f(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { return "one 
named tuple argument" }

// error: ambiguous use of 'f'
// f { x, y in x + y }

f { t in t.rhs + t.lhs } // "one named tuple argument"

// error: ambiguous use of 'f'
// f { t in t.0 + t.1 } // "one named tuple argument"

// error: ambiguous use of 'f'
let c = { (a: Int, b: Int) -> Int in a + b }
type(of: c) // ((Int, Int) -> Int).Type
// error: ambiguous use of 'f'
// f(c)

Swift 3 does not allow overloading ((Int, Int)) -> Int and (Int, Int) -> Int, 
but allows overloading ((lhs: Int, rhs: Int)) -> Int and (Int, Int) -> Int.

Yet I could never call the (Int, Int) -> Int version, even when I provide with 
a function that exactly matches its signature. And there are much too many 
ambiguous situations the compiler can't deal with.

So yes, there is a problem with Swift 3.

How is it with Swift 4 (2017-06-02 snapshot)?

// SWIFT 4

func f(_ closure: (Int, Int) -> Int) -> String { return "two arguments" }
// error: invalid redeclaration of 'f'
// func f(_ closure: ((Int, Int)) -> Int) -> String { return "one anonymous 
tuple argument" }
func f(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { return "one 
named tuple argument" }

f { x, y in x + y }  // "two arguments"
f { t in t.rhs + t.lhs } // "one named tuple argument"
f { t in t.0 + t.1 } // "one named tuple argument"

let c = { (a: Int, b: Int) -> Int in a + b }
type(of: c)  // ((Int, Int) -> Int).Type
f(c) // "two arguments"

Much better.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-08 Thread Gwendal Roué via swift-evolution

> Le 8 juin 2017 à 19:40, Brent Royal-Gordon via swift-evolution 
>  a écrit :
> 
>> On Jun 7, 2017, at 3:03 AM, Adrian Zubarev via swift-evolution 
>> > wrote:
>> 
>> Well please no:
>> 
>> 
>>  let fn2: ((Int, Int)) -> Void = { lhs, rhs in } 
>> 
>> Instead use destructuring sugar pitched by Chris Lattner on the other thread:
>> 
>> let fn2: ((Int, Int)) -> Void = { ((lhs, rhs)) in }
>> 
> 
> I think this suggestion is better than the status quo. I'm wondering, though, 
> if we should just drop the outer set of parentheses entirely, unless you're 
> also putting types on the parameters. That is, a closure of type `(Int, Int) 
> -> T` can look like this:
> 
>   { (x: Int, y: Int) in … }
> 
> Or it can look like this:
> 
>   { x, y in … }
> 
> But it *cannot* look like this:
> 
>   { (x, y) in … }
> 
> The `(x, y)` form can instead be a closure of a type like `((Int, Int)) -> 
> T`, which immediately destructures the tuple parameter into separate 
> constants.

I better understand your message. It does look good at first sight.

But... The full picture needs to be completed with closures of type `((Int, 
Int)) -> T` and `((lsh: Int, rhs: Int)) -> T`. Those are among the most 
*interesting* in the regressions they brought.

Will there be any forbidden syntax as well? What about unfitted signatures, 
which I talked just before?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-08 Thread Gwendal Roué via swift-evolution

> Le 8 juin 2017 à 20:17, Gwendal Roué  a écrit :
> 
> This gives us the ability to deal with unfitted function signatures. For 
> example, most Dictionary methods. Yes, they are usually unfitted:
> 
> extension Dictionary {
> func forEach(_ body: ((key: Key, value: Value)) throws -> Void) 
> rethrows
> }
> 
> Who cares about this named (key:value:) tuple? Absolutely nobody, as 
> exemplified by this remarquable Swift 3 snippet below, where no tuple, no 
> `key`, and no `value` is in sight:
> 
> let scores: [String: Int] = ... // [playerName: score]
> scores.forEach { name, score in
> print("\(name): \(score)")
> }
> 
> Do you see?

I regret my "Absolutely nobody" snippet. Some people like the `key` and `value` 
identifiers.

Those people are the people who write the standard library, people who write 
blog posts about Swift novelties, and people who write experimental software 
around Swift. All very valuable people.

There are other kinds of developers, who don't really care about the beauty of 
dictionary design and implementation. They just want a container that does what 
it's supposed to do: map stuff to other stuff. Not keys to values.

To them, a dictionary is like a screwdriver: when you use it, you don't want to 
think about it much.

And the recent changes force us to see uninteresting implementation details 
that obscure everyday code.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-08 Thread Gwendal Roué via swift-evolution

> Le 8 juin 2017 à 19:40, Brent Royal-Gordon via swift-evolution 
>  a écrit :
> 
>> On Jun 7, 2017, at 3:03 AM, Adrian Zubarev via swift-evolution 
>> > wrote:
>> 
>> Well please no:
>> 
>> 
>>  let fn2: ((Int, Int)) -> Void = { lhs, rhs in } 
>> 
>> Instead use destructuring sugar pitched by Chris Lattner on the other thread:
>> 
>> let fn2: ((Int, Int)) -> Void = { ((lhs, rhs)) in }
>> 
> 
> I think this suggestion is better than the status quo. I'm wondering, though, 
> if we should just drop the outer set of parentheses entirely, unless you're 
> also putting types on the parameters. That is, a closure of type `(Int, Int) 
> -> T` can look like this:
> 
>   { (x: Int, y: Int) in … }
> 
> Or it can look like this:
> 
>   { x, y in … }
> 
> But it *cannot* look like this:
> 
>   { (x, y) in … }
> 
> The `(x, y)` form can instead be a closure of a type like `((Int, Int)) -> 
> T`, which immediately destructures the tuple parameter into separate 
> constants.
> 
> -- 
> Brent Royal-Gordon
> Architechies

Hello,

There's a difference, in the mind of people here that try to show how bad were 
the recent changes, between:

1: closures defined independently
2: closures given as a parameter to a function.

I think that we all agree that the type of a closure that is defined 
independently should be well defined:

// Choose between (Int, Int) -> () or ((x: Int, y: Int)) -> ()
let a = { (x: Int, y: Int) -> Int in ... }
let b = { ((x: Int, y: Int)) -> Int in ... }

However, when a closure is given as an argument of a function that expects a 
closure, we ask for the maximum possible flexibility, as Swift 3 did:

func wantsTwoArguments(_ closure: (Int, Int) -> Int) { closure(1, 2) }
wantsTwoArguments { a, b in a + b }
wantsTwoArguments { (a, b) in a + b }
wantsTwoArguments { t in t.0 + t.1 } // OK, maybe not

func wantsATupleArgument(_ closure: ((Int, Int)) -> Int) { closure((1, 2)) }
wantsATupleArgument { a, b in a + b }
wantsATupleArgument { (a, b) in a + b }
wantsATupleArgument { t in t.0 + t.1 }

func wantsANamedTupleArgument(_ closure: ((lhs: Int, rhs: Int)) -> Int) { 
closure((lhs: 1, rhs: 2)) }
wantsANamedTupleArgument { a, b in a + b }
wantsANamedTupleArgument { (a, b) in a + b }
wantsANamedTupleArgument { t in t.lhs + t.rhs }

This gives us the ability to deal with unfitted function signatures. For 
example, most Dictionary methods. Yes, they are usually unfitted:

extension Dictionary {
func forEach(_ body: ((key: Key, value: Value)) throws -> Void) rethrows
}

Who cares about this named (key:value:) tuple? Absolutely nobody, as 
exemplified by this remarquable Swift 3 snippet below, where no tuple, no 
`key`, and no `value` is in sight:

let scores: [String: Int] = ... // [playerName: score]
scores.forEach { name, score in
print("\(name): \(score)")
}

Do you see?

Gwendal


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Possible issue with SE-0166 Swift Archival & Serialization implementation

2017-06-08 Thread Gwendal Roué via swift-evolution

> On Jun 8, 2017, at 9:45 AM, Itai Ferber <ifer...@apple.com 
> <mailto:ifer...@apple.com>> wrote:
> 
> Hi Gwendal,
> 
>> On Jun 8, 2017, at 8:27 AM, Gwendal Roué via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>>> 
>>> Le 8 juin 2017 à 16:51, James Froggatt via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>> 
>>> I've just been trying out the new Coding protocol, and was rather surprised 
>>> when trying to implement the `encode(to encoder: Encoder)` method.
>>> 
>>> The Swift evolution proposal provides the following example code:
>>> 
>>>   public func encode(to encoder: Encoder) throws {
>>>   // Generic keyed encoder gives type-safe key access: cannot encode 
>>> with keys of the wrong type.
>>>   let container = encoder.container(keyedBy: CodingKeys.self)
>>> 
>>>   // The encoder is generic on the key -- free key autocompletion here.
>>>   try container.encode(latitude, forKey: .latitude)
>>>   try container.encode(longitude, forKey: .longitude)
>>>   }
>>> 
>>> 
>>> Here, container is stored as a `let` value, and uses reference semantics, 
>>> while the proposal also clearly lists these `encode` methods as mutating. 
>>> With the current implementation of the proposal, the container must be 
>>> stored as a `var`, which leads to code like the following:
>>> 
>>>   var container = encoder.singleValueContainer()
>>>   try container.encode(data)
>> 
>> Yes, practically speaking and with latest Swift 4, the container needs to be 
>> declared as `var`.
>> 
>> I admit it's weird, and feels unnatural:
>> 
>>   public func encode(to encoder: Encoder) throws {
>>   // A mutated value that nobody consumes: so weird.
>>   var container = encoder.container(keyedBy: CodingKeys.self)
>>   try container.encode(latitude, forKey: .latitude)
>>   try container.encode(longitude, forKey: .longitude)
>>   }
> Why? It’s perfectly reasonable for the container to maintain some internal 
> state as it’s encoding. It shouldn’t have to sacrifice value semantics for 
> that.

No big trouble, Itai: just that a value type is usually mutated before being 
used elsewhere.

Take this code snippet for example:

var a = [1]
a.append(2)
// if a is not used any longer, something is wrong, don't you agree?

And now this other one:

var x = SomeValueType()
x.append(2)
// why would it be different for x?

One of the *possible* interpretations of value types is that they are (or look 
like, if you prefer) purely local, and without side effect.

I know that values can hold references and vice-versa, and that the exact 
distinction between value and reference types is thin, even generally in the 
hand of the library developer: one can expose a reference type that behaves 
like a value type, and one can write a value type that obviously hides some 
references (like the containers above).

That's all. No big deal, really.
Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Possible issue with SE-0166 Swift Archival & Serialization implementation

2017-06-08 Thread Gwendal Roué via swift-evolution

> Le 8 juin 2017 à 16:51, James Froggatt via swift-evolution 
>  a écrit :
> 
> I've just been trying out the new Coding protocol, and was rather surprised 
> when trying to implement the `encode(to encoder: Encoder)` method.
> 
> The Swift evolution proposal provides the following example code:
> 
>public func encode(to encoder: Encoder) throws {
>// Generic keyed encoder gives type-safe key access: cannot encode 
> with keys of the wrong type.
>let container = encoder.container(keyedBy: CodingKeys.self)
> 
>// The encoder is generic on the key -- free key autocompletion here.
>try container.encode(latitude, forKey: .latitude)
>try container.encode(longitude, forKey: .longitude)
>}
> 
> 
> Here, container is stored as a `let` value, and uses reference semantics, 
> while the proposal also clearly lists these `encode` methods as mutating. 
> With the current implementation of the proposal, the container must be stored 
> as a `var`, which leads to code like the following:
> 
>var container = encoder.singleValueContainer()
>try container.encode(data)

Yes, practically speaking and with latest Swift 4, the container needs to be 
declared as `var`.

I admit it's weird, and feels unnatural:

   public func encode(to encoder: Encoder) throws {
   // A mutated value that nobody consumes: so weird.
   var container = encoder.container(keyedBy: CodingKeys.self)
   try container.encode(latitude, forKey: .latitude)
   try container.encode(longitude, forKey: .longitude)
   }

> This clearly wont work as expected if the container were to have value 
> semantics, and writing code like this feels plain wrong. Is SE-0166 really 
> intended to work with referrence-type encoders only?

Actually, it can work with encoder/containers that have value semantics, and 
forward the mutations somewhere else (for example to a closure which fills a 
mutating container).

But this is again bizarre, and contrieved: 
https://github.com/groue/GRDB.swift/blob/15bfe5f6cf76070cfb17216223bdebc6b158d654/GRDB/Record/Persistable%2BEncodable.swift

You make me think that those structs should swiftly be refactored into 
reference types.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution
> Le 8 juin 2017 à 05:15, Susan Cheng via swift-evolution 
>  a écrit :
> 
> Just a thought
> 
> if parentheses is important, why the tuples are not?
> 
> var tuple1: (Int, Int) = (0, 0)
> var tuple2: Int, Int = (0, 0)
> 
> type(of: tuple1) == type(of: tuple2)// true
> 
> var void: ((())) = ()
> 
> type(of: void) == type(of: Void())  // true

I think is is because Swift doesn't have tuples with a single value: those 
parenthesis are just parenthesis around an expression:

let a = 1 + 2
let b = (1 + 2)
let c = (1 + 2) * 3
let d = ((1 + 2)) * 3

Many languages behave like that, Swift is no exception.

It also allows some fancy/legacy/foreign programming styles :-)

// C-style if
if (a && b) {
...
}
// "return function"
return(a && b)

Languages that have single-valued tuples need a special syntax so that they are 
distinguished from parenthesised expressions. In Python, this is a trailing 
comma:

1# 1
(1)  # 1
(1,) # (1,)

Swift currently disallows trailing commas inside parenthesis.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 20:33, Gwendal Roué  a écrit :
> 
> For example, take those three functions:
> 
>   func f(_ closure:(Int, Int) -> ())
>   func g(_ closure:((Int, Int)) -> ())
>   func h(_ closure:((a: Int, b: Int)) -> ())
> 
> If one can always write (as in Swift 3):
> 
>   f { (a, b) in ... }
>   g { (a, b) in ... }
>   c { (a, b) in ... }
> 
> Then one can easily deal with a badly fit closure signature.
> 
> This is most examplified by dictionaries. They always expose (key: Key, 
> value: Value) tuples (their Element type). Problem is that 'key' and 'value' 
> are identifiers that only matter for dictionaries, not for dictionary users. 
> It's very important for dictionary users to forget about tuples, and the 
> `key` and `value` words:
> 
>   // No pollution
>   dictionary.map { (name, score) in ... }

It looks like some people in this mailing list are horrified by this "request" 
(not a feature request, but a request that Swift 3 behavior is restored, 
actually).

What could be the reasons for such a bad reaction?

1: measurable runtime overhead (slower programs in some cases, without any 
obvious way for the developper to notice where is the extra cost)
2: measurable compiler overhead (slower compilation)
3: implementation complexity (slower swift progress, technical debt, etc.)
4: other?

I understand 1. We are all fascinated by C++ and Rust "zero-overhead". If this 
is the main concern of the community, then we may focus the discussion of that 
very precise topic.

I can live with 2 (just a personal subjective preference)

About 3: I can not tell because I lack the necessary skills.

4: enlighten us!

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 17:15, Vladimir.S  a écrit :
> 
> On 07.06.2017 16:20, Gwendal Roué wrote:
>>> Le 7 juin 2017 à 15:11, Xiaodi Wu >> > a écrit :
>>> 
>>> While SE-0025 was generally regarded as unfortunate, the thousands of 
>>> emails that followed relitigating it were much, much worse.
>>> 
>>> The removal of implicit tuple splatting, which is *not* SE-0110, was 
>>> approved on the understanding that it would be a regression until explicit 
>>> tuple splatting is introduced. This tradeoff was considered and approved. 
>>> It’s clear that you disagree, but that is not grounds to divert a necessary 
>>> discussion on mitigating SE-0110 into relitigating something else.
>> Push me out if you want, but will you push out those blatant wounds out as 
>> well?
>> Example 1
>> -return columns.index { (column, _) in column.lowercased() == 
>> lowercaseName }
>> +return columns.index { $0.0.lowercased() == lowercaseName }
> 
> Why not
> columns.index { (arg: (column: String, _: Int)) in arg.column.lowercased() == 
> lowercaseName }
> ?

It would works, but it's less than ideal: the `args` name has no meaning. We 
have an extra type declaration instead of type inference. It's much longer. The 
clarity is tremendously reduced.

- return columns.index { (column, _) in column.lowercased() == lowercaseName }
+ return columns.index { (arg: (column: String, _)) in arg.column.lowercased() 
== lowercaseName }

> Yes, I understand that first syntax short and not verbose, but the 
> alternative you provided IMHO much worse than explicit type declaration in 
> closure.

It's not an "alternative": it's Swift 3.

Maybe you did already profit from it, but did not notice.

> 
>> Example 2 :
>> -.map { (mappedColumn, baseColumn) -> (Int, String) in
>> +.map { (pair) -> (Int, String) in
>> +let mappedColumn = pair.key
>> +let baseColumn = pair.value
> 
> Can't compile something like this even in Swift 3, could you provide a small 
> code snippet for this?

Sure:

let mapping: [String: String] = ...
mapping.map { (mappedColumn, baseColumn) -> (Int, String) in ... }

>> Example 3 :
>> -.map { (table, columns) in 
>> "\(table)(\(columns.sorted().joined(separator: ", ")))" }
>> +.map { "\($0.key)(\($0.value.sorted().joined(separator: ", 
>> ")))" }
> 
> Same, why not
> 
> .map { (arg: (table: String, columns: [String])) in 
> "\(arg.table)(\(arg.columns.sorted().joined(separator: ", ")))" }

Same answer: the extra `args` works, but we still have an ergonomics regression 
from Swift 3.

>> Example 4 :
>> -dictionary.first { (column, value) in column.lowercased() 
>> == orderedColumn.lowercased() }
>> +dictionary.first { $0.key.lowercased() == 
>> orderedColumn.lowercased() }
> 
> Same.

Indeed.

> 
>> See also messages from Stephen Cellis, who shows how other kinds of 
>> developer code has lost expressivity and clarity with those changes that 
>> have been "considered and approved".
> 
> Gwendal, no one saying that new syntax is better, that it is good thing that 
> we lost the short syntax for tuple argumment deconstructions in closures.

Good to hear :-)

> But there is just no easy/obvious way to keep that syntax in Swift 4. The 
> problem can't be solved just by not implementing SE-0110, as in Swift4 we 
> should have two separate function types: one that takes single tuple argument 
> and second that accepts a list of arguments, i.e. (Int,Int)->() and 
> ((Int,Int))->() should be two different types now.

Of course I understand that.

I expect the compiler to perform the expected conversions for ergonomics' sake.

I can understand that this sugar could be added *after* current problems which 
are not related to ergonomics are solved. I just want to make it clear that 
there is an ergonomics problem *now*, and that solving it should have a very 
high priority.

> This is not just SE-0110, this is also SE-0066, so, to be correct, you should 
> propose to revisit it also.
> 
> Please look here:
> 
> func foo(_ x: Int, _ y: Int) {} // type(of: foo) should be (Int, Int)->()
> func bar(_ x (Int, Int)) {} // type(of: bar) should be ((Int, Int))->()
> 
> The above is described in SE-0066. Then, you have a closure constants:
> 
> var fooClosure = {(x: Int, y: Int) in }
> var barClosure = {(x: (Int, Int)) in }
> 
> what should be types of these closures? Obvious the same: (Int,Int)->() and 
> ((Int,Int))->() respectively.

I guess you mean, not the same: (Int, Int) -> () vs. ((Int, Int)) -> ().

> Then you have a func that accepts ((Int,Int))->Int closure:
> 
> func schedule(callback: ((Int,Int))->()) {..}
> 
> , given type of foo func is (Int, Int)->() , do you suggest to allow sending 
> foo to 'schedule' func? The same question is for fooClosure
> 
> schedule(callback: foo) // ??
> schedule(callback: fooClosure) // ??

Yes, 

Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 15:52, Xiaodi Wu  a écrit :
> 
> Let’s clarify: you just wrote that you have problems with SE-0029, SE-0066, 
> SE-0110, and “before,” did you not?

WTF? No I did not (citation below)!

> Le 7 juin 2017 à 15:02, Gwendal Roué  a écrit :
> 
>> Le 7 juin 2017 à 14:42, Vladimir.S > > a écrit :
>> 
>> Gwendal, again, you are proposing to revert not just SE-0110 and SE-0066 but 
>> mainly SE-0029 "Remove implicit tuple splat behavior from function 
>> applications"
>> (https://github.com/apple/swift-evolution/blob/master/proposals/0029-remove-implicit-tuple-splat.md
>>  
>> )
> 
> Do you mean that the regressions Stephen and I have shown have been 
> introduced not only by SE-0110, but before SE-0066, and SE-0029?

Your attitude is obnoxious. Enough Swift evolution for me today.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 15:28, Xiaodi Wu  a écrit :
> 
> These *are* changes related to SE-0110, and Chris and others have already 
> proposed possibilities for sugar that could make this better. That’s exactly 
> the discussion that was originally started, to be distinguished from the 
> alternative in which you and others are proposing reversing 5 or 6 other 
> proposals.

That's wrong.

"I and others" have always been after ergonomics regressions, not "reversing 5 
or 6 other proposals" (how dare you???)

Gw

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 15:11, Xiaodi Wu  a écrit :
> 
> While SE-0025 was generally regarded as unfortunate, the thousands of emails 
> that followed relitigating it were much, much worse.
> 
> The removal of implicit tuple splatting, which is *not* SE-0110, was approved 
> on the understanding that it would be a regression until explicit tuple 
> splatting is introduced. This tradeoff was considered and approved. It’s 
> clear that you disagree, but that is not grounds to divert a necessary 
> discussion on mitigating SE-0110 into relitigating something else.

Push me out if you want, but will you push out those blatant wounds out as well?

Example 1
-return columns.index { (column, _) in column.lowercased() == 
lowercaseName }
+return columns.index { $0.0.lowercased() == lowercaseName }

Example 2 :
-.map { (mappedColumn, baseColumn) -> (Int, String) in
+.map { (pair) -> (Int, String) in
+let mappedColumn = pair.key
+let baseColumn = pair.value

Example 3 :
-.map { (table, columns) in 
"\(table)(\(columns.sorted().joined(separator: ", ")))" }
+.map { "\($0.key)(\($0.value.sorted().joined(separator: ", 
")))" }

Example 4 :
-dictionary.first { (column, value) in column.lowercased() == 
orderedColumn.lowercased() }
+dictionary.first { $0.key.lowercased() == 
orderedColumn.lowercased() }

See also messages from Stephen Cellis, who shows how other kinds of developer 
code has lost expressivity and clarity with those changes that have been 
"considered and approved".

Cheers,
Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 14:42, Vladimir.S <sva...@gmail.com> a écrit :
> 
> On 07.06.2017 14:18, Gwendal Roué via swift-evolution wrote:
>> Xiaodi, Adrian, you are actively pushing so that something that was allowed, 
>> well compiled (no runtime issue), and covered actual uses cases, becomes 
>> forbidden. Without any developer advantage that would somehow balance the 
>> change.
>> That's called a regression.
>> And what's the rationale, already? A sense of compiler aesthetics? Since 
>> when a sense of compiler aesthetics is more valuable than a sense of code 
>> aesthetics? Aren't both supposed to walk together as a pair?
> 
> Gwendal, again, you are proposing to revert not just SE-0110 and SE-0066 but 
> mainly SE-0029 "Remove implicit tuple splat behavior from function 
> applications"
> (https://github.com/apple/swift-evolution/blob/master/proposals/0029-remove-implicit-tuple-splat.md
>  
> <https://github.com/apple/swift-evolution/blob/master/proposals/0029-remove-implicit-tuple-splat.md>)

Do you mean that the regressions Stephen and I have shown have been introduced 
not only by SE-0110, but before SE-0066, and SE-0029?

> We can discuss what sugar we can have to have tuple destructuring in closure 
> and probably some sugar to allow free function of list of arguments when 
> function of one tuple is required. But I don't see how we can revisit(and I 
> believe we shouldn't) a number of actively discussed(!) and accepted 
> proposals and dramatically change direction of Swift evolution even because 
> of "lacks in terms of user ergonomics" for some period.

I don't know. Nobody seemed to care about regressions, so I felt like it was 
high time some light was shed on them.

> Btw, please also note that this will not be possible in Swift 4:
> Probably this "feature" also was used in Swift 3 code, do we need to revisit 
> it also? (I believe no)

Writing "feature" with ironic quotes is a bad attitude. Some "features" are the 
quality of life of developers.

When proposals are accepted without user feedback, it's reasonable to expect 
that users come back after the harm has been done. It has happened before, for 
fileprivate (SE-0025). This is the case now. Some real bad harm to the language 
ergonomics has been done.

Again, I'm not talking about inner compiler design: feel free to do whatever is 
reasonable for Swift and the community. But regressions.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 13:28, Adrian Zubarev  a 
> écrit :
> 
>> Xiaodi, Adrian, you are actively pushing so that something that was allowed, 
>> well compiled (no runtime issue), and covered actual uses cases, becomes 
>> forbidden. Without any developer advantage that would somehow balance the 
>> change.
>> 
>> That's called a regression.
> 
> 
> func foo(_: (Int, Int)) {}
> func bar(_: Int, _: Int) {}
> 
> type(of: foo) == type(of: bar) //=> true - It's a BUG!

Then please push for the bug to be fixed. You are much better than am I at 
that. This does not mean breaking Swift 3 ergonomics.

The bug you mention involves type comparison, which is nowhere to be seen in 
the Swift 3 ergonomics checklist below. I'm sure we can all be happy.

func sum1(_ lhs: Int, _ rhs: Int) -> Int { return lhs + rhs }
func sum2(lhs: Int, rhs: Int) -> Int { return lhs + rhs }
func sum3(tuple: (Int, Int)) -> Int { return tuple.0 + tuple.1 }
func sum4(tuple: (lhs: Int, rhs: Int)) -> Int { return tuple.lhs + 
tuple.rhs }

// two arguments
func f1(_ closure: (Int, Int) -> Int) { closure(1, 2) }
f1 { lhs, rhs in lhs + rhs }
f1 { (lhs, rhs) in lhs + rhs }
f1 { tuple in tuple.0 + tuple.1 }
f1 { (tuple) in tuple.0 + tuple.1 }
f1(+)
f1(sum1)
f1(sum2)
f1(sum3)
f1(sum4)

// two arguments, with documentation names
func f2(_ closure: (_ a: Int, _ b: Int) -> Int) { closure(1, 2) }
f2 { lhs, rhs in lhs + rhs }
f2 { (lhs, rhs) in lhs + rhs }
f2 { tuple in tuple.0 + tuple.1 }
f2 { (tuple) in tuple.0 + tuple.1 }
f2(+)
f2(sum1)
f2(sum2)
f2(sum3)
f2(sum4)

// one tuple argument
func f3(_ closure: ((Int, Int)) -> Int) { closure((1, 2)) }
f3 { lhs, rhs in lhs + rhs }
f3 { (lhs, rhs) in lhs + rhs }
f3 { tuple in tuple.0 + tuple.1 }
f3 { (tuple) in tuple.0 + tuple.1 }
f3(+)
f3(sum1)
f3(sum2)
f3(sum3)
f3(sum4)

// one keyed tuple argument
func f4(_ closure: ((a: Int, b: Int)) -> Int) { closure((a: 1, b: 2)) }
f4 { lhs, rhs in lhs + rhs }
f4 { (lhs, rhs) in lhs + rhs }
f4 { tuple in tuple.a + tuple.b }
f4 { (tuple) in tuple.a + tuple.b }
f4(+)
f4(sum1)
f4(sum2)
f4(sum3)
f4(sum4)

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution
Xiaodi, Adrian, you are actively pushing so that something that was allowed, 
well compiled (no runtime issue), and covered actual uses cases, becomes 
forbidden. Without any developer advantage that would somehow balance the 
change.

That's called a regression.

And what's the rationale, already? A sense of compiler aesthetics? Since when a 
sense of compiler aesthetics is more valuable than a sense of code aesthetics? 
Aren't both supposed to walk together as a pair?

Gwendal

> Le 7 juin 2017 à 12:54, Xiaodi Wu <xiaodi...@gmail.com> a écrit :
> 
> IMO, if tuples and argument lists are to be distinguished in any way, it is 
> imperative that f3(+) and f4(+), and some of your other examples, _not_ work.
> 
> After all, if a tuple is not an argument list, it should possible to have a 
> function of type ((Int, Int)) -> Int and a function of type (Int, Int) -> Int 
> share the same name (IIUC, it’s a known bug that this does not currently 
> work). Quite simply, there’s a type mismatch if you pass sum1 to f3–what 
> happens if there’s a distinct, overloaded sum1 that takes a single tuple?
> 
> Chris’s suggestion restores a syntactic convenience without touching the type 
> system. What you are arguing for is essentially making ((Int, Int)) -> Int 
> and (Int, Int) -> Int synonymous again, either in some or in all contexts.
> 
> 
> On Wed, Jun 7, 2017 at 05:41 Gwendal Roué via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> Le 7 juin 2017 à 12:33, Gwendal Roué <gwendal.r...@gmail.com 
>> <mailto:gwendal.r...@gmail.com>> a écrit :
>> 
>> 
>>> Le 7 juin 2017 à 12:03, Adrian Zubarev via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>> 
>>> Well please no:
>>> 
>>> 
>>>  let fn2: ((Int, Int)) -> Void = { lhs, rhs in } 
>>> 
>>> Instead use destructuring sugar pitched by Chris Lattner on the other 
>>> thread:
>>> 
>>> let fn2: ((Int, Int)) -> Void = { ((lhs, rhs)) in }
>>> 
>> 
>> Despite Chris Lattern being a semi-god, his double-parenthesis suggestion 
>> cruelly lacks in terms of user ergonomics. The compiler should be able to 
>> deal with the following code snippet, just like Swift 3 does:
>> 
>> // two arguments
>> func f1(_ closure: (Int, Int) -> Int) { closure(1, 2) }
> 
>> [...]
> 
> Here is the full extent of the remarquable Swift 3 ergonomics. This full 
> snippet compiles in Swift 3:
> 
> func sum1(_ lhs: Int, _ rhs: Int) -> Int { return lhs + rhs }
> func sum2(lhs: Int, rhs: Int) -> Int { return lhs + rhs }
> func sum3(tuple: (Int, Int)) -> Int { return tuple.0 + tuple.1 }
> func sum4(tuple: (lhs: Int, rhs: Int)) -> Int { return tuple.lhs + 
> tuple.rhs }
> 
> // two arguments
> func f1(_ closure: (Int, Int) -> Int) { closure(1, 2) }
> f1 { lhs, rhs in lhs + rhs }
> f1 { (lhs, rhs) in lhs + rhs }
> f1 { tuple in tuple.0 + tuple.1 }
> f1 { (tuple) in tuple.0 + tuple.1 }
> f1(+)
> f1(sum1)
> f1(sum2)
> f1(sum3)
> f1(sum4)
> 
> // two arguments, with documentation names: identical
> func f2(_ closure: (_ a: Int, _ b: Int) -> Int) { closure(1, 2) }
> f2 { lhs, rhs in lhs + rhs }
> f2 { (lhs, rhs) in lhs + rhs }
> f2 { tuple in tuple.0 + tuple.1 }
> f2 { (tuple) in tuple.0 + tuple.1 }
> f2(+)
> f2(sum1)
> f2(sum2)
> f2(sum3)
> f2(sum4)
> 
> // one tuple argument
> func f3(_ closure: ((Int, Int)) -> Int) { closure((1, 2)) }
> f3 { lhs, rhs in lhs + rhs }
> f3 { (lhs, rhs) in lhs + rhs }
> f3 { tuple in tuple.0 + tuple.1 }
> f3 { (tuple) in tuple.0 + tuple.1 }
> f3(+)
> f3(sum1)
> f3(sum2)
> f3(sum3)
> f3(sum4)
> 
> // one keyed tuple argument
> func f4(_ closure: ((a: Int, b: Int)) -> Int) { closure((a: 1, b: 2)) }
> f4 { lhs, rhs in lhs + rhs }
> f4 { (lhs, rhs) in lhs + rhs }
> f4 { tuple in tuple.a + tuple.b }
> f4 { (tuple) in tuple.a + tuple.b }
> f4(+)
> f4(sum1)
> f4(sum2)
> f4(sum3)
> f4(sum4)
> 
> Gwendal
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 12:33, Gwendal Roué  a écrit :
> 
> 
>> Le 7 juin 2017 à 12:03, Adrian Zubarev via swift-evolution 
>> > a écrit :
>> 
>> Well please no:
>> 
>> 
>>  let fn2: ((Int, Int)) -> Void = { lhs, rhs in } 
>> 
>> Instead use destructuring sugar pitched by Chris Lattner on the other thread:
>> 
>> let fn2: ((Int, Int)) -> Void = { ((lhs, rhs)) in }
>> 
> 
> Despite Chris Lattern being a semi-god, his double-parenthesis suggestion 
> cruelly lacks in terms of user ergonomics. The compiler should be able to 
> deal with the following code snippet, just like Swift 3 does:
> 
> // two arguments
> func f1(_ closure: (Int, Int) -> Int) { closure(1, 2) }
> [...]

Here is the full extent of the remarquable Swift 3 ergonomics. This full 
snippet compiles in Swift 3:

func sum1(_ lhs: Int, _ rhs: Int) -> Int { return lhs + rhs }
func sum2(lhs: Int, rhs: Int) -> Int { return lhs + rhs }
func sum3(tuple: (Int, Int)) -> Int { return tuple.0 + tuple.1 }
func sum4(tuple: (lhs: Int, rhs: Int)) -> Int { return tuple.lhs + 
tuple.rhs }

// two arguments
func f1(_ closure: (Int, Int) -> Int) { closure(1, 2) }
f1 { lhs, rhs in lhs + rhs }
f1 { (lhs, rhs) in lhs + rhs }
f1 { tuple in tuple.0 + tuple.1 }
f1 { (tuple) in tuple.0 + tuple.1 }
f1(+)
f1(sum1)
f1(sum2)
f1(sum3)
f1(sum4)

// two arguments, with documentation names: identical
func f2(_ closure: (_ a: Int, _ b: Int) -> Int) { closure(1, 2) }
f2 { lhs, rhs in lhs + rhs }
f2 { (lhs, rhs) in lhs + rhs }
f2 { tuple in tuple.0 + tuple.1 }
f2 { (tuple) in tuple.0 + tuple.1 }
f2(+)
f2(sum1)
f2(sum2)
f2(sum3)
f2(sum4)

// one tuple argument
func f3(_ closure: ((Int, Int)) -> Int) { closure((1, 2)) }
f3 { lhs, rhs in lhs + rhs }
f3 { (lhs, rhs) in lhs + rhs }
f3 { tuple in tuple.0 + tuple.1 }
f3 { (tuple) in tuple.0 + tuple.1 }
f3(+)
f3(sum1)
f3(sum2)
f3(sum3)
f3(sum4)

// one keyed tuple argument
func f4(_ closure: ((a: Int, b: Int)) -> Int) { closure((a: 1, b: 2)) }
f4 { lhs, rhs in lhs + rhs }
f4 { (lhs, rhs) in lhs + rhs }
f4 { tuple in tuple.a + tuple.b }
f4 { (tuple) in tuple.a + tuple.b }
f4(+)
f4(sum1)
f4(sum2)
f4(sum3)
f4(sum4)

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: Always flatten the single element tuple

2017-06-07 Thread Gwendal Roué via swift-evolution

> Le 7 juin 2017 à 12:03, Adrian Zubarev via swift-evolution 
>  a écrit :
> 
> Well please no:
> 
> 
>  let fn2: ((Int, Int)) -> Void = { lhs, rhs in } 
> 
> Instead use destructuring sugar pitched by Chris Lattner on the other thread:
> 
> let fn2: ((Int, Int)) -> Void = { ((lhs, rhs)) in }
> 

Despite Chris Lattern being a semi-god, his double-parenthesis suggestion 
cruelly lacks in terms of user ergonomics. The compiler should be able to deal 
with the following code snippet, just like Swift 3 does:

// two arguments
func f1(_ closure: (Int, Int) -> Int) { closure(1, 2) }
f1 { lhs, rhs in lhs + rhs }
f1 { (lhs, rhs) in lhs + rhs }
f1 { tuple in tuple.0 + tuple.1 }
f1(+)

// two arguments, with documentation names
func f2(_ closure: (_ a: Int, _ b: Int) -> Int) { closure(1, 2) }
f2 { lhs, rhs in lhs + rhs }
f2 { (lhs, rhs) in lhs + rhs }
f2 { tuple in tuple.0 + tuple.1 }
f2(+)

// one tuple argument
func f3(_ closure: ((Int, Int)) -> Int) { closure((1, 2)) }
f3 { lhs, rhs in lhs + rhs }
f3 { (lhs, rhs) in lhs + rhs }
f3 { tuple in tuple.0 + tuple.1 }
f3(+)

// one keyed tuple argument
func f4(_ closure: ((a: Int, b: Int)) -> Int) { closure((a: 1, b: 2)) }
f4 { lhs, rhs in lhs + rhs }
f4 { (lhs, rhs) in lhs + rhs }
f4 { tuple in tuple.a + tuple.b }
f4(+)

This covers the Swift 3 regressions developped by Stephen Celis and I, unless I 
have missed any. And this should be the goal of the designers of this language, 
*regardless of the actual types*. Developers are olding their breath: please 
just make this happen.

Now Swift 3 may have an issue with $n parameters. Here is my suggestion, should 
`((Int, Int)) -> Int` be different from `(Int, Int) -> Int`:

f1 { $0 + $1 } // OK
f1 { $0.0 + $0.1 } // OK in Swift 3, compiler error in Swift 4?

f2 { $0 + $1 } // OK
f2 { $0.0 + $0.1 } // OK in Swift 3, compiler error in Swift 4?

f3 { $0 + $1 } // OK in Swift 3, compiler error in Swift 4?
f3 { $0.0 + $0.1 } // OK

f4 { $0 + $1 } // OK in Swift 3, compiler error in Swift 4?
f4 { $0.a + $0.b } // OK

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-06-06 Thread Gwendal Roué via swift-evolution

> Le 6 juin 2017 à 17:22, Shawn Erickson <shaw...@gmail.com> a écrit :
> 
> 
> On Tue, Jun 6, 2017 at 7:18 AM Gwendal Roué via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> 
>> Le 6 juin 2017 à 15:30, Vladimir.S <sva...@gmail.com 
>> <mailto:sva...@gmail.com>> a écrit :
>> 
>> I'm just trying to understand your opinion.
>> Let me know, what result do you *expect* for this Swift4 code given what 
>> SE-0066 requires for function types:
>> 
>> func foo(x : (Int, Int))->() {}
>> 
>> print(type(of: foo))  // ??
>> print(foo is (_: Int, _: Int)->())  // ??
> 
> I couldn't care less.
> 
> What I care about: the code regressions introduced by SE-0110 (look at 
> previous messages in this long thread, and the ridiculous state of closures 
> that eat tuples), and the migration bugs (look at Xcode 9 release notes).
> 
> Note that many of Apple's swift team are likely swamped with WWDC at the 
> moment. They are also dealing with merging out their private changes 
> announced so far at WWDC. Xcode 9 is prerelease still so expect things to get 
> revised to some degree before the final release.
> 
> Not say to not voice concerns but at this time some patience will be needed.
> 
> -Shawn

You are right, Shawn. I hope that the core team is currently enjoying all the 
congratulations they deserve :-)

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-06-06 Thread Gwendal Roué via swift-evolution

> Le 6 juin 2017 à 15:30, Vladimir.S  a écrit :
> 
> I'm just trying to understand your opinion.
> Let me know, what result do you *expect* for this Swift4 code given what 
> SE-0066 requires for function types:
> 
> func foo(x : (Int, Int))->() {}
> 
> print(type(of: foo))  // ??
> print(foo is (_: Int, _: Int)->())  // ??

I couldn't care less.

What I care about: the code regressions introduced by SE-0110 (look at previous 
messages in this long thread, and the ridiculous state of closures that eat 
tuples), and the migration bugs (look at Xcode 9 release notes).

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-06-06 Thread Gwendal Roué via swift-evolution

> Le 6 juin 2017 à 12:06, Vladimir.S  a écrit :
> 
> On 06.06.2017 7:36, Gwendal Roué wrote:
>> http://adcdownload.apple.com/WWDC_2017/Xcode_9_beta/Xcode_9_beta_Release_Notes.pdf
>>> The migrator does not properly distinquish between single-tuple and 
>>> multiple-argument function types as described in SE–0110, causing 
>>> additional mismatched type errors with the closure types that are passed to 
>>> Standard Library functions expecting tuple objects. (32431899)
>>> 
>>> Workaround: Manually fix the closure types to accept values of tuples 
>>> instead of separate argument values.
>>> 
>>> 
>>> When using $0 and $1 in a closure that is passed to a function expecting a 
>>> closure with a single tuple argument, the compiler may error after 
>>> migration with:
>>> 
>>> error: closure tuple parameter '(TYPE, TYPE)' does not support 
>>> destructuring with implicit parameters
>>> 
>>> (32489893)
>>> 
>>> Workaround: Change $0 and $1 references to $0.0 and $0.1 respectively.
>>> 
>> Where are the firemen?
> 
> Could you help me to understand which of my question did you reply on with 
> the above link and quotes? What are you trying to say? Thank you.

Oh, just that the Xcode 9 beta release notes list not less than four (four!) 
known issues related to SE-0110.

On top of the already discussed regressions introduced by SE-0110, we now have 
a painful migration.

I wonder why we're still spilling blood, why the fire hasn't been extinguish 
yet. Hence: where are the firemen?

Is there anybody responsible here? When will this endless discussion about 
"revisiting SE-0110" will eventually end with a reasonable decision?

When will the proposal process will be amended so that developers should be 
given a voice, along with language layers, on swift evolution? Developers don't 
have the same skills as language layers. Too many developers lack the poise and 
confidence to talk about the future impact of a language modification. Too many 
language layers fail to admit that some language modification do actual harm on 
written code after they have invested a lot of time thinking about it. That's 
normal.

And that's a recipe for things like SE-0110.

What I've read here so far makes me think SE-0110 belongs to the "false good 
ideas", as SE-0025 have been before. Along with SE-0025, maybe SE-0166, it has 
been deemed "stable" much too early. Unfortunately, the swift evolution process 
only produces stable amendments that are very painful to fix. I wish the core 
team would think about it some day: aren't the quality of the language and its 
core libraries at stake?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-06-05 Thread Gwendal Roué via swift-evolution
Wait, there's more!
> When passing a closure with a single underscore argument ({ _ in ...}) to a 
> function expecting multiple arguments, the compiler may error after migration 
> with:
> 
> error: cannot convert value of type '(_) -> ()' to expected argument
> type
> (32301091)
> Workaround: To fix the error, change the single argument to the correct 
> number of arguments
> 
> such as { (_,_) in ...}
> 
> 
> 
> When passing a closure to map with two function arguments, the compiler may 
> after migration error with:
> 
>error: 'map' produces '[T]', not the expected contextual result type
>''
> (32432752)
> Workaround: Change the closure signature to accept a tuple argument of two 
> elements when
> 
> using map. 
> 

Gwendal

> Le 6 juin 2017 à 06:36, Gwendal Roué  a écrit :
> 
> http://adcdownload.apple.com/WWDC_2017/Xcode_9_beta/Xcode_9_beta_Release_Notes.pdf
>  
> 
> 
>> The migrator does not properly distinquish between single-tuple and 
>> multiple-argument function types as described in SE–0110, causing additional 
>> mismatched type errors with the closure types that are passed to Standard 
>> Library functions expecting tuple objects. (32431899)
>> 
>> Workaround: Manually fix the closure types to accept values of tuples 
>> instead of separate argument values.
>> 
>> 
>> 
>> When using $0 and $1 in a closure that is passed to a function expecting a 
>> closure with a single tuple argument, the compiler may error after migration 
>> with:
>> 
>> error: closure tuple parameter '(TYPE, TYPE)' does not support
>> destructuring with implicit parameters
>> (32489893)
>> 
>> Workaround: Change $0 and $1 references to $0.0 and $0.1 respectively. 
>> 
> Where are the firemen?
> 
> Gwendal
> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-06-05 Thread Gwendal Roué via swift-evolution
http://adcdownload.apple.com/WWDC_2017/Xcode_9_beta/Xcode_9_beta_Release_Notes.pdf

> The migrator does not properly distinquish between single-tuple and 
> multiple-argument function types as described in SE–0110, causing additional 
> mismatched type errors with the closure types that are passed to Standard 
> Library functions expecting tuple objects. (32431899)
> 
> Workaround: Manually fix the closure types to accept values of tuples instead 
> of separate argument values.
> 
> 
> 
> When using $0 and $1 in a closure that is passed to a function expecting a 
> closure with a single tuple argument, the compiler may error after migration 
> with:
> 
> error: closure tuple parameter '(TYPE, TYPE)' does not support
> destructuring with implicit parameters
> (32489893)
> 
> Workaround: Change $0 and $1 references to $0.0 and $0.1 respectively. 
> 
Where are the firemen?

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-06-05 Thread Gwendal Roué via swift-evolution

> Le 4 juin 2017 à 19:16, Chris Lattner via swift-evolution 
>  a écrit :
> 
> One way to split the difference here is to eliminate the splatting behavior, 
> but keep the destructuring (irrefutable pattern matching) behavior as well.  
> In these cases, just require an extra explicit paren for the parameter list.  
> This would change the diff's to:
> 
> Example 1
> -return columns.index { (column, _) in column.lowercased() == 
> lowercaseName }
> +   return columns.index { ((column, _)) in column.lowercased() == 
> lowercaseName }
> 
> Example 2 :
> -.map { (mappedColumn, baseColumn) -> (Int, String) in
> +.map { ((mappedColumn, baseColumn)) -> (Int, String) in
> 
> Example 3 :
> -.map { (table, columns) in 
> "\(table)(\(columns.sorted().joined(separator: ", ")))" } 
> +.map { ((table, columns)) in 
> "\(table)(\(columns.sorted().joined(separator: ", ")))" }   
> 
> Example 4 :
> -dictionary.first { (column, value) in column.lowercased() == 
> orderedColumn.lowercased() }
> +dictionary.first { ((column, value)) in column.lowercased() 
> == orderedColumn.lowercased() }
> 
> 
> What do you think?  Seems like it would solve the type checker problem, 
> uglify the code a lot less, and make the fixit/migration happily trivial.
> 
> -Chris

Thanks for your feedback !

Your solution performs much better, but only to some point: the developers will 
just add parenthesis until the compiler is happy.

Quoting 
https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md:
 


> ## Motivation
> 
> Right now, the following is possible:
> 
> let fn1 : (Int, Int) -> Void = { x in 
> // The type of x is the tuple (Int, Int).
> // ...
> }
> 
> 
> let fn2 : (Int, Int) -> Void = { x, y in
> // The type of x is Int, the type of y is Int.
> // ...
> }
> 
> A variable of function type where there exist n parameters (where n > 1) can 
> be assigned a value (whether it be a named function, a closure literal, or 
> other acceptable value) which either takes in n parameters, or one tuple 
> containing n elements. This seems to be an artifact of the tuple splat 
> behavior removed in SE-0029.
> 
> The current behavior violates the principle of least surprise and weakens 
> type safety, and should be changed.

The motivation section is not at all about any "type checker problem". It's 
about a postulate that has been proven horribly source-breaking, and 
counter-productive. The type safety argument is moot. The principle of least 
surprise has been blown away by SE-0110, putting Swift aside from the majority 
of other languages.

I'm surprised that everybody tries to workaround SE-0110 consequences, 
admitting that it's relevant, instead of revisiting SE-0110 at its very root.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Self's nominal restriction denies significant feature patterns

2017-06-02 Thread Gwendal Roué via swift-evolution
The key is to implement methods that deal with Self as protocol extensions. Not 
*in* the protocol itself:

// YES
protocol DAOProtocol {
init()
}

extension DAOProtocol {
static func retOne() -> Self {return self.init()}
static func retMany() -> Array { return [] }
static func retTuple() -> (Self, Int) { return (self.init(), 0) }
}

// NO
// protocol DAOProtocol {
// init()
// static func retOne() -> Self
// static func retMany() -> Array
// static func retTuple() -> (Self, Int)
// }

class Selfie : DAOProtocol{
required init() {}
}

Selfie.retOne()
Selfie.retMany()
Selfie.retTuple()

Beware: methods declared in protocol extensions *can not be customized* by 
adopting types. Only methods declared in the protocol itself can, and become 
customization points. This is an important constraint to think about when you 
design your protocols. Again, GRDB can be of great help for you: it has been 
working well for almost two years now.

Gwendal


> Le 2 juin 2017 à 12:10, Zaid Daghestani  a écrit :
> 
> *edit*
> Actual protocol implementation:
> 
> protocol Selfie {
> init()
> }
> extension Selfie {
> static func retOne() -> Self {return self.init()}
> static func retMany() -> Array { return [] }
> static func retTuple() -> (Self, Int) { return (self.init(), 0) }
> }
> 
> 
>> On Jun 2, 2017, at 3:08 AM, Zaid Daghestani > > wrote:
>> 
>> Wow, you’re right. Look like this is a bug? The issue shows up in class 
>> definitions, not protocol definitions.   
>> 
>> This works:
>> 
>> protocol Selfie {
>> static func retOne() -> Self
>> static func retMany() -> Array
>> static func retTuple() -> (Self, Int)
>> }
>> 
>> This doesn’t work:
>> 
>> class Selfie {
>> required init() {}
>> // Compiles
>> static func retOne() -> Self {return self.init()}
>> // Doesn't Compile
>> static func retMany() -> Array { return [] }
>> // Doesn't Compile
>> static func retTuple() -> (Self, Int) { return (self.init(), 0) }
>> 
>> }
>> 
>> So Self in non-nominal types with class methods end up with the compiler 
>> error:
>> 
>> Error: 'Self' is only available in a protocol or as the result of a method 
>> in a class; did you mean ’Selfie’?
>> 
>> Can we get confirmation from anyone?
>> 
>> 
>> 
>>> On Jun 2, 2017, at 2:39 AM, Gwendal Roué >> > wrote:
>>> 
>>> Hello Zaid,
>>> 
>>> I don't know what prevents you from implementing your DAOs.
>>> 
>>> For an example of a library that uses them extensively, see 
>>> http://github.com/groue/GRDB.swift: 
>>> 
>>> struct PointOfInterest {
>>> var id: Int64?
>>> var title: String?
>>> var favorite: Bool
>>> var coordinate: CLLocationCoordinate2D
>>> }
>>> 
>>> // (snip) adopt protocols that turn PointOfInterest in a "record"
>>> 
>>> // Fetch from SQL
>>> let pois = try PointOfInterest.fetchAll(db, "SELECT * FROM 
>>> pointOfInterests") // [PointOfInterest]
>>> 
>>> // Fetch without SQL
>>> let title = Column("title")
>>> let favorite = Column("favorite")
>>> let poi1 = try PointOfInterest.fetchOne(db, key: 1)   
>>> // PointOfInterest?
>>> let pois = try PointOfInterest.fetchOne(db, keys: [1, 2, 3])  
>>> // [PointOfInterest]
>>> let paris = try PointOfInterest.filter(title == "Paris").fetchOne(db) 
>>> // PointOfInterest?
>>> let favoritePois = try PointOfInterest
>>> // [PointOfInterest]
>>> .filter(favorite)
>>> .order(title)
>>> .fetchAll(db)
>>> 
>>> // Insert, update, delete
>>> var berlin = PointOfInterest(
>>> id: nil,
>>> title: "Berlin",
>>> favorite: false,
>>> coordinate: CLLocationCoordinate2DMake(52.52437, 13.41053))
>>> try berlin.insert(db)
>>> berlin.id // some value
>>> berlin.favorite = true
>>> try berlin.update(db)
>>> try berlin.delete(db)
>>> 
>>> GRDB "records" work pretty well with structs, but also class hierarchies, 
>>> without any caveat.
>>> 
>>> Can you explain a little more your issue ?
>>> 
>>> Gwendal Roué
>>> 
>>> 
 Le 2 juin 2017 à 11:18, Zaid Daghestani via swift-evolution 
 > a écrit :
 
 Greetings Swift Community,
 
 Today I’m throwing out a pitch on freeing the shackles on Self. Self is a 
 potentially significant tool that I am itching to implement in my patterns 
 to make my code more concise, clear and intuitive.
 
 Self, by far, is cherished by Data Models and ORM's, and particularly DAO 
  s (Ref. 1 for examples). There are a 
 

Re: [swift-evolution] [Pitch] Self's nominal restriction denies significant feature patterns

2017-06-02 Thread Gwendal Roué via swift-evolution
Hello Zaid,

I don't know what prevents you from implementing your DAOs.

For an example of a library that uses them extensively, see 
http://github.com/groue/GRDB.swift:

struct PointOfInterest {
var id: Int64?
var title: String?
var favorite: Bool
var coordinate: CLLocationCoordinate2D
}

// (snip) adopt protocols that turn PointOfInterest in a "record"

// Fetch from SQL
let pois = try PointOfInterest.fetchAll(db, "SELECT * FROM 
pointOfInterests") // [PointOfInterest]

// Fetch without SQL
let title = Column("title")
let favorite = Column("favorite")
let poi1 = try PointOfInterest.fetchOne(db, key: 1)   // 
PointOfInterest?
let pois = try PointOfInterest.fetchOne(db, keys: [1, 2, 3])  // 
[PointOfInterest]
let paris = try PointOfInterest.filter(title == "Paris").fetchOne(db) // 
PointOfInterest?
let favoritePois = try PointOfInterest// 
[PointOfInterest]
.filter(favorite)
.order(title)
.fetchAll(db)

// Insert, update, delete
var berlin = PointOfInterest(
id: nil,
title: "Berlin",
favorite: false,
coordinate: CLLocationCoordinate2DMake(52.52437, 13.41053))
try berlin.insert(db)
berlin.id // some value
berlin.favorite = true
try berlin.update(db)
try berlin.delete(db)

GRDB "records" work pretty well with structs, but also class hierarchies, 
without any caveat.

Can you explain a little more your issue ?

Gwendal Roué


> Le 2 juin 2017 à 11:18, Zaid Daghestani via swift-evolution 
>  a écrit :
> 
> Greetings Swift Community,
> 
> Today I’m throwing out a pitch on freeing the shackles on Self. Self is a 
> potentially significant tool that I am itching to implement in my patterns to 
> make my code more concise, clear and intuitive.
> 
> Self, by far, is cherished by Data Models and ORM's, and particularly DAO 
>  s (Ref. 1 for examples). There are a 
> significant amount of patterns in which a base class’s methods are Self 
> relevant and not generic relevant. Self being non-referrable in non-nominal 
> types denies significant feature and pattern delivery such as DAO. And to 
> deny implementation of a pattern as significant as DAO’s seems like a shot in 
> the foot. Adding Self to non-nominal types brings Collections and Async to 
> our class/protocol methods. A single query method returning a sync or likely 
> async collection on my DataModel class will be used in about 80% of my app 
> screens and 80% of my eerver API’s, almost all of the time. Hell this even 
> applies to struct patterns as well.
> 
> Now, DAO’s can actually already currently be achieved via generics, see Ref. 
> 2. This actually still a pretty good implementation, but Self is a 
> significantly more true implementation of these patterns. Issues with the 
> current generic pattern of Self relevancy in Swift is:
> 1- Generic methods in the base class are a workaround to the lack of Self. 
> The base class is not a class that implements generic patterns. It a base 
> class that implements Self patterns. Self is more concise and intuitive in 
> implementing a DAO or any other Self relevant base class.
> 2- Self relevant patterns are distinct and not the same as Generic patterns. 
> 3- In usage of a DAO, the generic pattern requires that the Left Hand Side be 
> typed to collapse the generic. In the case of Self relevance, the particular 
> class name is enough. Swift, being an inference language, would be truer with 
> the Self system, and not the repetitive type declaration style of ObjC/Java 
> that generics provide.
> let friends = User.where("id IN %@", friendIds) // truer to Swift type 
> inference
> // vs.
> let friends:[User] = User.where("id IN %@", friendIds) // Java/Objective-C 
> style repetitive type declarations
> 
> Let’s break the chains on Self! It is extremely intuitive, and we are all 
> going to use it
> 
> Peace!
> 
> Z
> 
> 
> 
> 
> Ref 1: DAO patterns::
> 
> class DataModelObject  {
> 
> /* One of the most significant use cases
>  * Retrieving a queried on collection asynchronusly
>  */
> class func `where`(_ predicate:String, _ args:CVarArg...) -> 
> Promise<[Self]> {
> // querie
> return Promise(value: [[])
> }
> 
> // some more examples
> 
> // optional async get
> class func get(id:String) -> Promise {
> return Promise(value:self.init(id:id))
> }
> 
> // sync all collection
> class func all() -> [Self] {
> return []
> }
> // asynnchronous fetch
> class func allAsync() -> Promise<[Self]> {
> return Promise(value: [])
> }
> 
> // in the case of RealmDB we have returns of Results, a lazy 
> collection
> class func `where`(_ predication:NSPredicate) -> Results {
> return Results()
> }

Re: [swift-evolution] Question regarding SE-0167 Swift Encoders

2017-05-31 Thread Gwendal Roué via swift-evolution

> Le 31 mai 2017 à 15:39, David Hart <da...@hartbit.com> a écrit :
> 
>> 
>> On 31 May 2017, at 14:36, Gwendal Roué via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> Itai,
>> 
>> (This email is not technical)
>> 
>> I'm not claiming that SE-0166 should be able to address all archival 
>> formats. I've been talking about GRDB to show at least one format that 
>> SE-0166 doesn't cover well. And should SE-0166 be fixed to support SQL (in 
>> the GRDB fashion), this does not mean that other developers won't eventually 
>> fight with SE-0166 until they understand it does not fit their bill.
>> 
>> But there's something very special with SE-0166:
>> 
>> It's in the standard library, with all the backward-compatibility 
>> constraints that come with such a position.
>> 
>> IT'S BLESSED WITH CODE GENERATION.
> 
> One important future goal I hope we can address in future versions of Swift 
> is powerful macro/meta-programming features. I think like Sourcery 
> (https://github.com/krzysztofzablocki/Sourcery 
> <https://github.com/krzysztofzablocki/Sourcery>) but at compile-time, in the 
> language. Once we have that, I hope we can re-implement SE-0166’s code 
> generation using those meta-programming features into the Standard Library 
> and tear it out of the compiler. If we can achieve that, we will have a 
> strong toolbox for any third-library which have similar needs.
> 
> PS: With meta-programming, we could also re-implement the automatic 
> Equatable/Hashable conformances. More magic in the compiler is usually a bad 
> thing I think.

Hi David,

You're right, it's possible that SE-0166 eventually uses future macro-like 
features.

When this happens, the code generation blessing will be available to all Swift 
users, and SE-0166 will no longer be the necessary underlying foundation for 
libraries that want to use its code generation features (regardless of whether 
they are right or wrong: library developers don't think like compiler 
developers).

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Question regarding SE-0167 Swift Encoders

2017-05-31 Thread Gwendal Roué via swift-evolution

> Le 31 mai 2017 à 19:15, Itai Ferber  a écrit :
> 
> Hi Gwendal,
> 
> I hear your frustration. Some comments inline.

And I apologize for having written a rant :-)

>> On May 31, 2017, at 5:36 AM, Gwendal Roué > > wrote:
>> 
>> Itai,
>> 
>> (This email is not technical)
>> 
>> I'm not claiming that SE-0166 should be able to address all archival 
>> formats. I've been talking about GRDB to show at least one format that 
>> SE-0166 doesn't cover well. And should SE-0166 be fixed to support SQL (in 
>> the GRDB fashion), this does not mean that other developers won't eventually 
>> fight with SE-0166 until they understand it does not fit their bill.
> I’ll respond to the technical portion of this thread in the other email, but 
> let me at least provide some background here. When working on this feature, 
> we thought for a very long time about what we were looking to support with 
> this feature, and how (feel free to take a look at the Alternatives 
> Considered section of the proposal, though of course, there were more 
> attempts and approaches before that).
> The majority of this thought was put into figuring out what the proper 
> abstractions were for applying this new API — how can we abstract over 
> different archival and serialization formats in a way that makes this useful?
> 
> In truth, if you try to abstract over all archival and serialization formats, 
> the abstraction that you get is... the empty set. :) There are simply so many 
> different things at odds with one another across different formats (JSON 
> supports null values, plist does not; numbers are arbitrary precision in 
> JSON, but not in plist or MessagePack or others; plist and MessagePack and 
> others support binary data blobs, but JSON does not; etc.) that if you try to 
> abstract over them all, you end up with nothing useful — an empty protocol 
> that covers nothing.
> 
> So the key here is to try to strike a pragmatic balance between supporting 
> some of the most common archival and serialization formats in a way that 
> makes them useful, even if we have to handle special cases in some of them 
> (e.g. null values in plist, binary data in JSON, etc.). It’s true that we 
> cannot support them all, but in fact, we’re not looking to, because it would 
> weaken the API.
> 
> I will respond to the comments specific to GRDB in the other thread, but this 
> is a bit of background. Yes, there will always developers who will not be 
> able to fit a serialization format into this API because it is fundamentally 
> different in a way that cannot fit with the rest of the formats we’re looking 
> to support. There’s nothing to be done about that. But, you mention this 
> yourself.

I totally support this point of view. And JSON/Plist/NSCoding were the expected 
fundamentals.

For me the consequence of these intrinsic limitations / admitted caveats / 
necessary humbleness, should have blocked the inclusion of the this archival 
mechanism in the Standard Lib. Or at least its *fast* inclusion in the stdlib.

The reason for this is that unlike many others parts of the standard lib that 
are under constant scrutiny from the community, chances are low that many 
Coder/Decoder are/will be written.

To be short: don't you think it's too early to declare the archival library 
*stable*?

>> But there's something very special with SE-0166:
>> 
>> It's in the standard library, with all the backward-compatibility 
>> constraints that come with such a position.
>> 
>> IT'S BLESSED WITH CODE GENERATION.
>> 
>> I don't know if you, Michael LeHew, Tony Parker, and the core team, realize 
>> the importance of this insanely great privilege granted to this proposal.
> Believe me, I do, because we considered a lot of different approaches before 
> settling on this. We wanted to avoid code generation for this reason — it has 
> a privileged place within the compiler, it generates code which the user may 
> not be able to introspect, etc.
> At the end of the day, though, we decided on this option because it provided 
> the best user experience as part of the language in the vast majority of 
> cases. There’s a lot to be said for that, and you mention this yourself, too.

So you want to improve the user experience... But below you attempt to lower 
the impact of code generation:

>> The lack of introspection and macros in Swift makes SE-0166 immensely 
>> attractive for a whole category of libraries.
>> 
>> When SE-0166 is lacking, should those libs ignore it, and lose CODE 
>> GENERATION, which means looking like it's still Swift 3?
>> 
>> Should those libs claim SE-0166 conformance, and raise runtime errors for 
>> invalid inputs (where "invalid" does not mean "invalid data", or "invalid 
>> code", but "impossible to fit in SE-0166" <=> "invalid library")?
> That being said, let’s separate the capabilities of the Codable API itself 
> from the code generated by the compiler for 

Re: [swift-evolution] Question regarding SE-0167 Swift Encoders

2017-05-31 Thread Gwendal Roué via swift-evolution
Itai,

(This email is not technical)

I'm not claiming that SE-0166 should be able to address all archival formats. 
I've been talking about GRDB to show at least one format that SE-0166 doesn't 
cover well. And should SE-0166 be fixed to support SQL (in the GRDB fashion), 
this does not mean that other developers won't eventually fight with SE-0166 
until they understand it does not fit their bill.

But there's something very special with SE-0166:

It's in the standard library, with all the backward-compatibility constraints 
that come with such a position.

IT'S BLESSED WITH CODE GENERATION.

I don't know if you, Michael LeHew, Tony Parker, and the core team, realize the 
importance of this insanely great privilege granted to this proposal.

The lack of introspection and macros in Swift makes SE-0166 immensely 
attractive for a whole category of libraries.

When SE-0166 is lacking, should those libs ignore it, and lose CODE GENERATION, 
which means looking like it's still Swift 3?

Should those libs claim SE-0166 conformance, and raise runtime errors for 
invalid inputs (where "invalid" does not mean "invalid data", or "invalid 
code", but "impossible to fit in SE-0166" <=> "invalid library")?

I'd like to hear a little better than that :-) GRDB is a library of unusual 
quality (sorry for the auto-congratulation). Until now, fatal errors thrown by 
GRDB were always a sign of programmer mistake. Not of defects in the 
foundations. I wish this would remain true.

Less caveats and runtime/fatal errors mean less user frustration.

Less caveats also mean less documentation to write. Ideally, this should be 
enough: https://github.com/groue/GRDB.swift/tree/Swift4#codable-records

Gwendal
Just a guy that write Swift apps and libraries


> Le 30 mai 2017 à 20:49, Itai Ferber <ifer...@apple.com> a écrit :
> 
> Hi Gwendal,
> 
> There are no stupid questions — everything helps hammer out this API, so I 
> appreciate you taking the time to look at this so deeply.
> I have to confess that I’m not familiar with this concept, but let’s take a 
> look:
> 
> if let valueType = T.self as? DatabaseValueConvertible.Type {
> // if column is missing, trigger the "missing key" error or return nil.
> } else if let complexType = T.self as? RowConvertible.Type {
> // if row scope is missing, trigger the "missing key" error or return nil.
> } else {
> // don't know what to do
> fatalError("unsupported")
> }
> Is it appropriate for a type which is neither DatabaseValueConvertible nor 
> RowConvertible to be decoded with your decoder? If not, then this warrants a 
> preconditionFailure or an error of some sort, right? In this case, that would 
> be valid.
> 
> You also mention that "it’s still impossible to support other Codable types" 
> — what do you mean by this? Perhaps there’s a way to accomplish what you’re 
> looking to do.
> In any case, one option (which is not recommended unless if there are other 
> avenues to solve this by) is to perform a "dry run" decoding. Attempt to 
> decode the type with a dummy decoder to see what container it will need, then 
> prepare your approach and do it again for real. Obviously, this isn’t a clean 
> way to do it if we can find alternatives, but it’s an option.
> 
> — Itai
> 
> On 29 May 2017, at 4:51, Gwendal Roué via swift-evolution wrote:
> 
> Hello,
> 
> I have already asked stupid questions about SE-0167 and SE-0166, but this 
> time I hope this is a real one.
> 
> According so SE-0166, codable types themselves instantiate a single value 
> decoder, or a keyed container:
> 
> public struct Farm : Codable {
> public init(from decoder: Decoder) throws {
> let container = try decoder.container(keyedBy: CodingKeys.self
> ...
> }
> }
> 
> public enum Animal : Int, Codable {
> public init(from decoder: Decoder) throws
> let intValue = try decoder.singleValueContainer().decode(Int.self)
> ...
> }
> }
> 
> According to SE-0167, decoder decode non-trivial types in their 
> decode(_:forKey:) and decodeIfPresent(_:forKey:) methods:
> 
> func decode(_ type: T.Type, forKey key: Key) throws -> T where T : 
> Decodable
> func decodeIfPresent(_ type: T.Type, forKey key: Key) throws -> T? where T 
> : Decodable
> 
> My trouble is that the decoder does not know whether the Decodable type will 
> ask for a keyed container, or for a single value container.
> 
> Why is it a problem?
> 
> In the context of decoding of SQL rows, keys may refer to different things, 
> depending on whether we are decoding a *value*, or a *complex object*:
> 
> - for values, keys are column names, as everybody can expect
> - for complex objects, keys are name

Re: [swift-evolution] Question regarding SE-0167 Swift Encoders

2017-05-30 Thread Gwendal Roué via swift-evolution
Hello Itai,

Thanks for helping sorting things out.

I have since my initial question a better understanding of Codable, and I hope 
I can better express the trouble. I bump against the fact that SE-0166 and 
SE-0167 assume that there is a single kind of coding keys.

This is the case for JSON and Plist:

{
"a": "foo"
"b": { ... }
}

But imagine a different serialization format where we don't use the same kind 
of keys for values and objects. Values are stored on red keys, and objects on 
blue keys:

{
"a" (red): "foo"
"b" (blue): { ... }
}

This serialization format accepts keys with the same name, as long as they 
don't have the same color:

{
"a" (red): "foo"
"a" (blue): { ... }
}

This format is used by SQL rows in GRDB. A SQL row is both a set of columns 
with associated values (the "red" keys), plus a set of scopes with associated 
"view" on the row (the blue keys):

let row = ...
row["id"]  // 1
let scopedRpw = row.scoped(on: "foo")! // 
scopedRow["id"]// 2

If you wonder: "but why???": columns and scopes are what can make rows a 
suitable base for hierarchical decoding, just like JSON and PList. When a flat 
SQL row fetched from a joined query is seen as a hierarchical structure, 
several simple `init(row:)` initializers can get the rows they expect, and we 
load a complex graph of objects. I have high hopes 
(https://github.com/groue/GRDB.swift/issues/176#issuecomment-285938568).

I care about Codable because of the code generation is has been blessed with. I 
expect GRDB users to rush on Codable since they won't have any longer to write 
the decoding boilerplate.


> I have to confess that I’m not familiar with this concept, but let’s take a 
> look:
> if let valueType = T.self as? DatabaseValueConvertible.Type {
> // if column is missing, trigger the "missing key" error or return nil.
> } else if let complexType = T.self as? RowConvertible.Type {
> // if row scope is missing, trigger the "missing key" error or return nil.
> } else {
> // don't know what to do
> fatalError("unsupported")
> }
> Is it appropriate for a type which is neither DatabaseValueConvertible nor 
> RowConvertible to be decoded with your decoder? If not, then this warrants a 
> preconditionFailure or an error of some sort, right? In this case, that would 
> be valid.
> 
Yes it is, there's no point preventing this.

We can forget the GRDB DatabaseValueConvertible and RowConvertible protocals in 
this discussion - they have their purpose, but are irrelevant here, and I was 
wrong letting them in the discussion. Will you look at some updated code?

In practice, let's consider the 
`KeyedDecodingContainerProtocol.decode(_:forKey:)` method. The decoding 
container is asked for a type T. It does not know yet if T is a single-value or 
a keyed type. No problem: it delays the decision until the Decoder is asked for 
a container:

struct RowKeyedDecodingContainer: 
KeyedDecodingContainerProtocol {
func decode(_ type: T.Type, forKey key: Key) throws -> T where T : 
Decodable {
// Push the key, and wait until the decoder is asked for a container
// so that we know if T is keyed, or single-value:
return try T(from: RowDecoder(row: row, codingPath: codingPath + 
[key]))
}
}

struct RowDecoder: Decoder {
func container(keyedBy type: Key.Type) throws -> 
KeyedDecodingContainer {
if let key = codingPath.last {
// Asked for a keyed type: look for a row scope
if let scopedRow = row.scoped(on: key!.stringValue) {
let container = RowKeyedDecodingContainer(row: 
scopedRow, codingPath: codingPath)
return KeyedDecodingContainer(container)
} else {
throw DecodingError.keyNotFound...
}
} else {
// Asked for a keyed type at the top level
let container = RowKeyedDecodingContainer(row: row, 
codingPath: codingPath)
return KeyedDecodingContainer(container)
}
}

func singleValueContainer() throws -> SingleValueDecodingContainer {
// Asked for a single-value type: look for a column
return RowColumnDecodingContainer(row: row, column: 
codingPath.last!!.stringValue)
}
}

(Sorry for the bangs, I still have to understand how I should deal with nil 
coding keys)

This works pretty well so far.

But now let's consider the 
`KeyedDecodingContainerProtocol.decodeIfPresent(_:forKey:)` method. Now we have 
a problem. This method must return nil if the key is missing. But which key? We 
don't know if the decoded type is keyed, or single-value. We can't postpone the 
decision, as 

Re: [swift-evolution] Question regarding SE-0167 Swift Encoders

2017-05-29 Thread Gwendal Roué via swift-evolution

> Le 29 mai 2017 à 13:51, Gwendal Roué  a écrit :
> 
> In the context of decoding of SQL rows, keys may refer to different things, 
> depending on whether we are decoding a *value*, or a *complex object*:
> 
> - for values, keys are column names, as everybody can expect
> - for complex objects, keys are names of "row scopes". Row scopes are a 
> concept introduced by GRDB.swift and allows a type that knows how to consume 
> `SELECT * FROM table1` to consume as well the results of `SELECT table1.*, 
> table2.* FROM table1 JOIN table2` through a "scope" that presents the row in 
> the shape expected by the consumer (here, only columns from table1).

This is the general topic of "row adapters", something that I don't know if any 
other SQL libraries implements. You may thus not be familiar with it, and may 
even doubt if that concept has any value.

Row adapters are indeed quite unusual, but they're very useful, and solve hard 
problems.

Please check https://github.com/groue/GRDB.swift#row-adapters 
 for more information.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


[swift-evolution] Question regarding SE-0167 Swift Encoders

2017-05-29 Thread Gwendal Roué via swift-evolution
Hello,

I have already asked stupid questions about SE-0167 and SE-0166, but this time 
I hope this is a real one.

According so SE-0166, codable types themselves instantiate a single value 
decoder, or a keyed container:

public struct Farm : Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: 
CodingKeys.self
...
}
}

public enum Animal : Int, Codable {
public init(from decoder: Decoder) throws
let intValue = try 
decoder.singleValueContainer().decode(Int.self)
...
}
}

According to SE-0167, decoder decode non-trivial types in their 
decode(_:forKey:) and decodeIfPresent(_:forKey:) methods:

func decode(_ type: T.Type, forKey key: Key) throws -> T where T : 
Decodable
func decodeIfPresent(_ type: T.Type, forKey key: Key) throws -> T? 
where T : Decodable

My trouble is that the decoder does not know whether the Decodable type will 
ask for a keyed container, or for a single value container.

Why is it a problem?

In the context of decoding of SQL rows, keys may refer to different things, 
depending on whether we are decoding a *value*, or a *complex object*:

- for values, keys are column names, as everybody can expect
- for complex objects, keys are names of "row scopes". Row scopes are a concept 
introduced by GRDB.swift and allows a type that knows how to consume `SELECT * 
FROM table1` to consume as well the results of `SELECT table1.*, table2.* FROM 
table1 JOIN table2` through a "scope" that presents the row in the shape 
expected by the consumer (here, only columns from table1).

This is supposed to allow support for types that contain both nested types and 
values (one of the goals of SE-0166 and SE-0167):

struct Compound : Codable {
let someStruct: SomeStruct // object that feeds on the 
"someStruct" scope
let name: String // value that feeds on the "name" column
}

The two decoding methods decode(_:forKey:) and decodeIfPresent(_:forKey:) can't 
be implemented nicely, because they don't know whether the decodable type will 
ask for a keyed container or a single value container, and thus they don't know 
whether they should look for the presence of a row scope, or of a column:

A workaround is to perform runtime checks on the GRDB protocols adopted by T, 
as below. But it's still impossible to support other codable types:

if let valueType = T.self as? DatabaseValueConvertible.Type {
// if column is missing, trigger the "missing key" error or 
return nil.
} else if let complexType = T.self as? RowConvertible.Type {
// if row scope is missing, trigger the "missing key" error or 
return nil.
} else {
// don't know what to do
fatalError("unsupported")
}

Do you have any advice?

Gwendal Roué


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-05-28 Thread Gwendal Roué via swift-evolution

> Le 27 mai 2017 à 19:43, Dave Abrahams via swift-evolution 
>  a écrit :
> 
> 
> on Thu May 25 2017, Gwendal Roué  > wrote:
> 
>>> Furthermore, this probably comes up most commonly with dictionaries,
>>> since they're a sequence of tuples. The element tuple for
>>> dictionaries has element labels (key: Key, value: Value), so instead
>>> of writing `{ tuple in let (key, value) = tuple; f(key, value) }`,
>>> you could use the implicit argument and write `{ f($0.key, $0.value)
>>> }`.
>>> 
>>> -Joe
>> 
>> I've migrated a project from Swift 3 to Swift 4 (relevant commit:
>> https://github.com/groue/GRDB.swift/commit/4f26cbcacf7b783c9c503f2909f2eb03ef7930fe)
>> 
>> Joe is right, dictionaries, as handy as they are, are particularly affected. 
>> But $0 is hardly a
>> panacea.
>> 
>> What I regret the most with the change is the lost ability to give
>> *relevant names* to tuple elements (and sometimes with the forced
>> introduction of a phony variable that has no relevant name (like
>> "pair").
> 
> Not saying there's no problem here, but `kv` (or `keyValue` if you must)
> works pretty well for this.  At least it isn't purely a reflection of
> the type and gives some hint as to semantics.

Let me please try to be understood:

A dictionary is a convenience type, with many many purposes. One rarely thinks 
of a dictionary as a "dictionary". It's more often a "cache", or a "name1 to 
name2 mapping", as in "name to position mapping", "lowercase string to 
case-preserved string mapping", or whatever you want.

The "kv", "pair", "key", "value" identifiers are not only irrelevant, they 
actively hinder code readability. Compare:

- ...map { $0.key ... $0.value ... }
- ...map { (name, position) in name ... position ... }

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-05-27 Thread Gwendal Roué via swift-evolution
> Le 27 mai 2017 à 14:20, Gwendal Roué  a écrit :
> 
>> Le 26 mai 2017 à 21:35, Robert Bennett via swift-evolution 
>> > a écrit :
>> 
>> On the contrary I think the solution can absolutely be to break other code. 
> 
> You can break whatever you want.
> 
> But whatever the solution you come up with, remember that SE-0110 currently 
> *degrades* the quality of code written by Swift programmers. It can be argued 
> that SE-0110 is a blatant *regression*. Maybe not as bad as the initial 
> introduction of fileprivate, but something which is pretty bad, though.
> 
> References:
> - 
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170522/036808.html
>  
> 
> - 
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170522/036814.html
>  
> 
One more link, about the loss of single-lign closures induced by SE-0110: 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170522/036792.html

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-05-27 Thread Gwendal Roué via swift-evolution

> Le 26 mai 2017 à 21:35, Robert Bennett via swift-evolution 
>  a écrit :
> 
> On the contrary I think the solution can absolutely be to break other code. 

You can break whatever you want.

But whatever the solution you come up with, remember that SE-0110 currently 
*degrades* the quality of code written by Swift programmers. It can be argued 
that SE-0110 is a blatant *regression*. Maybe not as bad as the initial 
introduction of fileprivate, but something which is pretty bad, though.

References:
- 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170522/036808.html
 

- 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170522/036814.html
 


It would be nice if some responsible language designer would at least *agree* 
that there is a problem.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Feedback on SE-0166 and SE-0167

2017-05-27 Thread Gwendal Roué via swift-evolution

> Le 27 mai 2017 à 11:59, David Hart  a écrit :
> 
> I didn’t know that was possible either! Really cool. Even better:
> 
>  if let databaseValueType = T.self as? DatabaseValueConvertible.Type {
>  let databaseValue: DatabaseValue = row.value(named: key.stringValue)
>  return databaseValueType.fromDatabaseValue(databaseValue) as! T
>  } else { … }


Yes, that's even more clear like that :-)

And for Encodable support, it works just great (not a single line of 
boilerplate code):

private enum Color: String, DatabaseValueConvertible, Encodable {
case red, green, blue
}

private struct EncodableStruct : Persistable, Encodable {
static let databaseTableName = "myTable"
let name: String
let color: Color?
}

try dbQueue.inDatabase { db in
try EncodableStruct(name: "Arthur", color: .red).insert(db)
}

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Feedback on SE-0166 and SE-0167

2017-05-27 Thread Gwendal Roué via swift-evolution

> Le 26 mai 2017 à 22:30, David Hart <da...@hartbit.com> a écrit :
> 
> Can you explain what’s the problem with Issue 2?

The problem was me, I guess :-) Of course nobody knows the list of keys, but 
the type itself. It's a matter of injecting an encoder. I'll do that.

Thanks also Itai for your answer.

> Am I correct in suggesting that Issue 1 is more of a missing generics feature 
> than a problem with SE-0166/0167?

There are two ways to see such issue: either a language is not ready, either a 
library isn't designed for its language. :-) But this is not the case here. 
Again, Itai has the correct answer:

   if T.self is DatabaseValueConvertible.Type {
   let databaseValue: DatabaseValue = row.value(named: key.stringValue)
   return (T.self as! 
DataBaseValueConvertible.Type).fromDatabaseValue(databaseValue) as! T
   } else { ... }

This is the way to test a type against a protocol - I didn't know this was even 
possible!

Thanks a lot, Itai and David: SE-0166 and SE-0167 are delivering their 
promises, and GRDB will make good use from them :-)
Gwendal

> 
> David.
> 
>> On 26 May 2017, at 16:26, Gwendal Roué via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> Hello,
>> 
>> I want to provide real-life feedback for the Swift Archival & Serialization 
>> (SE-0166) and Swift Encoders (SE-0167) proposals that currently ship in 
>> Swift 4 snapshots.
>> 
>> The context: I'm the author of GRDB.swift [1], a SQLite library that, among 
>> other goals, aims at easing the conversion between database rows and custom 
>> models (structs and class hierarchies):
>> 
>>  // Sample code
>>  let arthur = Player(name: "Arthur", score: 100)
>>  try arthur.insert(db)
>>  print(arthur.id)
>>  
>>  let topPlayers = try Player
>>  .order(Column("score").desc)
>>  .limit(10)
>>  .fetchAll(db) // [Player]
>> 
>> Due to the lack of any introspection in Swift, GRDB currently wants you to 
>> perform explicit conversion:
>> 
>>  struct Player {
>>  var id: Int64?
>>  let name: String
>>  let score: Int
>>  }
>>  
>>  extension Player : RowConvertible {
>>  init(row: Row) {
>>  id = row.value(named: "id")
>>  name = row.value(named: "name")
>>  score = row.value(named: "score")
>>  }
>>  }
>>  
>>  extension Player : TableMapping, MutablePersistable {
>>  static let databaseTableName = "player"
>>  var persistentDictionary: [String: DatabaseValueConvertible?] {
>>  return ["id": id, "name": name, "score: score]
>>  }
>>  }
>> 
>> That's enough, but that's still too much.
>> 
>> SE-0166 and SE-0167 sound like the promise that some boilerplate code could 
>> be automatically generated.
>> 
>> Along with JSONDecoder and PListDecoder, let's introduce DatabaseRowDecoder! 
>> The current state of the work is at 
>> https://github.com/groue/GRDB.swift/tree/Swift4
>> 
>> 
>> At first, it's very satisfying. Decodable keeps some of it promises:
>> 
>>  struct Player : RowConvertible, Decodable {
>>  static let databaseTableName = "player"
>>  var id: Int64?
>>  let name: String
>>  let score: Int
>>  }
>>  
>>  // Yeah, no more extra code necessary for this to work!
>>  let topPlayers = try Player
>>  .order(Column("score").desc)
>>  .limit(10)
>>  .fetchAll(db)
>> 
>> But there are some issues.
>> 
>> 
>> ### Issue 1: SE-0166/0167 merge the concepts of keyed objects and values
>> 
>> This is a problem. Let's take this example:
>> 
>>  enum Color: Int, Codable {
>>  case blue, green, red
>>  }
>>  
>>  struct Flower : RowConvertible, Decodable {
>>  let name: String
>>  let color: Color
>>  }
>>  
>> The way to decode a color comes from KeyedDecodingContainerProtocol:
>> 
>>  protocol KeyedDecodingContainerProtocol {
>>  func decode(_ type: T.Type, forKey key: Key) throws -> T 
>> where T : Decodable
>>  func decodeIfPresent(_ type: T.Type, forKey key: Key) throws 

[swift-evolution] Feedback on SE-0166 and SE-0167

2017-05-26 Thread Gwendal Roué via swift-evolution
Hello,

I want to provide real-life feedback for the Swift Archival & Serialization 
(SE-0166) and Swift Encoders (SE-0167) proposals that currently ship in Swift 4 
snapshots.

The context: I'm the author of GRDB.swift [1], a SQLite library that, among 
other goals, aims at easing the conversion between database rows and custom 
models (structs and class hierarchies):

// Sample code
let arthur = Player(name: "Arthur", score: 100)
try arthur.insert(db)
print(arthur.id)

let topPlayers = try Player
.order(Column("score").desc)
.limit(10)
.fetchAll(db) // [Player]

Due to the lack of any introspection in Swift, GRDB currently wants you to 
perform explicit conversion:

struct Player {
var id: Int64?
let name: String
let score: Int
}

extension Player : RowConvertible {
init(row: Row) {
id = row.value(named: "id")
name = row.value(named: "name")
score = row.value(named: "score")
}
}

extension Player : TableMapping, MutablePersistable {
static let databaseTableName = "player"
var persistentDictionary: [String: DatabaseValueConvertible?] {
return ["id": id, "name": name, "score: score]
}
}

That's enough, but that's still too much.

SE-0166 and SE-0167 sound like the promise that some boilerplate code could be 
automatically generated.

Along with JSONDecoder and PListDecoder, let's introduce DatabaseRowDecoder! 
The current state of the work is at 
https://github.com/groue/GRDB.swift/tree/Swift4


At first, it's very satisfying. Decodable keeps some of it promises:

struct Player : RowConvertible, Decodable {
static let databaseTableName = "player"
var id: Int64?
let name: String
let score: Int
}

// Yeah, no more extra code necessary for this to work!
let topPlayers = try Player
.order(Column("score").desc)
.limit(10)
.fetchAll(db)

But there are some issues.


### Issue 1: SE-0166/0167 merge the concepts of keyed objects and values

This is a problem. Let's take this example:

enum Color: Int, Codable {
case blue, green, red
}

struct Flower : RowConvertible, Decodable {
let name: String
let color: Color
}

The way to decode a color comes from KeyedDecodingContainerProtocol:

protocol KeyedDecodingContainerProtocol {
func decode(_ type: T.Type, forKey key: Key) throws -> T 
where T : Decodable
func decodeIfPresent(_ type: T.Type, forKey key: Key) throws 
-> T? where T : Decodable
}

But the ability to decode a Color from a database row comes from the 
DatabaseValueConvertible, which I can't invoke since I can't test if type T 
conforms to this protocol:

struct RowKeyedDecodingContainer: 
KeyedDecodingContainerProtocol {
let row: Row

// Not OK: no support for values
func decode(_ type: T.Type, forKey key: Key) throws -> T 
where T : Decodable {
if   {
let databaseValue: DatabaseValue = 
row.value(named: key.stringValue)
return T.fromDatabaseValue(databaseValue) 
} else { ... }
}
}

So the current state of the Codable library disallow GRDB from supporting value 
properties which are not the trivial Int, Int32, etc. Of course, GRDB itself 
makes it possible, with explicit user code. But we're talking about removing 
boilerplate and relying on the code generation that Codable is blessed with, 
here. We're talking about sharing the immense privilege that Codable is blessed 
with.

However, if I can't decode **values**, I can still decode **complex keyed 
objects** (in this case the row behaves like a hierarchical container - a 
concept already present in GRDB and allows it to consume complex rows like 
results of joins):

struct Book : RowConvertible, Decodable { ... }
struct Author : RowConvertible, Decodable { ... }
struct Pair : RowConvertible, Decodable {
let book: Book
let author: Author
}

struct RowKeyedDecodingContainer: 
KeyedDecodingContainerProtocol {
let row: Row

// OK, support for other decodable objects
func decode(_ type: T.Type, forKey key: Key) throws -> T 
where T : Decodable {
if let scopedRow = row.scoped(on: key.stringValue) {

Re: [swift-evolution] Revisiting SE-0110

2017-05-25 Thread Gwendal Roué via swift-evolution
> Furthermore, this probably comes up most commonly with dictionaries, since 
> they're a sequence of tuples. The element tuple for dictionaries has element 
> labels (key: Key, value: Value), so instead of writing `{ tuple in let (key, 
> value) = tuple; f(key, value) }`, you could use the implicit argument and 
> write `{ f($0.key, $0.value) }`.
> 
> -Joe

I've migrated a project from Swift 3 to Swift 4 (relevant commit: 
https://github.com/groue/GRDB.swift/commit/4f26cbcacf7b783c9c503f2909f2eb03ef7930fe)

Joe is right, dictionaries, as handy as they are, are particularly affected. 
But $0 is hardly a panacea.

What I regret the most with the change is the lost ability to give *relevant 
names* to tuple elements (and sometimes with the forced introduction of a phony 
variable that has no relevant name (like "pair").

Here are below four examples of regressions introduced by SE-0110:

Example 1
-return columns.index { (column, _) in column.lowercased() == 
lowercaseName }
+return columns.index { $0.0.lowercased() == lowercaseName }

Example 2 :
-.map { (mappedColumn, baseColumn) -> (Int, String) in
+.map { (pair) -> (Int, String) in
+let mappedColumn = pair.key
+let baseColumn = pair.value

Example 3 :
-.map { (table, columns) in 
"\(table)(\(columns.sorted().joined(separator: ", ")))" }   
+.map { "\($0.key)(\($0.value.sorted().joined(separator: ", 
")))" }

Example 4 :
-dictionary.first { (column, value) in column.lowercased() == 
orderedColumn.lowercased() }
+dictionary.first { $0.key.lowercased() == 
orderedColumn.lowercased() }

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Revisiting SE-0110

2017-05-25 Thread Gwendal Roué via swift-evolution

> Le 25 mai 2017 à 17:47, Nate Cook via swift-evolution 
>  a écrit :
> 
>> For consistency, the decision was to make closure parameter lists work the 
>> same way as function parameters. Function parameters do not allow 
>> destructuring of arguments in their declaration, so it seemed weird to let 
>> closures do that.
> 
> I have to say that for me, it has never seemed weird at the use site to 
> destructure tuples like that. The only confusion I've ever seen from users is 
> when deconstruction didn't work enough, like if the parameter was (Int, (Int, 
> Int)) and you couldn't destructure the nested tuple.

I even suggest that tuple destructuring gets more consideration.

That is because without restructuring, many closures that could be written as a 
single line have to be written with several lines (in order to explicitly 
destructure input tuples, as in the sample code provided by the OP):

+self.forEach { (arg) in
+let (keyItem, valueItem) = arg

Unfortunately, multiline closures are less nice than single line closures: 
multiline closures can't avoid the `return` keyword. And multiline closures 
have downgraded type inference:

func f(_ closure: () -> T) -> T { return closure() }

// Yeah!
f { 1 }

// Meh: unable to infer complex closure return type; add explicit type to 
disambiguate
f {
let x = 1
return x
}

Of course, the type inference problem above could be fixed independently of 
tuple destructuring. But it looks like it is difficult to implement: see Jordan 
Rose's comment in https://bugs.swift.org/browse/SR-1570 
 which links to 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002583.html
 
.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Improve String Literals

2017-05-16 Thread Gwendal Roué via swift-evolution

> Le 16 mai 2017 à 17:31, Xiaodi Wu  a écrit :
> 
> On Tue, May 16, 2017 at 8:01 AM, Gwendal Roué  > wrote:
> Xiaodi Wu, your opposition has been recorded. You don't buy the Motivation 
> section. Other people here do, definitely.
> 
> I think you make some insightful comments below. But again, to clarify, I am 
> not voicing support or opposition to the ideas themselves.
> 

> I am objecting that this pitch contains mostly ideas discussed previously and 
> amply, and which have been formally considered and rejected. _Whether or not 
> you buy the motivation for doing so_, it is--as a matter of etiquette if 
> nothing else--not appropriate to make repeated pitches every few weeks. As I 
> wrote earlier, few (if any) people would volunteer their time and effort to 
> bring up thoughtful points about an upcoming decision if the same discussion 
> is simply going to repeat itself two weeks after the decision has been made.

You did very kindly quote the rejection reasons. This is a work effort that the 
proposal authors should take seriously. Everybody knows how difficult it is to 
find a past message in swift-evolution :-)

The core team has left some room for improvement. They talk about non-explicit 
"subtleties", and future "additive features". I don't see any etiquette 
violation here.

> Therefore, I am claiming that even if some believe that this is the best idea 
> ever conceived, and even if minor changes to the rationale or design are 
> made, it should as a matter of principle not be the subject of further 
> discussion on this list _because it has already been rejected_. To do so 
> would undermine accepted norms which are important to encourage thoughtful 
> and timely participation.

Like you, I want any further work to build on top of SE-0168, which has been 
accepted. There is no matter for a fileprivate drama here. The new proposal 
needs some focus: we should give some time to the authors.

Gwendal

> 
> 
> 
> > Le 15 mai 2017 à 23:52, Xiaodi Wu via swift-evolution 
> > > a écrit :
> >
> > I'm quite sure it means this: As with all parts of Swift, a decision can be 
> > re-considered if implementation difficulties are found, or if new insights 
> > arise from extended use. Because these features are additive, rejecting 
> > them now does not mean that source compatibility requirements would make 
> > such re-consideration impossible--if they are to be re-considered in the 
> > future. Until such time as a fit justification is found to bring the 
> > current decision into question, the decision of the core team is that these 
> > proposed features are rejected from inclusion in Swift.
> > On Mon, May 15, 2017 at 16:28 David Hart  > > wrote:
> >> On 14 May 2017, at 03:55, Xiaodi Wu  >> > wrote:
> >>
> >> On Sat, May 13, 2017 at 1:42 AM, David Hart  >> > wrote:
> >>
> >>> On 12 May 2017, at 23:14, Xiaodi Wu  >>> > wrote:
> >>>
> >>> I feel like a broken record: Of the three proposed components of the 
> >>> proposed solution, two were amply considered by the community and the 
> >>> core team in SE-0168. The decision has already been made _not_ to 
> >>> implement these ideas at this time.
> >>
> >> Can you provide me with quote from the Core Team that it should not be 
> >> implemented at this time? I have troubles finding it.
> >>
> >>> Significant defects discovered after the fact during implementation or 
> >>> new insights after extensive usage can prompt revisiting the decision, 
> >>> but that is not the case here: implementation did not require further 
> >>> clarification and the feature has only just landed on master. We simply 
> >>> cannot revisit topics willy-nilly. The process simply cannot work that 
> >>> way: few have the time and energy to offer their fullest consideration 
> >>> the first time round, and no one would be willing to do that if it means 
> >>> that the same topic will be revisited one month later.
> >>
> >> The concerns summarised in this proposal were only heavily discussed after 
> >> the acceptance of multi-line strings. Therefore, there is a great chance 
> >> that they were not discussed by the Core Team. We feel obliged to put this 
> >> proposal forward to formalise those issues.
> >>
> >>
> >> [1]
> >>
> >> Your draft proposes to '[d]ivorce the `"""` delimiter from [...] 
> >> multi-line syntax' in order to allow `"""long strings"""` to be valid 
> >> syntax.
> >>
> >> SE-0168 proposed 'a single simple syntax for inclusion: """long 
> >> strings"""`, explicitly permitting that syntax.
> >>
> >> The core team, after considering SE-0168, deliberately rejected that 
> >> feature for Swift 4. They wrote that they 'acknowledge[] 

Re: [swift-evolution] [Pitch] Improve String Literals

2017-05-16 Thread Gwendal Roué via swift-evolution

> Le 16 mai 2017 à 16:39, David Hart  a écrit :
> 
>> 
>> On 16 May 2017, at 15:01, Gwendal Roué  wrote:
>> 
>> Xiaodi Wu, your opposition has been recorded. You don't buy the Motivation 
>> section. Other people here do, definitely.
>> 
>>> Divorce the """ delimiter from the multi-line syntax and have them only 
>>> support unescaped double-quotes
>> 
>> This means support for:
>> 
>>  let x = "
>>  foo
>>  bar
>>  "
>> 
>> This one is unexpected, and not requested by many users. Does it bring much?
>> 
>> I wonder whether this addition was introduced in order to make the proposal 
>> as consistent as possible, and prevent some criticisms. It has proven 
>> pointless. I suggest forgetting about pleasing people who don't want to be 
>> pleased, and to reconsider this "divorce" section. Consistency is not the 
>> main point. The main point is UX. This means easing the daily life of code 
>> writers, and easing the daily life of code readers (this involves being 
>> careful which text editors and code prettyfiers are unable to handle the 
>> proposal).
> 
> Well, one of the issues I have with the status-quo is that ""” has two 
> meanings (support for “ without escaping and multi-line support), which 
> causes consistency issues when you want to support “"” one-liners. I prefer a 
> model where features can be orthogonally composed: hence “”” for escaping, 
> and newlines around delimiters to signify multi-lines. Support for 
> multi-lines with “ delimiters is a natural consequence of that model: so why 
> disallow it?

Because this pollutes your proposal. Instead of making it simpler, it makes it 
more complex. You force the reader to think about the consequences of the 
composition of orthogonal topics, and sort between useful ones that improve 
life, and useless ones that pollute the mind, the time of stack overflow 
reviewers, and the future Swift String tutorials. Do you want to give more work 
to the linters and style fashionistas who love those kind of holes in language?

If the two following literals are equivalent, I suggest your forget about the 
first, since it brings nothing on top of SE-0168:

"
foo
bar
"

"""
foo
bar
"""

The proposal argument for it is weak:

> They gain support for " delimiters, which has the nice advantage of saving a 
> few characters in multi-line strings which are known to never contain 
> double-quotes:

"never" is a smelly word: real programs evolve, and good diffs are local diffs:

 // bad diff
- "
+ """
...
...
...
- “Yes”, he said.
+ "Yes", he said
...
...
...
-"
+"""

> Support escaping newlines in multi-line strings with a trailing \
>> 
>> Great. That's the main request, unless I'm misled: split long literals 
>> accross multiple lines. 
>> 
>> Now that Xiaodi Wu has found them, the core team questions about the 
>> trailing backslash should be addressed in more details.
> 
> Sure:

Cool. Hard-wrapping is the meat.

> acknowledge[] that single-line triple quoted strings have other uses in other 
> languages, [...] but supporting that alongside the indentation-stripping 
> behavior leads to a lot of subtlety, and there could be other solutions to 
> the escaping problem down the line, such as raw strings.
> 
> I’m not sure what subtleties they are referring to, so I don’t know how to 
> address those fears. And I’m not convinced raw strings are the right solution 
> because I’d like to retain escaping and string interpolation even in those 
> one-liners. Raw strings are interesting, I just don’t see them as a solution 
> for triple-quoted one-liners.

This is about "single-line triple quoted strings", not trailing backslash and 
hard-wrapping. Still, more about that below, in the section about C inspiration.

> 
> [d]iscussion on the list raised the idea of allowing a line to end with \ to 
> "escape" the newline and elide it from the value of the literal.' They 
> deliberately rejected that feature for Swift 4, reasoning that '[they] had 
> concerns about only allowing that inside multi-line literals and felt that 
> that could also be considered later as an additive feature.
> 
> This last one confused me. In what else than multi-line literals could we 
> escape newlines? Be definition, if you don’t escape it, it’s a newline and 
> your are by definition in a multi-line literal.

This means that SE-0168 was about triple-quoted literals, and that the core 
team felt uneasy supporting trailing backslash for triple-quoted literals only.

If you intend to provide hard-wrapping with the trailing backslash, your 
proposal must support it in single-quoted literals also.

> 
>>> Adopt the C/Objective-C syntax that concatenates single-line strings
>> 
>> A battle-tested solution. Doesn't it look redundant with both the "divorce" 
>> and the trailing backslash?
> 
> It may look redundant but I see them supporting two different purposes:
> 
>   • 

Re: [swift-evolution] [Pitch] Improve String Literals

2017-05-16 Thread Gwendal Roué via swift-evolution
I 
> Le 16 mai 2017 à 15:39, Adrian Zubarev  a 
> écrit :
> 
> Well the main complain I had during the discussion with David was, that I 
> previously had such a model in mind which will break up long double-quoted 
> string literals. Please look up this design in the alternative section of our 
> proposal. By adding slightly redundant multi-line string literal syntax for 
> consistency renders that complain to zero. By allowing:
> 
> "
> SELECT 'name'
> FROM 'people'
> WHERE age > 20
> "
> it becomes clear that the trailing backslash should only be used for escaping 
> new line injection in multi-line string literals, but not for breaking up 
> long strings (similar to other languages like JavaScript):
> 
> "SELECT 'name' \
> FROM 'people' \
> WHERE age > 20"
> This also lets us adopt the C/Objective-C syntax instead. 
> 
> "SELECT 'name' "
> "FROM 'people' "
> "WHERE age > 20"

SE-0168 had one focus: long literals that contain newline characters. And it 
does a great job addressing it.

SE-0168 does not talk about hard wrapping. Make this the only focus of your 
proposal. Simplify your motivation section. Strip away redundant solutions. 
Become expert in hard wrapping, and please give us one correct solution. Don't 
forget to talk about trailing/leading newlines and text editor grammars, 
because those were two important discussion topics for SE-0168.

Gwendal

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Improve String Literals

2017-05-16 Thread Gwendal Roué via swift-evolution
Xiaodi Wu, your opposition has been recorded. You don't buy the Motivation 
section. Other people here do, definitely.

> Divorce the """ delimiter from the multi-line syntax and have them only 
> support unescaped double-quotes

This means support for:

let x = "
foo
bar
"

This one is unexpected, and not requested by many users. Does it bring much?

I wonder whether this addition was introduced in order to make the proposal as 
consistent as possible, and prevent some criticisms. It has proven pointless. I 
suggest forgetting about pleasing people who don't want to be pleased, and to 
reconsider this "divorce" section. Consistency is not the main point. The main 
point is UX. This means easing the daily life of code writers, and easing the 
daily life of code readers (this involves being careful which text editors and 
code prettyfiers are unable to handle the proposal).

> Support escaping newlines in multi-line strings with a trailing \

Great. That's the main request, unless I'm misled: split long literals accross 
multiple lines. 

Now that Xiaodi Wu has found them, the core team questions about the trailing 
backslash should be addressed in more details.

> Adopt the C/Objective-C syntax that concatenates single-line strings

A battle-tested solution. Doesn't it look redundant with both the "divorce" and 
the trailing backslash?

Last, the proposal contains literals without leading and trailing newlines. I 
thought those were not supported by SE-0168. If this is the case, we need more 
detail here, so that the proposal is rock solid, and the core team confident it 
deserves consideration. A little more work, please :-)

Thanks,
Gwendal Roué



> Le 15 mai 2017 à 23:52, Xiaodi Wu via swift-evolution 
>  a écrit :
> 
> I'm quite sure it means this: As with all parts of Swift, a decision can be 
> re-considered if implementation difficulties are found, or if new insights 
> arise from extended use. Because these features are additive, rejecting them 
> now does not mean that source compatibility requirements would make such 
> re-consideration impossible--if they are to be re-considered in the future. 
> Until such time as a fit justification is found to bring the current decision 
> into question, the decision of the core team is that these proposed features 
> are rejected from inclusion in Swift.
> On Mon, May 15, 2017 at 16:28 David Hart  wrote:
>> On 14 May 2017, at 03:55, Xiaodi Wu  wrote:
>> 
>> On Sat, May 13, 2017 at 1:42 AM, David Hart  wrote:
>> 
>>> On 12 May 2017, at 23:14, Xiaodi Wu  wrote:
>>> 
>>> I feel like a broken record: Of the three proposed components of the 
>>> proposed solution, two were amply considered by the community and the core 
>>> team in SE-0168. The decision has already been made _not_ to implement 
>>> these ideas at this time.
>> 
>> Can you provide me with quote from the Core Team that it should not be 
>> implemented at this time? I have troubles finding it.
>> 
>>> Significant defects discovered after the fact during implementation or new 
>>> insights after extensive usage can prompt revisiting the decision, but that 
>>> is not the case here: implementation did not require further clarification 
>>> and the feature has only just landed on master. We simply cannot revisit 
>>> topics willy-nilly. The process simply cannot work that way: few have the 
>>> time and energy to offer their fullest consideration the first time round, 
>>> and no one would be willing to do that if it means that the same topic will 
>>> be revisited one month later.
>> 
>> The concerns summarised in this proposal were only heavily discussed after 
>> the acceptance of multi-line strings. Therefore, there is a great chance 
>> that they were not discussed by the Core Team. We feel obliged to put this 
>> proposal forward to formalise those issues.
>> 
>> 
>> [1]
>> 
>> Your draft proposes to '[d]ivorce the `"""` delimiter from [...] multi-line 
>> syntax' in order to allow `"""long strings"""` to be valid syntax.
>> 
>> SE-0168 proposed 'a single simple syntax for inclusion: """long strings"""`, 
>> explicitly permitting that syntax.
>> 
>> The core team, after considering SE-0168, deliberately rejected that feature 
>> for Swift 4. They wrote that they 'acknowledge[] that single-line triple 
>> quoted strings have other uses in other languages, [...] but supporting that 
>> alongside the indentation-stripping behavior leads to a lot of subtlety, and 
>> there could be other solutions to the escaping problem down the line, such 
>> as raw strings.' They concluded that: 'If nothing else, single-line triple 
>> quoted strings can be considered later as an additive feature.' 
>> 
>> [2]
>> 
>> Your draft proposes to 'support escaping newlines in multi-line strings with 
>> a trailing `\`'.
>> 
>> The core team, after considering 

Re: [swift-evolution] [Review] SE-0179: Swift `run` Command

2017-05-16 Thread Gwendal Roué via swift-evolution

> Le 16 mai 2017 à 02:09, Daniel Dunbar via swift-evolution 
>  a écrit :
> 
> Hello Swift community,
> 
> The review of SE-0179: Swift `run` Command begins now and runs through May 
> 25th, 2017.
> 
> The proposal is available here:
> 
>   
> https://github.com/apple/swift-evolution/blob/master/proposals/0179-swift-run-command.md
>  
> 
> What is your evaluation of the proposal?
Good +1

It's not quite clear if `swift run --configuration release` runs the release 
build, but I'll assume it's true.

The considered alternative of symlinking to the latest build folder looks like 
an opportunity for bugs, as most stateful command-line interfaces: I'm not in 
favor for it.
> Is the problem being addressed significant enough to warrant a change to 
> Swift?
Yes, since the inner layout of the build folder is about to depend on the 
platform. 
> Does this proposal fit well with the feel and direction of Swift?
Sure
> If you have used other languages or libraries with a similar feature, how do 
> you feel that this proposal compares to those?
`swift run` has a taste of scripting language :-)
> How much effort did you put into your review? A glance, a quick reading, or 
> an in-depth study?
A read of the proposal.

Gwendal Roué

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


  1   2   >