Re: [swift-evolution] [Draft] Hasher & HashVisitable

2017-03-13 Thread Károly Lőrentey via swift-evolution


>> On 2017. Mar 14., at 2:44, Xiaodi Wu via swift-evolution 
>>  wrote:
>> 
>> On Mon, Mar 13, 2017 at 8:30 PM, Tony Allevato via swift-evolution 
>>  wrote:
>> Adding the list back to this reply because I don't believe you meant to 
>> reply only to me, and I think it's an important discussion to have :)
>> 
>> 
>> On Mon, Mar 13, 2017 at 4:32 PM Vincent Esche 
>>  wrote:
>> Automatic generation of Hashable implementation code only "solves" the 
>> problem of having to implement `var hashValue`.
>> It however only works for some types. By no means for all.
>> 
>> Certainly, and I never suggested that it would work for every case. I was 
>> responding to Sean's point that the compiler should be able to do "good 
>> enough" in the common cases and I offered a way that that can be achieved.
>> 
>> 
>> Take this hypothetical implementation of a HSB color:
>> 
>> struct Color {
>>  let hue: UInt8
>>  let saturation: UInt8
>>  let brightness: UInt8
>> }
>> 
>> Let the semantic of this type be this:
>> Any two colors with a `brightness` of `0` are to be considered equal 
>> regardless of their respective `hue` or `saturation`. At night all cats are 
>> gray. 
>> 
>> An auto-generated conformance impl for `Color` would most likely be wrong 
>> afaict.
>> And those kind of semantics are everywhere.
>> 
>> Of course, and in those cases, you wouldn't want to use an auto-derived 
>> Equatable or Hashable implementation. Those kinds of semantics are 
>> "everywhere" for certain definitions of "everywhere", but similarly, 
>> semantics where the hash value of a thing can be determined simply via 
>> combination of the hash values of its components are also "everywhere".
>> 
>> I wouldn't suggest that auto-deriving Hashable solves *all* problems, and 
>> similarly, your proposal doesn't help in the situation you described either. 
>> Your API provides a different way to mix the hue, saturation, and brightness 
>> components in an implementation of hashValue, but it doesn't force the user 
>> to mix them *correctly* (by excluding hue/saturation if brightness is zero).
>> 
>> So in both cases, users still have to provide custom implementations of == 
>> and hashValue. But without auto-deriving, users have to provide them even 
>> for the cases where the auto-derived implementation *would have been 
>> correct.*  Auto-deriving is about reducing the number of types that need to 
>> have custom implementations, thereby reducing the chance that a user will do 
>> it wrong.
>> 
>> When considering a type with auto-derived Hashable and Equatable, there are 
>> two ways it can be wrong:
>> 
>> 1) The auto-generated implementations of both == and hashValue don't honor 
>> the semantic contract of the type (for example, don't ignore brightness when 
>> it's zero).
>> 2) The user overrides the auto-generated implementation of one of 
>> ==/hashValue but not both, and violates the contracts between them.
>> 
>> For #1, yes, the compiler generated an incorrect implementation in that 
>> case. However, I would argue it's the developer's responsibility to fix it 
>> by overriding it if they need different semantics. As I mentioned above, 
>> without derivation, the developer could still implement it incorrectly, just 
>> as they could with your API.
>> 
>> For #2, this could be solved by requiring users to override both if they 
>> override one of them. Now they're back in the same situation as #1—they 
>> either did it right, or they did it wrong.
>> 
>>  
>> 
>> Auto-generation clearly is no panacea when it comes to hashing. Especially 
>> if it leads to invalid and unsafe default implementations.
>> 
>> Auto-deriving cannot produce "unsafe" implementations because it's defined 
>> in terms of a function operating over the hash values of its components. It 
>> can produce an implementation that does not match the intended semantics of 
>> the class that are defined outside of its component values, but that's not 
>> the compiler's job to decide; it's up to the user to provide those.
>> 
>> Regarding unsafety, it's worth noting that your ContiguouslyHashable 
>> protocol is inherently unsafe and fragile. Imagine that a user implements a 
>> struct that they make conform to ContiguouslyHashable because at the time, 
>> it's a simple fixed layout type with primitive fields. If they take that 
>> type and add a new field to it that isn't contiguously hashable (say, a 
>> class reference) and they forget to replace the ContiguouslyHashable 
>> conformance, they now have a very broken type, and that behavior isn't 
>> caught until *runtime* when things go wrong.
>> 
>> At least with derived conformances, in that situation the *compiler* would 
>> see that the type was no longer hashable and emit an error when it's used 
>> anywhere that Hashable/hashValue was expected.
>> 
>> So if safety is your motivation, ContiguouslyHashable kind of 

Re: [swift-evolution] [Draft] Hasher & HashVisitable

2017-03-13 Thread Károly Lőrentey via swift-evolution
I think standardizing on a “correct” way to combine multiple hashable 
components into a single hash is an important step toward automating it. 
Visitor-based hashing simplifies the implementation of Hashable by essentially 
making it into a simple decision about which components to include in the hash. 
The details of how to mix bits into a single fixed-size bitstring is abstracted 
away into the hasher, so hashing becomes as easy to implement as the equality 
operator.

Swift already includes very limited support for automated generation of 
Equatable and Hashable implementations (for basic enum types, at least). Having 
this new form of hashing would make it a little easier to extend this mechanism 
to cover other cases—at least, a proposal for that wouldn’t need to invent and 
describe a solution for combining hash values.

Cheers,
Karoly

> On 2017-03-13, at 18:54, Sean Heber via swift-evolution 
>  wrote:
> 
> I’m dumb when it comes to proper hashing, but it’s such a tediously common 
> thing in my experience to need to add Hashable to some kind of a struct so I 
> can stash it in a set or use it as a dictionary key. Is there really no way 
> to make this all more automatic? I have to be honest - this proposal seems 
> *harder* to understand than the way it works now. Of course the easiest would 
> be if the language could just do this “good enough" for me using reflection 
> or whatever and if I really did run into a problem where I wanted to do this 
> myself, I could override something.
> 
> Perfect is the enemy of good.
> 
> l8r
> Sean
> 
> 
>> On Mar 13, 2017, at 10:38 AM, Vincent Esche via swift-evolution 
>>  wrote:
>> 
>> Hi there,
>> 
>> I've written up a proposal for an overhaul/replacement of the Hashable 
>> protocol and would love to hear your feedback on it!
>> 
>> Rendered | Blog Post
>> 
>> Cheers,
>> Vincent
>> 
>> Ps: I'd like to thank David Hart (@hartbit) for his great editorial feedback 
>> on this proposal. 
>> 
>> HashVisitable
>> 
>>  • Proposal: SE-
>>  • Authors: Vincent Esche
>>  • Review Manager: TBD
>>  • Status: Awaiting review
>> Introduction
>> 
>> Replace the Hashable protocol by two new procotols (Hasher and 
>> HashVisitable) to improve safety, versatility and learnability.
>> 
>> Motivation
>> 
>> Implementing Hashable is difficult and the consequences if not done well 
>> have dire performance and safety repercussions.
>> 
>> The documentation of Hashable lists a sample implementation of var hashValue:
>> 
>> /// A point in an x-y coordinate system.
>> struct GridPoint {
>>var x: Int
>>var y: Int
>> }
>> 
>> extension GridPoint: Hashable {
>>var hashValue: Int {
>>return x.hashValue ^ y.hashValue
>>}
>> 
>>static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
>>return lhs.x == rhs.x && lhs.y == rhs.y
>>}
>> }
>> 
>> Calculating the hashes of all GridPoints (given the above implementation) on 
>> a 1000 × 1000 grid …
>> 
>> let (width, height) = (1000, 1000)
>> let total = width * height
>> var hashes = Set()
>> for x in 0..>for y in 0..>hashes.insert(GridPoint(x: x, y: y).hashValue)
>>}
>> }
>> print("\(hashes.count) unique hashes out of a total of \(total).")
>> 
>> … results in just 1024 unique hash values for 1_000_000 unique values.
>> 
>> In other words: The recommended implementation causes 99.9% of values to 
>> trigger a hash collision.
>> 
>> Out of those 1_000_000 values the median collision count was 976 with min 
>> and max being 976 and 1000respectively.
>> 
>> The collision rate will have negative impact in algorithms which heavily use 
>> hashValue like the ones in Dictionaryand Set. Furthermore, it increases the 
>> vulnerability to DDOS attacks when exposed to the web.
>> 
>> If even the official Swift documentation gets the implementation of 
>> hashValue wrong, then who is to expect the average Swift programmer to do 
>> any better?
>> 
>> In contrast, running the same snippet using HashVisitable and the 
>> semi-secure Fnv1aHash (see below) results in zero collisions!
>> 
>> Finally, the design of the Hashable protocol forces the use of one 
>> implementation without the possibility of switching between multiple hashing 
>> algorithms.
>> 
>> Proposed solution
>> 
>> Instead of coupling the hashing algorithm with each and every Swift type, we 
>> should provide a hashing API based on the visitor-pattern. By freeing 
>> application developers from the burden of having to implement hashing 
>> algorithms, the Standard Library can provide default ones which fulfill 
>> collision, performance and security goals. Furthermore, it would allow 
>> developers to swap to different algorithms based on the use case.
>> 
>> Detailed design
>> 
>> The proposal deprecates the Hashable protocol and introduces the following 
>> two:
>> 
>> protocol Hasher
>> {
>> 
>> mutating func finish() -> Int
>> 
>> 
>> mutating func 

Re: [swift-evolution] [Draft] Hasher & HashVisitable

2017-03-13 Thread Károly Lőrentey via swift-evolution
Yes please! I’ve a package on GitHub to implement roughly the same thing. I’ve 
been happily using it for months now, and I wouldn’t ever write a hashValue 
implementation by hand again.

https://github.com/lorentey/SipHash 

I think the fact that we’ve both come up with essentially the same API is an 
interesting data point; it definitely underlines the need for a better Hashable 
protocol.

My comments:

* In an ideal world, this would be a replacement for Hashable, not a protocol 
with a different name. Once visitor-based hashing becomes available, nobody 
should implement a hashValue property.

* All standard Hashable types in standard library should implement the new hash 
function directly, rather than relying on the default implementation.

* Why is the HashVisitable.hash a generic function? Hasher could just as well 
be a concrete type defined in stdlib. Making it generic may have some 
performance implications.

* I find that I prefer to hash components by calling a mutating method on the 
hasher, rather than directly calling the components' hash implementations. 
Putting the hasher first is much more readable to me, primarily because it gets 
rid of all the distracting  It also makes it possible to find slightly 
better names, eliminating the repetitiveness of "foo.hash()":

extension GridPoint: SipHashable {
func appendHashes(to hasher: inout
 SipHasher) {
 hasher.append(x)
 hasher.append(y)
}
}

* I suggest using SipHash instead of FNV-1a. The standard library already 
contains an implementation for SipHash, as undocumented internal API, complete 
with a note that it should be made public. AFAICR, it is currently only used 
for String hashing, but it would be very much worth making it universal. 
(Accomodating SipHash's random key is one reason why hashValue’s documentation 
explicitly notes that its value is "not guaranteed to be equal across different 
executions of your program.”)

* ContiguouslyHashable seems like an unsafe construct to me. It is quite 
dangerous to base hashing on the raw byte sequence underlying a value: for 
example, struct values may include uninitialized gaps between some of their 
stored properties due to alignment constraints. So two otherwise identical 
values may very well have different in-memory representations. Therefore, I 
suggest ContiguouslyHashable should be removed from the proposal. Swift 
programmers who know what they’re doing would still be able to call 
withUnsafeBytes(of:) when they want to, but regular schmoes like myself will 
not be tempted to shoot themselves in the foot by using it inappropriately.

Cheers,
Karoly


> On 2017-03-13, at 16:38, Vincent Esche via swift-evolution 
>  wrote:
> 
> Hi there,
> 
> I've written up a proposal for an overhaul/replacement of the Hashable 
> protocol and would love to hear your feedback on it!
> 
> Rendered 
>  | Blog 
> Post 
> 
> Cheers,
> Vincent
> 
> Ps: I'd like to thank David Hart (@hartbit) for his great editorial feedback 
> on this proposal. 
> 
> HashVisitable
> 
> Proposal: SE- 
> Authors: Vincent Esche 
> Review Manager: TBD
> Status: Awaiting review
>  
> Introduction
> 
> Replace the Hashable protocol by two new procotols (Hasher and HashVisitable) 
> to improve safety, versatility and learnability.
> 
>  
> Motivation
> 
> Implementing Hashable is difficult and the consequences if not done well have 
> dire performance and safety repercussions.
> 
> The documentation of Hashable lists a sample implementation 
>  of var hashValue:
> 
> /// A point in an x-y coordinate system.
> struct GridPoint {
> var x: Int
> var y: Int
> }
> 
> extension GridPoint: Hashable {
> var hashValue: Int {
> return x.hashValue ^ y.hashValue
> }
> 
> static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
> return lhs.x == rhs.x && lhs.y == rhs.y
> }
> }
> Calculating the hashes of all GridPoints (given the above implementation) on 
> a 1000 × 1000 grid …
> 
> let (width, height) = (1000, 1000)
> let total = width * height
> var hashes = Set()
> for x in 0.. for y in 0.. hashes.insert(GridPoint(x: x, y: y).hashValue)
> }
> }
> print("\(hashes.count) unique hashes out of a total of \(total).")
> … results in just 1024 unique hash values for 1_000_000 unique values.
> 
> In other words: The recommended implementation causes 99.9% of values to 
> trigger a hash collision.
> 
> Out of those 1_000_000 values the median collision count was 976 with 

Re: [swift-evolution] Sort Descriptors

2016-11-03 Thread Károly Lőrentey via swift-evolution

> On 2016-11-03, at 19:39, Chris Eidhof via swift-evolution 
>  wrote:
> I was wondering if there's any interest in adding Swift-like sort descriptors 
> to the language. Currently, we have `sort` and `sorted`, which take a 
> function of type `(A, A) -> Bool`. Foundation has `NSSortDescriptor`, which 
> corresponds more to `(A, A) -> ComparisonResult`. NSSortDescriptor is a lot 
> easier to work with than Swift's stdlib way: it's more declarative, it's easy 
> to combine multiple sort descriptors into one (e.g. sort by last name, then 
> sort by first name, and so on). However, NSSortDescriptor uses runtime 
> programming, and is not very typesafe.
> 
> We could do a lot better in Swift. There are at least a few possibilities:
> 
> typealias SortDescriptor = (A, A) -> Bool
> typealias SortDescriptor = (A, A) -> ComparisonResult
> struct SortDescriptor { let compare: (A, A) -> Bool }
> struct SortDescriptor { let compare: (A, A) -> ComparisonResult }
> 
> I've experimented a bit with this, and it seems like the `struct` based 
> version with `ComparisonResult` is quite nice, because then we can add 
> methods/properties on it (e.g. to reverse a sort descriptor, or to return a 
> `Bool` instead of a `ComparisonResult`). 
> 
> My "SortDescriptor" could also be called "Comparator", and in fact, there is 
> already something like that in Foundation (of type (Any,Any) -> Bool).
> 
> Is there interest in adding support for this to the stdlib? If yes, is anyone 
> interested in writing a good proposal together?

There is definitely interest!

In fact, Robert Widmann, Jaden Geller, Harlan Haskins and Pyry Jahkola had 
previously worked on a draft proposal to clean up Comparable's semantics, and 
to move from a < + == model to a single comparator operator called "<=>”. Sadly 
this happened just before Swift 3 deadline, and the proposal was lost in the 
noise.

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025466.html
 

https://github.com/pyrtsa/swift-evolution/blob/ca89e7b3a1dffc99baa695a03544fcba75afd0f3/proposals/-formalized-ordering.md
 


The new sort functions are included under Future Directions above, but it would 
also be possible to add them before resolving the general case. 

If this is a good time to reopen this discussion, then I’m all for it! 

-- 
Karoly

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


Re: [swift-evolution] [Proposal Draft] Provide Custom Collections for Dictionary Keys and Values

2016-10-12 Thread Károly Lőrentey via swift-evolution
I believe the implementation of efficient in-place mutation is very explicit in 
the code -- it is done by implementing DictionaryValue’s subscript using a 
special “mutableAddressWithNativeOwner” addressor instead of a normal setter. 

https://github.com/natecook1000/swift/blob/ed95aec4a20589a3b9c131f43444aa33705343cc/stdlib/public/core/HashedCollections.swift.gyb#L2169-L2173
 


AFAICU this would also work if DictionaryValue was a reference type. 

Unfortunately, as far as I know, these addressors aren’t available outside 
stdlib, so custom collections cannot currently implement such mutable views 
(including mutable ranges) in a similarly efficient way. 

We can, however, approximate a similar effect outside of stdlib by designing 
closure-based APIs like `mydict.withValues { values in values[i] = 42 }`, in 
which the collection moves its storage to the view while the closure is 
executing (temporarily making its own contents disappear / appear invalid). The 
syntax and underlying mental model is perhaps not as nice, but (assuming the 
compiler is able to optimize away the nonescaping closure) we can achieve some 
of the performance benefits. 

> On 2016-10-12, at 19:17, plx via swift-evolution  
> wrote:
> 
> Thanks for the quick reply; given that I’m quite wrong about the important 
> mechanics I rescind my criticisms.
> 
> I will say I care about this enough to reply because the inability to do 
> in-place mutation of dictionary values has been an incredibly frustrating 
> limitation and I’d just assumed the situation with slices/views would 
> necessarily have similar issues for similar reasons…but glad to learn it’s 
> not what I thought!
> 
> That said, I think efficient in-place mutation is too important to only 
> expose so implicitly (seemingly due to the compiler eliding the 
> otherwise-expected retain increments when the view is sufficiently 
> “transient”…which seems like you perhaps can’t have an "in-place capable" 
> view that’s implemented as a class, I’d think).
> 
> But none of this impacts my change to being in support for the proposal.
> 
>> On Oct 12, 2016, at 10:07 AM, Nate Cook > > wrote:
>> 
>> 
>>> On Oct 12, 2016, at 9:32 AM, plx via swift-evolution 
>>> > wrote:
>>> 
>>> The issue addressed is real; I’m not sure this is the best approach. 
>>> 
>>> In particular, unless I’m missing something obvious, the ownership strategy 
>>> here would have to be:
>>> 
>>> - `DictionaryKeys` and `DictionaryValues` would each induce the expected +1 
>>> retain on the underlying storage
>>> - `DictionaryValues`’s mutations avoid triggering COW on the underlying 
>>> storage by skipping the usual ownership check
>>> 
>>> …as otherwise it’s unclear how you’d do those in-place mutations (and this 
>>> seems to be how the implementation works...is that correct?).
>> 
>> That's not quite right—when you access these views through the dictionary, 
>> they do not increment the storage retain count. This is the way slicing and 
>> views currently work on other mutable types. For example, when you reverse a 
>> slice of an array in-place, the slice doesn't get its own duplicate storage:
>> 
>> var a = Array(1...10)
>> a[0..<5].reverse()
>> a == [5, 4, 3, 2, 1, 6, 7, 8, 9, 10]
>> 
>> However, if you create a new variable out of the slice and reverse that, the 
>> slice does get its own storage:
>> 
>> var b = Array(1...10)
>> var bSlice = b[0..<5]
>> bSlice.reverse()
>> bSlice == [5, 4, 3, 2, 1]
>> b == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> 
>> Strings and their views work the same way:
>> 
>> var s = "abcdefg"
>> s.characters.append("H")   // storage updated in place
>> s == "abcdefgH"
>> 
>> var sChars = s.characters  // no copy yet
>> sChars.removeLast() // sChars gets its own copy before the mutation
>> s == "abcdefgH"
>> String(sChars) == "abcdefg"
>> 
>> var t = s   // no copy yet
>> t.characters.removeLast()  // t gets a new copy here
>> s == "abcdefgH"
>> t == "abcdefg"
>> 
>> I don't know the name of the compiler feature that enables this, but it's a 
>> critical part of the way views and slices work.
>> 
>>> With that design, it seems like you’d wind up allowing things like the 
>>> below:
>>> 
>>>   // example A
>>>   let foo = [ “abc”: [1,2,3], “efg”: [4,5,6] ]
>>>   let bar = foo // shared storage, no COW
>>>   foo.values[foo.index(of: “abc”)!].append(789) // update shared storage, 
>>> no COW
>>> 
>>>   // shared storage mutated,
>>>   // despite (a) both being `let` and (b) only foo.values getting touched
>>>   foo[“abc”] // [1, 2, 3, 789]
>>>   bar[“abc”] // [1, 2, 3, 789]
>> 
>> Example A isn't allowed—if foo and bar are both immutable, both of their 
>> `values` collections are also immutable, so there's no 

Re: [swift-evolution] [Proposal Draft] Provide Custom Collections for Dictionary Keys and Values

2016-10-12 Thread Károly Lőrentey via swift-evolution
Ah, I see plx has already brought this up. So this is a bug in the 
implementation, and (presumably) DictionaryValue’s mutable subscript addressor 
is supposed to take care of COW semantics without introducing needless copying.

(It’s too bad we aren’t supposed to use these magical addressors outside 
stdlib; the same issues tend to come up in custom collections, too.) :-(


> On 2016-10-12, at 17:58, Károly Lőrentey via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> I think this is a lovely approach to solving this API design problem.
> 
> One thing I don’t quite understand yet is how these kinds of mutable views 
> interact with copy on write semantics. COW rules can be subtle, and these 
> views seem to put an extra twist on top that seems hard to understand/explain.
> 
> I would expect DictionaryValues to behave like a separate copy of the 
> dictionary:
> 
>var dict = [“foo”: 1, “bar”: 2]
>let i = dict.keys.index(of: “foo”)!
>var values = dict.values
>values[i] = 42 // COW copy
>print(dict[“foo”]) // => 1
>dict.values = values   // Original storage is released
>print(dict[“foo”]) // => 42
> 
> Given that `values` contains a strong reference to the storage, I was curious 
> to find out how this copy is elided when we write `dict.values[i] = 42`. So I 
> tried building your branch, and I found that mutating `values` has an 
> immediate effect on the dictionary as well:
> 
>let dict = [“foo”: 1, “bar”: 2] // Note let, not var
>let copy = dict
>let i = dict.keys.index(of: “foo”)!
>var values = dict.values
>values[i] = 42 
>print(dict[“foo”]) // => 42 (?!)
>print(copy[“foo”]) // => 42 (?!?!)
> 
> This is not the intended behavior, right?
> 
> Károly
> 
>> On 2016-10-11, at 23:28, Nate Cook via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> Introduction
>> 
>> This proposal addresses significant unexpected performance gaps when using 
>> dictionaries. It introduces type-specific collections for a Dictionary 
>> instance's keys and values properties.
>> 
>> New DictionaryKeys and DictionaryValues collections provide efficient key 
>> lookup and mutable access to dictionary values, enabling updates to be 
>> performed in-place and allowing copy-on-write optimization of stored values.
>> 
>>  
>> <https://gist.github.com/natecook1000/473720ba072fa5a0cd5e6c913de75fe1#motivation>Motivation
>> 
>> This proposal address two problems:
>> 
>> The Dictionary type keys implementation is inefficient, because 
>> LazyMapCollection doesn't know how to forward lookups to the underlying 
>> dictionary storage.
>> Dictionaries do not offer value-mutating APIs. The mutating key-based 
>> subscript wraps values in an Optional. This prevents types with 
>> copy-on-write optimizations from recognizing they are singly referenced.
>> This proposal uses the following [String: [Int]] dictionary to demonstrate 
>> these problems:
>> 
>> var dict = ["one": [1], "two": [2, 2], "three": [3, 3, 3]]
>>  
>> <https://gist.github.com/natecook1000/473720ba072fa5a0cd5e6c913de75fe1#inefficient-dictkeys-search>Inefficient
>>  dict.keys Search
>> 
>> Swift coders normally test key membership using nil checks or underscored 
>> optional bindings:
>> 
>> if dict["one"] != nil {
>> // ...
>> }
>> if let _ = dict["one"] {
>> // ...
>> }
>> These approaches provide the expected performance of a dictionary lookup but 
>> they read neither well nor "Swifty". Checking keys reads much better but 
>> introduces a serious performance penalty: this approach requires a linear 
>> search through a dictionary's keys to find a match.
>> 
>> if dict.keys.contains("one") {
>> // ...
>> }
>> A similar dynamic plays out when comparing dict.index(forKey:) and 
>> dict.keys.index(of:).
>> 
>>  
>> <https://gist.github.com/natecook1000/473720ba072fa5a0cd5e6c913de75fe1#inefficient-value-mutation>Inefficient
>>  Value Mutation
>> 
>> Dictionary values can be modified through the keyed subscript by direct 
>> reassignment or by using optional chaining. Both of these statements append 
>> 1 to the array stored by the key "one":
>> 
>> // Direct re-assignment
>> dict["one"] = (dict["one"] ?? []) + [1]
>> 
>> // Optional chaining
>> dict["one"]?.append(1)
>&

Re: [swift-evolution] [Proposal Draft] Provide Custom Collections for Dictionary Keys and Values

2016-10-12 Thread Károly Lőrentey via swift-evolution
I think this is a lovely approach to solving this API design problem.

One thing I don’t quite understand yet is how these kinds of mutable views 
interact with copy on write semantics. COW rules can be subtle, and these views 
seem to put an extra twist on top that seems hard to understand/explain.

I would expect DictionaryValues to behave like a separate copy of the 
dictionary:

   var dict = [“foo”: 1, “bar”: 2]
   let i = dict.keys.index(of: “foo”)!
   var values = dict.values
   values[i] = 42 // COW copy
   print(dict[“foo”]) // => 1
   dict.values = values   // Original storage is released
   print(dict[“foo”]) // => 42

Given that `values` contains a strong reference to the storage, I was curious 
to find out how this copy is elided when we write `dict.values[i] = 42`. So I 
tried building your branch, and I found that mutating `values` has an immediate 
effect on the dictionary as well:

   let dict = [“foo”: 1, “bar”: 2] // Note let, not var
   let copy = dict
   let i = dict.keys.index(of: “foo”)!
   var values = dict.values
   values[i] = 42 
   print(dict[“foo”]) // => 42 (?!)
   print(copy[“foo”]) // => 42 (?!?!)

This is not the intended behavior, right?

Károly

> On 2016-10-11, at 23:28, Nate Cook via swift-evolution 
>  wrote:
> 
> Introduction
> 
> This proposal addresses significant unexpected performance gaps when using 
> dictionaries. It introduces type-specific collections for a Dictionary 
> instance's keys and values properties.
> 
> New DictionaryKeys and DictionaryValues collections provide efficient key 
> lookup and mutable access to dictionary values, enabling updates to be 
> performed in-place and allowing copy-on-write optimization of stored values.
> 
>  
> Motivation
> 
> This proposal address two problems:
> 
> The Dictionary type keys implementation is inefficient, because 
> LazyMapCollection doesn't know how to forward lookups to the underlying 
> dictionary storage.
> Dictionaries do not offer value-mutating APIs. The mutating key-based 
> subscript wraps values in an Optional. This prevents types with copy-on-write 
> optimizations from recognizing they are singly referenced.
> This proposal uses the following [String: [Int]] dictionary to demonstrate 
> these problems:
> 
> var dict = ["one": [1], "two": [2, 2], "three": [3, 3, 3]]
>  
> Inefficient
>  dict.keys Search
> 
> Swift coders normally test key membership using nil checks or underscored 
> optional bindings:
> 
> if dict["one"] != nil {
> // ...
> }
> if let _ = dict["one"] {
> // ...
> }
> These approaches provide the expected performance of a dictionary lookup but 
> they read neither well nor "Swifty". Checking keys reads much better but 
> introduces a serious performance penalty: this approach requires a linear 
> search through a dictionary's keys to find a match.
> 
> if dict.keys.contains("one") {
> // ...
> }
> A similar dynamic plays out when comparing dict.index(forKey:) and 
> dict.keys.index(of:).
> 
>  
> Inefficient
>  Value Mutation
> 
> Dictionary values can be modified through the keyed subscript by direct 
> reassignment or by using optional chaining. Both of these statements append 1 
> to the array stored by the key "one":
> 
> // Direct re-assignment
> dict["one"] = (dict["one"] ?? []) + [1]
> 
> // Optional chaining
> dict["one"]?.append(1)
> Both approaches present problems. The first is complex and hard to read. The 
> second ignores the case where "one" is not a key in the dictionary. It forces 
> its check into a higher branch and encourages forced unwrapping. Furthermore, 
> neither approach allows the array to grow in place. They introduce an 
> unnecessary copy of the array's contents even though dict is the sole holder 
> of its storage.
> 
> Adding mutation to a dictionary's index-based subscripting isn't possible. 
> Changing a key stored at a particular index would almost certainly modify its 
> hash value, rendering the index incorrect. This violates the requirements of 
> the MutableCollection protocol.
> 
>  
> Proposed
>  Solution
> 
> This proposal adds a custom collection for the keys and values dictionary 
> properties. This follows the example set by String, which presents multiple 
> views of its contents. A new DictionaryKeys collection introduces efficient 
> key lookup, while a new DictionaryValues collection provides a mutable 
> collection interface to dictionary values.
> 
> These changes introduce a simple and efficient way of checking whether a 
> dictionary includes a key:
> 
> // Performant
> if 

Re: [swift-evolution] [Pitch] deprecating ManagedBufferPointer

2016-10-11 Thread Károly Lőrentey via swift-evolution
+1

ManagedBuffer has been really useful a couple of times, but I never found a use 
for ManagedBufferPointer. I can’t even say I’m entirely sure what need it was 
originally designed to fulfill.

> On 2016-10-11, at 00:12, Erik Eckstein via swift-evolution 
>  wrote:
> 
> The purpose of ManagedBufferPointer is to create a buffer with a custom 
> class-metadata to be able to implement a custom deinit (e.g. to destroy the 
> tail allocated elements).
> It was used in Array (before I replaced it with the new 
> tail-allocated-array-built-ins). But now it’s not used anymore in the 
> standard library.
> 
> As a replacement for ManagedBufferPointer one can just derive a class from 
> ManagedBuffer and implement the deinit in the derived class.
> 
> final class MyBuffer : ManagedBuffer {
>   deinit {
> // do whatever needs to be done
>   }
> }
> 
> // creating MyBuffer:
> let b = MyBuffer.create(minimumCapacity: 27, makingHeaderWith: { myb in 
> return MyHeader(...) })
> 
> IMO ManagedBuffer is much cleaner than ManagedBufferPointer (it doesn’t need 
> this custom bufferClass to be passed to the constructor). Also 
> ManagedBufferPointer doesn’t use SIL tail-allocated arrays internally. 
> Although this is not something visible to the programmer, it makes life 
> easier for the compiler.
> 
> So I suggest that we deprecate ManagedBufferPointer.
> 
> Erik
> ___
> 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] [Review #3] SE-0117: Allow distinguishing between public access and public overridability

2016-07-22 Thread Károly Lőrentey via swift-evolution
Thank you very much for clarifying these! My position is now of course back in 
favor of the proposal. +1

(Sorry for being a stickler; I know what deadlines are like. I hope the team 
gets a bit of time to rest.)

<3,
-- 
Károly
@lorentey

> On 2016-07-22, at 18:36, John McCall <rjmcc...@apple.com> wrote:
> 
>> 
>> On Jul 22, 2016, at 9:09 AM, Károly Lőrentey via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> On 2016-07-21 15:33:37 +, Chris Lattner via swift-evolution said:
>>> * What is your evaluation of the proposal?
>> 
>> I gave enthusiastic thumbs up to the previous two proposals. I agree
>> wholeheartedly with the underlying goal, and I love the new Motivation
>> section. I'm OK with the idea of making "open" imply "public" by
>> default, which seems to be the gist of the new design.
>> 
>> However, reading the actual details in this third revision made me
>> uncomfortable. I expected the specification to be bulletproof by now;
>> but the actual text of the "Proposed design" section seems to be even
>> less coherent than the previous two.
>> 
>> I understand there's a (self-imposed) deadline, but this one could've
>> really used a little more time in the oven.
>> 
>> While I am still strongly in favor of the direction and high-level
>> design of the proposal, I cannot in good conscience argue in favor
>> of such ill-defined details in a _third_review_. So I'm giving
>> this specific revision -1 in protest. 
> 
> I'm sorry if my drafting wasn't up to snuff.  In my defense, I needed to get 
> it out quickly,
> and I had a lot to rewrite.  I was pretty tired by the time I actually 
> finished the motivation
> section.
> 
>> Here are some of my problems with the text:
>> 
>> 1. The proposal offers two separate design approaches for `open` classes, 
>> listing
>> arguments for both. Please excuse my bluntness, but this is now the third 
>> attempt
>> to push this through: With all due respect, would you please make up your 
>> mind?
> 
> Most of the proposal has been "pushed through", frankly.  We are looking for 
> feedback
> on this specific question.  I agree that the proposal framework is an awkward 
> fit for
> this kind of discussion prompt.
> 
>> 2. The option to get rid of sealed classes is brand new with SE-0117rev3.
>> Did someone argue for it in review #2?
>> 
>> (I'm all for adding better support for sealed class hierarchies, so I prefer 
>> plan A.)
>> 
>> It's nice that we're given the option of reducing language complexity, but 
>> then
>> it's bizarre that the idea of eliminating sealed _members_ isn't mentioned 
>> at all.
> 
> Because it was settled in the core-team review.
> 
>> Although, a literal reading of "plan B" does in fact seem to imply that any 
>> member
>> that is not explicitly marked open would not even be _internally_ 
>> overridable:
>> 
>>"The second design says that there is no such thing as an open class 
>> because
>>all classes are subclassable unless made final. Note that its direct 
>> methods
>>would still not be overridable unless individually made open, although its
>>inherited open methods could still be overridden."
>> 
>> There is no mention of "public", and no mention of module boundaries.
>> Thus, plan B basically proposes to make *all members* in *all classes* 
>> `final` by default.
>> This seems inconsistent with the rest of the proposal, so I'll assume this 
>> is a
>> mistake in wording, not the actual design intent. (Or is it?)
> 
> It is a mistake in wording.
> 
>> Let's assume the intent was to keep members internally overridable by 
>> default.
>> But then why not go the full way? We can achieve the proposal's goals by 
>> just tweaking
>> existing defaults -- there's no need to introduce complicated new 
>> overridability levels:
>> 
>> "This proposal does not change the rules of class subclassibility. However, 
>> it introduces the
>> (previously implicit) "open" qualifier to explicitly declare an overridable 
>> member,
>> and changes the rules of default overridability as follows:
>>   - Members of public classes are now final by default.
>>   - Members of internal and private classes remain overridable ("open") by 
>> default."
>> 
>> I prefer plan A, but I'd also be OK with this bare-bones proposal.
>> 
>> I'm strongly opposed to plan B (either as stated

Re: [swift-evolution] [Review #3] SE-0117: Allow distinguishing between public access and public overridability

2016-07-22 Thread Károly Lőrentey via swift-evolution

On 2016-07-21 15:33:37 +, Chris Lattner via swift-evolution said:


* What is your evaluation of the proposal?


I gave enthusiastic thumbs up to the previous two proposals. I agree
wholeheartedly with the underlying goal, and I love the new Motivation
section. I'm OK with the idea of making "open" imply "public" by
default, which seems to be the gist of the new design.

However, reading the actual details in this third revision made me
uncomfortable. I expected the specification to be bulletproof by now;
but the actual text of the "Proposed design" section seems to be even
less coherent than the previous two.

I understand there's a (self-imposed) deadline, but this one could've
really used a little more time in the oven.

While I am still strongly in favor of the direction and high-level
design of the proposal, I cannot in good conscience argue in favor
of such ill-defined details in a _third_review_. So I'm giving
this specific revision -1 in protest. 

Here are some of my problems with the text:

1. The proposal offers two separate design approaches for `open` 
classes, listing
  arguments for both. Please excuse my bluntness, but this is now the 
third attempt
  to push this through: With all due respect, would you please make up 
your mind?



2. The option to get rid of sealed classes is brand new with SE-0117rev3.
  Did someone argue for it in review #2?

  (I'm all for adding better support for sealed class hierarchies, so 
I prefer plan A.)


  It's nice that we're given the option of reducing language 
complexity, but then
  it's bizarre that the idea of eliminating sealed _members_ isn't 
mentioned at all.


  Although, a literal reading of "plan B" does in fact seem to imply 
that any member
  that is not explicitly marked open would not even be _internally_ 
overridable:


 "The second design says that there is no such thing as an open 
class because
 all classes are subclassable unless made final. Note that its 
direct methods
 would still not be overridable unless individually made open, 
although its

 inherited open methods could still be overridden."

  There is no mention of "public", and no mention of module boundaries.
  Thus, plan B basically proposes to make *all members* in *all 
classes* `final` by default.
  This seems inconsistent with the rest of the proposal, so I'll 
assume this is a

  mistake in wording, not the actual design intent. (Or is it?)

  Let's assume the intent was to keep members internally overridable 
by default.
  But then why not go the full way? We can achieve the proposal's 
goals by just tweaking
  existing defaults -- there's no need to introduce complicated new 
overridability levels:


  "This proposal does not change the rules of class subclassibility. 
However, it introduces the
  (previously implicit) "open" qualifier to explicitly declare an 
overridable member,

  and changes the rules of default overridability as follows:
- Members of public classes are now final by default.
- Members of internal and private classes remain overridable 
("open") by default."


  I prefer plan A, but I'd also be OK with this bare-bones proposal.

  I'm strongly opposed to plan B (either as stated in the proposal or 
what (I assume

  above) is the intent behind it.)


3. The code examples are needlessly complicated by trying to describe 
both sub-proposals.

  I find this is confusing and it obscures the actual effect of both variants.

  The examples are also inconsistent with the text: e.g., AFAICT, 
property `size` below

  is still intended to be overridable inside the module that defines
  `SubclassableParentClass`.

  open class SubclassableParentClass {
// This property is not overridable.
public var size : Int
...
  }

4. The previous revisions ignored dynamic members, which wasn't great. 
The current

  document acknowleges that "dynamic" members exists, but then *prohibits*
  them from being overridden across a module boundary!

 "`open` is not permitted on declarations that are explicitly 
`final` or `dynamic`."
 "A class member that is not `open` cannot be overridden outside 
of the current module."


  If this was intentional, I'd love to see the reasoning behind this decision.
  Otherwise the wording should be fixed:

 "A class member that is not `open` or `dynamic` cannot be 
overridden outside

 of the current module."


5. It seems strangely inconsistent that `open` now implies `public` by default,
  but `final` doesn't. The proposal fails to explain this inconsistency.
  Was this point considered and dismissed, or was it not considered at all?

  Changing `final` to imply `public` later would be a source-breaking change.
  Given that SE-0117 is one of the last proposals where maintaining source
  compatibility isn't a major consideration, it's unclear if we'll 
ever have an

  opportunity to fix such minor inconsistencies.

  The same argument also applies to 

Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-20 Thread Károly Lőrentey via swift-evolution

> On 2016-07-20, at 19:34, John McCall  wrote:
> 
> I agree that having the concept of "visible publicly but only arbitrary 
> modifiable internally" adds complexity to the language.  However, once we've 
> got non-open public classes — and as I understand it, you still support those 
> — that complexity already exists.  You're not really eliminating anything by 
> preventing this from being applied to methods.
> 
> Also, we're going to be proposing a lot of new things for library-resilience 
> over the next six months or so that will add appreciable but unavoidable 
> complexity to the language around module boundaries. Module boundaries have a 
> lot of special significance in the language design because Swift takes the 
> stable binary interface problem much more seriously than, I think, almost any 
> other language can claim to.

Fair enough! Let’s move on.

>> This reminds me: Whether or not we allow the sealed level on methods, I 
>> suggest we provide a contextual keyword to (optionally) spell it. A "sealed" 
>> keyword is the obvious choice. This would encourage people to use common 
>> terminology, and makes it easier to use search engines to find an 
>> explanation of the concept. Autogenerated API summaries should add the 
>> "sealed" keyword.
> 
> Yes, we should probably add some way to spell it.  "sealed" does not feel 
> like a natural opposite to "open", however, and I think we're quite taken 
> with "open".  I would suggest "nonopen" or "closed”.

Ah, interesting! Kotlin and Scala uses the “sealed” keyword for their own 
variants for the same concept. C# is popular and uses “sealed” to mean what we 
call “final”; it’s in the same general ballpark. MATLAB (!!!) does the same. So 
it can be argued “sealed" is a somewhat common term of art for roughly this 
pattern. 

I could get used to “closed”, though.

But I think “nonopen” is a no-no (pen): it makes my eyes bleed.

-- 
Károly
@lorentey___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-20 Thread Károly Lőrentey via swift-evolution

> On 2016-07-18, at 19:05, John McCall via swift-evolution 
>  wrote:
> The basic effect of Károly's counter-proposal is that every public member of 
> an open class has to be marked either "open" or "final".  That's boilerplate.

My primary point was that there is no need for a middle ground between "final" 
and "open" members.

I want to push my primary point a little more, so let’s forget my secondary 
suggestion to have no default, and let’s set an implicit choice. 

I'd still argue for having no middle ground. “final” seems to be a good 
default; its effect matches the proposal.

> I think you and Károly are evaluating the addition of non-open methods as if 
> they were being added primarily to increase expressive capabilities.  They do 
> marginally increase expressiveness, but I agree that it's not a common 
> situation to explicitly want.  However, neither are non-open classes.  

It's more of an Occam's razor thing. The proposal prevents people from 
unintentionally exposing a wider API area than they intended. I agree with this 
wholeheartedly. I just don't believe that we need to add a brand new access 
level for members to achieve this goal.

Having an implicit "sealed" class level is a much easier sell for me, because 
it is sometimes desirable to expose a sealed class hierarchy, but Swift doesn't 
currently support it well -- AFAICT not as an intentional choice, but rather as 
an unfortunate side-effect of the initializer rules. You could've simply chosen 
to propose making "final" the default for public classes. Kotlin's troubles 
mostly wouldn't apply as long as internal classes would remain open, so I'd 
have supported that too. But rather than this, the proposal is built on top a 
nice solution to the sealed class problem. Solving it is obviously a good idea, 
and it is closely related to the goal of the proposal.

There is no such language problem in Swift 2 with sealed methods: an internal 
open member is sealed by virtue of not being externally visible. It’s 
straightforward to add a public final trampoline in the rare case when a sealed 
member should also be made externally callable. I believe the proposal works 
perfectly well without adding a language feature for this uncommon usecase.

> The goal here is not to create new expressive power, it's to establish a 
> comprehensible intermediate position that's acceptable as a default so that 
> publicizing an API doesn't require so much annotation and bookkeeping.  
> Otherwise, programmers are forced to immediately decide between 
> over-promising (by making the method publicly overridable) or breaking their 
> own code (if they have internal overrides).

But making API public should never be done in a hurry. It includes making the 
API presentable, which involves some amount of refactoring. Granted, if an API 
has internally overridden methods that the author wants to make public but 
sealed, then they'd need to refactor these methods. But given how rare this is, 
and how easy it is to implement the trampoline pattern, is such a trivial 
refactoring step really too much to ask? (There are a number of much more 
complicated refactorings involved in making an API public; e.g., it is often 
the case that a method I want to make public has a parameter or return value 
with a type that I wish to keep internal.)

I believe that apart from this one little wrinkle, the behavior that SE-0117 
proposes can be fully implemented by allowing just "final", "open" and 
"dynamic" members, with "final" being the default for public members of open 
classes, and "open" being the default for all other members (including non-open 
classes).

Is smoothing out that wrinkle worth introducing a whole new default level of 
member overridability? I think this is worth some more discussion.

Note that if we end up with "final” members by default and it turns out to be 
the wrong choice, changing the default to sealed would not be a source-breaking 
change.

> Furthermore, I don't agree that non-open methods add significant new 
> complexity.  For clients of a library, a non-open method is final; there are 
> no semantically-detectable differences (ignoring covariant overrides).  
> Within a library, non-open methods remove the need for some unnecessary 
> bookkeeping.  And just on a conceptual level, the analogy to class behavior 
> is quite simple.

This reminds me: Whether or not we allow the sealed level on methods, I suggest 
we provide a contextual keyword to (optionally) spell it. A "sealed" keyword is 
the obvious choice. This would encourage people to use common terminology, and 
makes it easier to use search engines to find an explanation of the concept. 
Autogenerated API summaries should add the "sealed" keyword.

We never have to spell "internal", but I think it is still very useful that it 
exists.

--
Károly
@lorentey

___
swift-evolution mailing list

Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-19 Thread Károly Lőrentey via swift-evolution

On 2016-07-19 11:35:03 +, Brent Royal-Gordon via swift-evolution said:



On Jul 19, 2016, at 4:00 AM, Károly Lőrentey via swift-evolution 
<swift-evolution@swift.org> wrote:


"dynamic final" is prohibited by the current version of compiler.


Huh, I didn't know that. I don't agree with that design.

(However, I do notice that a `final` class can have `dynamic` members.)


I'm very very far from understanding how Swift interacts with the Obj-C 
runtime, but I believe that might be a bug. I do not expect e.g. KVO to 
work correctly on these. I don't think the Objective-C runtime 
understands or enforces final (at neither class nor member level), and 
I expect abusing it to break out of "final" (at either level) could 
violate critical compile-time assumptions and cause deep problems. I 
think this also applies to anything with @objc that isn't also declared 
dynamic -- even "@objc open" members aren't necessarily dispatched via 
message passing, are they?



Can you provide an example of a problem that would be solved by allowing it?


In our current Objective-C world, the obvious example would be an 
NSObject subclass with a property that should not be overridden (so you 
want to mark it `final`), but which participates in KVO (so in fact 
Foundation will use the Objective-C runtime to invisibly subclass the 
class, override the setter, and change the type of the instance to the 
subclass). I believe it makes perfect sense to declare such a property 
`dynamic final`; the Objective-C-level overriding performed by 
Foundation is an implementation detail, and does not change the fact 
that you should never declare an override of that property.


To me, it doesn't make much sense to declare that a property must not 
be overridden, then expect KVO to be able to override it anyway. 
"dynamic" clearly does allow overriding (and more); it just adds 
supports for a less convenient syntax. AFAIK KVO isn't using secret 
APIs that aren't also available to my API clients. If I choose to use 
"dynamic" in my API, then I have to design for whatever the Objective-C 
runtime supports, and that includes overrides. Only disallowing 
overrides with Swift syntax doesn't seem to be much of a win here.


I'm not saying we couldn't come up with some coherent definition for a 
hypothetical "final dynamic"; I just really don't see what would be the 
point of it, besides making the language more complicated.


It's not really clear how `dynamic` would be used without Objective-C, 
but I could imagine analogous situations, like an ORM implementing Core 
Data-style faults using dirty, low-level class-changing hacks. A class 
that was *semantically* `final`, and thus ought to be eligible for 
static dispatch, might thus require dynamic dispatch anyway.


It is nice (and critically important) that we can keep using Cocoa in 
Swift; but supposing we wanted to create a brand new ORM for a 
hypothetical "Swifty Cocoa", it wouldn't make much sense to do it using 
the same runtime techniques as Core Data. (After all, we already have 
such a framework in Swift; it's called Core Data.) I'd prefer to choose 
a swiftier approach, like generating the equivalent of 
NSManagedObject's model-specific boilerplate at compile time.



Cocoa currently hides the boilerplate for all of these wonderful 
constructs behind amazingly effective runtime acrobatics. This fits 
perfectly into Objective-C, and it also works very well in Swift. But 
such features could be in better harmony with Swift's unique set of 
language constructs if their boilerplate was hidden behind amazingly 
effective **compile-time** acrobatics instead.


Such compile-time acrobatics are hard to perform today, and it is 
possible that the ability to create such systems will forever remain an 
advanced skill, just like forging runtime magic requires advanced 
skills in Objective-C.


But Swift doesn't have an analogue to objc/runtime.h yet. What will 
such a thing look like? A general metaprogramming/DSL subsystem (like 
some form of hygienic macro engine)? A family of narrowly scoped 
language/compiler features that provide extensible syntactic sugar to 
get rid of specific kinds of boilerplate (like property behaviors or 
coroutines)? A set of standalone tools for generating Swift source code 
(like mogenerator)? Something else? Some combination of these?


I'd like to move on from the Objective-C runtime and start exploring 
this rich new frontier; I think it's awesome that Swift isn't *just* a 
bracket-free dialect of Objective-C.


I'm sorry for derailing the discussion. I think we agree on most of 
this, anyway.



--
Károly
@lorentey


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


Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-19 Thread Károly Lőrentey via swift-evolution

On 2016-07-19 00:46:21 +, Brent Royal-Gordon via swift-evolution said:



On Jul 18, 2016, at 12:06 PM, Károly Lőrentey via swift-evolution 
<swift-evolution@swift.org> wrote:



Introducing "dynamic" or some other keyword to mark explicitly methods
that should be overriden is just the same "open" with sealed methods
by default would mean for public methods so it makes no difference to
me.


"dynamic" is already in the language. It changes method dispatch to use 
Objective-C style message passing, enabling advanced techniques based 
on the dynamic runtime, such as method swizzling or KVO. Since it 
already exists, I'm not arguing for its introduction; I merely want it 
integrated into the proposal, in order to keep the language coherent.


I would prefer not to ascribe overridability semantics to `dynamic`. I 
see `dynamic` as a hint to the compiler that something *outside of 
normal, safe Swift code* may cause this entity's implementation to 
change. A `dynamic final` member is a perfectly coherent concept: 
Formally, nothing is allowed to override this member, but in practice, 
something may change it behind the compiler's back.


"dynamic final" is prohibited by the current version of compiler. Can 
you provide an example of a problem that would be solved by allowing it?


--
Károly
@lorentey


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


Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-19 Thread Károly Lőrentey via swift-evolution

On 2016-07-18 21:42:03 +, Leonardo Pessoa via swift-evolution said:


On 18 July 2016 at 16:06, Károly Lőrentey  wrote:

If adding an extra qualifier turns out to be an onerous requirement, we can
choose a default at any time later, without breaking existing code. It'll
probably be easier to do so once we have a little experience in actually
using the new language.


So should we drop internal by default too?


Nope! Our topic is about guiding people towards putting more 
consideration into *public* APIs.


--
Károly
@lorentey


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


Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-18 Thread Károly Lőrentey via swift-evolution
If people were generally happy with having public members of open 
classes overridable by default, then we certainly wouldn't need to have 
a separate qualifier for that. (Although as "internal" demonstrates, 
it's nice to have a formal name for such things.)


However, (1) having a default would allow API designers to define 
public APIs with very little additional thought, and (2) it seems to me 
we're very very far from consensus on which default would be best. I'd 
like to avoid arguing even more about the theoretical merits of 
choosing open vs final vs dynamic by default. (Note that there are 
highly respectable app developers who honestly consider "open" much too 
restricting.)


I'm enthusiastic about sealed-by-default classes, but to be honest, I 
personally have no idea what default (if any) would be best for class 
members. Ask me again after I've worked with the new classes for a 
couple of months.


Karoly
@lorentey

On 2016-07-18 18:45:14 +, Nevin Brackett-Rozinsky via swift-evolution said:

Garth makes an excellent point. Károly is correct that we can already 
achieve “sealed” by making a `final` member call through to an 
`internal` one.


Therefore, it seem clear that “open” should only be applicable to 
classes, not to members. This should simplify the proposal nicely.


Nevin


On Mon, Jul 18, 2016 at 2:39 PM, Garth Snyder via swift-evolution 
 wrote:
> Károly wrote: I suggest we change the proposal to remove the implicit 
"sealed" level of public member overridability, and support only "open" 
or "final" class members. For members, "open" should mean the opposite 
of "final", with no levels in between. Member-level openness should be 
entirely independent of visibility; so it should be possible to say 
"internal open" to mean an internally overridable member that's not at 
all visible outside the module -- the same as today's default.


What is the distinction between this approach and simply omitting the 
ability to apply the “open” keyword to anything but a class?


The current behavior is (IIUC) that you cannot override a superclass’s 
final method. Aside from that, you can override any other method that’s 
visible to you, wherever you stand with regard to the superclass’s 
origin. If there’s no sealed status for members, why is any change to 
member annotations needed at all?


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


Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-18 Thread Károly Lőrentey via swift-evolution

On 2016-07-18 16:15:10 +, Leonardo Pessoa via swift-evolution said:


I believe sealed by default applied to functions makes the behaviour
consistent with classes and allows for the same behaviour we wanted
with this proposal. It would allows us to create subclassable classes
in which we would be able to internally override a method but not
outside the library and selectively allow other methods to be
overriden. Final won't do it so if this is not the default behaviour,
it will be necessary to introduce the sealed keyword so we can achieve
this.


Can you give an example where you'd need such a sealed method, but the 
obvious pattern I described wouldn't work?



It's inconsistent to have to explicitly open a class and
explicitly seal its methods and vice-versa. It was my assumption that
when we chose sealed by default with the proposal we were talking
about everything and not just classes (I at least was talking
everything).


This was my assumption as well, but then I thought things through. I 
suspect this might be what our friendly review manager was getting at 
when he gently lamented the lack of sufficient discussion on 
"overridable".



Introducing "dynamic" or some other keyword to mark explicitly methods
that should be overriden is just the same "open" with sealed methods
by default would mean for public methods so it makes no difference to
me.


"dynamic" is already in the language. It changes method dispatch to use 
Objective-C style message passing, enabling advanced techniques based 
on the dynamic runtime, such as method swizzling or KVO. Since it 
already exists, I'm not arguing for its introduction; I merely want it 
integrated into the proposal, in order to keep the language coherent.



Also having no default will not change that some library
developers will have everything sealed and selectively open.
No default shall also make developers prone to open to think more about
the keyword they'll choose to use,


Exactly! For this particular corner of the language, it fulfills the 
"unwavering goal of requiring additional thought when publishing a 
class as public API". Forcing people to make an explicit choice is by 
far the most straightforward way to achieve this. It also has the nice 
property of being harder to interpret as a value judgement on 
overridability, which is clearly a topic that gets people's monocles 
popping. ಠ_ರೃ



but I'm not fond of no default.


If adding an extra qualifier turns out to be an onerous requirement, we 
can choose a default at any time later, without breaking existing code. 
It'll probably be easier to do so once we have a little experience in 
actually using the new language.



As for the inheritance of openness, I firmly believe it shouldn't. If
a class inherited from an open class is open by default, there will be
no libraries making use of other libraries or we should also introduce
the sealed keyword in order to make the class (or method) sealed
again. This behaviour seems inconsistent to me too.


Agreed.



L


On 18 July 2016 at 09:07, Károly Lőrentey  wrote:

On 2016-07-18 09:17:43 +, David Hart via swift-evolution said:


On 18 Jul 2016, at 11:11, Xiaodi Wu via swift-evolution
 wrote:

On Mon, Jul 18, 2016 at 3:27 AM, Brent Royal-Gordon via swift-evolution
 wrote:

On Jul 17, 2016, at 8:57 PM, L. Mihalkovic via swift-evolution
 wrote:


On Jul 17, 2016, at 9:14 PM, Garth Snyder via swift-evolution
 wrote:

Is there a summary somewhere of the motivation for allowing methods to
be declared non-overridable within open classes?

[...]
Garth: I think it's implicit in the reasons to prevent subclassing. The
mere fact that a class allows subclassing doesn't necessarily mean that
every member in it is designed to be subclassed. Consider
`UIViewController`: It's obviously designed to be subclassed, and some
methods in it (such as `loadView`) are intended to be overridden, but others
(such as `loadViewIfNeeded`) are *not* intended to be overridden.

And [if UIViewController were to be written in Swift] there'd be a good
reason why `loadViewIfNeeded` and others of its ilk couldn't be final?

I don't know UIKit internals, but I could imagine loadViewIfNeeded be
overridden internally, if one knows the precise internal workings of
UIViewController. That would require open, to allow overriding internally
but not externally.




I thought about this aspect a little more. I think it's fair to say that
we're breaking new ground for language design here. Classes limiting
inheritance to a certain set of subclasses are nothing new (I've written &
used classes doing this in C++, Java and C#), but no language that I know of
allows limiting overrides of a specific public member in such a way. I think
we need a convincing rationale for making this esoteric middle ground
between final and open members the new default.

The 

Re: [swift-evolution] [Review] SE-0121: Remove `Optional` Comparison Operators

2016-07-18 Thread Károly Lőrentey via swift-evolution

> On 2016-07-12, at 20:26, Chris Lattner via swift-evolution 
>  wrote:
> The review of "SE-0121: Remove `Optional` Comparison Operators" begins now 
> and runs through July 19. The proposal is available here:
> 
>   
> https://github.com/apple/swift-evolution/blob/master/proposals/0121-remove-optional-comparison-operators.md
>  
> 

>   * What is your evaluation of the proposal?

If SE-0123 is accepted, then I don’t mind keeping optional comparisons. But I 
also wouldn’t protest much against removing them until Optional can be made to 
conditionally conform to Comparable.

If SE-0123 is rejected, then definitely +1; I’ve been bitten several times by 
accidentally using these while handling the return value of Collection’s 
index(of:).

I don’t remember ever intentionally using these overloads, except ironically:

https://twitter.com/lorentey/status/657254631660236800 


Note though that I often find myself wishing for Optional to implement 
Comparable. Writing comparison methods for little one-off Comparable structs 
that wrap Optionals gets tiring after a while. (As the proposal states, the 
existing overloads fall far short of achieving conditional conformance. I guess 
I could use these operators in the implementation of my wrapper structs, but I 
forget they exist.)

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

This depends on the outcome of SE-0123, which aims to eliminate the pitfall 
that makes these overloads dangerous. 

>   * Does this proposal fit well with the feel and direction of Swift?

I think Optional should implement Comparable whenever the wrapped type does. 
The proposal is a distinct step back from this. On the other hand, if SE-0123 
fails, I think it’s worth giving up on this goal in favor of removing a common 
pitfall.

>   * If you have used other languages or libraries with a similar feature, 
> how do you feel that this proposal compares to those?

Languages with implicit optionals do allow comparisons. E.g., "NSNotFound < 42" 
produces no compiler diagnostic. 

C++ has recently gained std::optional, which does provide />= operators, 
with the same semantics as Swift, including support for comparing optionals 
with non-optionals. It also has implicit promotion of values to optionals.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3672.html#rationale.relops
 


Rust’s std::Option enum implements the std::cmp::Ord trait when T does. So 
Rust’s optionals are (conditionally) comparable. I believe Rust provides no 
implicit coercion from T to std::Option, but to be honest I’m not entirely 
sure.
https://doc.rust-lang.org/std/option/enum.Option.html#method.cmp 


So the few languages I know that support explicit optionals also make them 
comparable.

>   * How much effort did you put into your review? A glance, a quick 
> reading, or an in-depth study?

Quick reading and minimal research.

-- 
Karoly
@lorentey

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


Re: [swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-18 Thread Károly Lőrentey via swift-evolution

On 2016-07-18 09:17:43 +, David Hart via swift-evolution said:

On 18 Jul 2016, at 11:11, Xiaodi Wu via swift-evolution 
 wrote:


On Mon, Jul 18, 2016 at 3:27 AM, Brent Royal-Gordon via swift-evolution 
 wrote:
> On Jul 17, 2016, at 8:57 PM, L. Mihalkovic via swift-evolution 
 wrote:

>
>> On Jul 17, 2016, at 9:14 PM, Garth Snyder via swift-evolution 
 wrote:

>>
>> Is there a summary somewhere of the motivation for allowing methods 
to be declared non-overridable within open classes?

[...]
Garth: I think it's implicit in the reasons to prevent subclassing. The 
mere fact that a class allows subclassing doesn't necessarily mean that 
every member in it is designed to be subclassed. Consider 
`UIViewController`: It's obviously designed to be subclassed, and some 
methods in it (such as `loadView`) are intended to be overridden, but 
others (such as `loadViewIfNeeded`) are *not* intended to be overridden.


And [if UIViewController were to be written in Swift] there'd be a good 
reason why `loadViewIfNeeded` and others of its ilk couldn't be final? 


I don't know UIKit internals, but I could imagine loadViewIfNeeded be 
overridden internally, if one knows the precise internal workings of 
UIViewController. That would require open, to allow overriding 
internally but not externally.



I thought about this aspect a little more. I think it's fair to say 
that we're breaking new ground for language design here. Classes 
limiting inheritance to a certain set of subclasses are nothing new 
(I've written & used classes doing this in C++, Java and C#), but no 
language that I know of allows limiting overrides of a specific public 
member in such a way. I think we need a convincing rationale for making 
this esoteric middle ground between final and open members the new 
default.


The UIKit example above isn't convincing at all. It is already quite 
easy to allow package-internal subclasses to configure the behavior of 
loadViewIfNeeded without such a novel language feature. E.g., the UIKit 
team can simply make loadViewIfNeeded call into a non-final but 
internal method:


public open class UIViewController {
private var _view: UIView? = nil

public final func loadViewIfNeeded() {
internalLoadViewIfNeeded()
}

internal func internalLoadViewIfNeeded() { // overridable internally
if let view = _view { return }
loadView()
}

public open func loadView() {
// Load it from a nib or whatevs
}
}

I see no drawback to this pattern; it is quite clear and simple. 
Therefore, in the interest of keeping the language free of needless 
complexity, I suggest we change the proposal to remove the implicit 
"sealed" level of public member overridability, and support only "open" 
or "final" class members.


For members, "open" should mean the opposite of "final", with no levels 
in between. Member-level openness should be entirely independent of 
visibility; so it should be possible to say "internal open" to mean an 
internally overridable member that's not at all visible outside the 
module -- the same as today's default.


(Note that (on platforms with an Objective-C runtime) "dynamic" 
provides a third level of flexibility for class members; I argue that 
it should imply "open". So in order of increasing flexibility, we'd 
have "final", "open" and "dynamic" members. This seems easy enough to 
describe and understand.)


I also suggest that for now, we should make neither "final" nor "open" 
nor "dynamic" the default for public members of open classes: we should 
rather require class authors to explicity add one of these qualifiers 
to all public member declarations. This way, we can defer the argument 
for choosing a default to a later (additive) proposal, once we have 
some experience with this setup. Non-public members can safely keep 
defaulting to "internal open", like they do today.


--
Károly
@lorentey


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


Re: [swift-evolution] [Review #2] SE-0117: Default classes to be non-subclassable publicly

2016-07-17 Thread Károly Lőrentey via swift-evolution

> On 2016-07-16, at 07:52, Chris Lattner via swift-evolution 
>  wrote:
> The second review of "SE-0117: Default classes to be non-subclassable 
> publicly" begins now and runs through July 22. The proposal is available here:
> 
>   
> https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md
> 
>   * What is your evaluation of the proposal?

+1, with notes:

1. The interaction of open with the dynamic keyword should be specified. Does 
"public dynamic" imply “open”? Dynamic provides a level of flexibility beyond 
mere subclassing, so I believe it should. Dynamic already conflicts with 
“final”, so there is precedent for this kind of interaction in the language. 
Note that “public dynamic” implying “open” means that we can’t have public 
dynamic members in a public class that’s not also open. I think this 
restriction is reasonable.

2. What about @objc methods? The docs say that it makes a name available but 
doesn’t guarantee dynamic dispatch on its own; so, it looks mostly irrelevant 
to this proposal.

3. The problem of code migration should be addressed. For example, we might 
want the auto-translator to automatically add open to non-final public 
methods/properties in existing code, to make it less painful to upgrade. People 
who simply accept the conversion results will get stuck with un-audited open 
stuff all over their public APIs, which is not ideal. On the other hand, this 
is no different to how their existing code behaved in Swift 2, so perhaps it is 
the best choice.

4. I don’t have a strong opinion on whether “open" should imply “public". If we 
accept that “public dynamic” is a stronger promise than “public open", then it 
would look strange that the former requires public, while the latter doesn’t. 
On the other hand, “public open” is going to be much more frequently used than 
“public dynamic”, so arguably it deserves special treatment.

5. I was suprised by the restriction that the superclass of open classes must 
also be open. But I don’t have a convincing usecase against it, so I guess it’s 
fine. I like that we have the option to revisit this later.


For fun, here are the distinct combinations of access levels and dispatch 
clauses for members in a "public open" class after this proposal:

public dynamic // plus “public dynamic open” if we keep it separate.
[public] open  // assuming “open” implies “public"
public
public final
[internal] dynamic
[internal]
[internal] final
private dynamic
private
private final


>   * Is the problem being addressed significant enough to warrant a change 
> to Swift?
Absolutely.
>   * Does this proposal fit well with the feel and direction of Swift?
Yep.
>   * If you have used other languages or libraries with a similar feature, 
> how do you feel that this proposal compares to those?
“Don’t use public subclassing" has been my policy for years, but I have not had 
the pleasure to use a language that helps me enforce this.
>   * How much effort did you put into your review? A glance, a quick 
> reading, or an in-depth study?
In-depth study broken across many short sessions.

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


Re: [swift-evolution] Fixing modules that contain a type with the same name

2016-07-16 Thread Károly Lőrentey via swift-evolution
For what it’s worth, I renamed OrderedSet to SortedSet in the Swift 3 version 
of BTree, so the original instance of this issue is hopefully no more.

Prohibiting modules from containing a symbol of the same name would require a 
mass renaming of many microframeworks. Besides BTree, I also have BigInt, Deque 
and RedBlackTree; I know Rob Rix has Result, Box, Either, Memo, Delay, Stream, 
BinaryTree, etc.; and there are oodles more. Renaming them is certainly doable, 
but it definitely would be a pain in the neck for everyone involved. I’m not 
even sure what naming convention we should use: most of these packages 
essentially consist of the type that they’re named after, and naming them like 
this was the most obvious option. (These names work well at the point of use, 
too: you want to use Result, so you need to import Result). Requiring/allowing 
reverse DNS-style module names (e.g. com.apple.Foundation) would be one way to 
solve the naming issue, but this seems hard to incorporate into the language at 
this point.)

I’d much prefer having “import Foo as Bar” as a (hopefully) easy-to-implement 
stop-gap solution than to give up on these nice microframework names. This 
would not break existing code.

I like the idea to allow absolute naming to resolve ambiguous names, but using 
_ for the root symbol seems very different to its usual meaning. Perhaps it's 
worth spending the # character on this: #.BTree.OrderedSet. Or how about 
"<>.BTree.OrderedSet”? None of these would be intuitively clear to read, 
though (and they need special magic to make sure a “.BTree.” prefix is 
resolved to mean the module, not the struct.). If nested modules are in the 
cards for a future Swift, not having a delimiter at the end of the module path 
could become an issue.

What if we allowed type expressions like “(OrderedSet in BTree)” or 
“(OrderedSet from Foundation)”? The swapped order sure is strange though, 
and I have no idea if such a construct would fit in the grammar. But at least 
the meaning of it is reasonably clear, and the same scheme could also support 
the extension method case: e.g., "foo.(bar in MyModule)()”.

C# has a somewhat similar issue with its namespaces: 
https://blogs.msdn.microsoft.com/ericlippert/2010/03/09/do-not-name-a-class-the-same-as-its-namespace-part-one/
 
.
 They have "global::” to refer to their root namespace, and they discourage 
(but not prohibit) naming a class the same as its enclosing namespace. I think 
Java's concept of obscured names is also relevant, but I’ll leave it to someone 
else to decipher the specification. :-)

-- 
Karoly
@lorentey

> On 2016-07-17, at 01:07, Félix Cloutier via swift-evolution 
>  wrote:
> 
> There is a lot of potential for it to be a breaking change. Currently, you 
> can do module qualification with Module.Symbol. This causes problems. The two 
> most obvious solutions (change the "operator" between Module and Symbol, or 
> prevent symbols from having the same name as their module) are breaking 
> changes.
> 
> Félix
> 
>> Le 16 juil. 2016 à 16:01:28, David Hart > > a écrit :
>> 
>> I don't see anything source breaking here. I'm fairly sure it's 100% 
>> additive and will therefore wait for after Swift 3.
>> 
>> On 17 Jul 2016, at 00:19, Félix Cloutier via swift-evolution 
>> > wrote:
>> 
>>> There is about 2 weeks left for source-breaking proposals, and this is 
>>> going to be one of them. How is progress going? Do you think that you'll 
>>> have enough time to push it out of the door?
>>> 
>>> Félix
>>> 
 Le 20 juin 2016 à 17:33:03, Paulo Faria > a écrit :
 
 Yeah! I’m working on a formal proposal that would solve the same problem. 
 Jordan, the problem he described is exactly like the one you explained to 
 me, haha. Now I’m a bit confused about how the proposal should be called. 
 Have any suggestions? What title could fit the two use cases we mentioned. 
 By the way, can you see any other use case that would be solved with the 
 same solution?
 
 
> On Jun 20, 2016, at 9:25 PM, Jordan Rose  > wrote:
> 
> I've been encouraging Paulo Faria to mention this case in his push for a 
> way to disambiguate extension methods, with the thought being we could 
> then use the same syntax to differentiate top-level names as well.
> 
> I'd also be happy with the "import as" syntax. The underscore syntax 
> seems a little opaque, but I suppose it wouldn't come up very often.
> 
> Jordan
> 
> 
>> On Jun 17, 2016, at 19:52, Félix Cloutier via swift-evolution 
>> 

Re: [swift-evolution] [swift-evolution-announce] [Returned for revision] SE-0117: Default classes to be non-subclassable publicly

2016-07-16 Thread Károly Lőrentey via swift-evolution
> On 2016. Jul 16., at 16:45, Karl via swift-evolution 
>  wrote:
> Sorry to mail 3 times in a row, but as I finished I remembered a concrete 
> example of where sealed protocols would be helpful:
> 
> UIKit has a UITextInput protocol, which is used by custom text object which 
> want to interact with the keyboard. It has a delegate property, of type 
> UITextInputDelegate (another protocol).
> 
> I have seen lots of people try to have their own objects conform to 
> UITextInputDelegate and set themselves as the delegate on a UITextInput 
> object. That is the wrong usage of the property. You are never supposed to 
> conform to UITextInputDelegate; the system has something which conforms to 
> it, and it will set itself as your delegate at some point during text input. 
> You use it to notify the system about changes to the text content and 
> selection region.
> 
> https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputDelegate_Protocol/index.html
> 
> If it was a sealed protocol, the UIKit API authors would be able to more 
> clearly communicate this intention and people wouldn’t be able to fall in 
> this trap. The only other way they could do it would be to use a concrete 
> final type, which evidently they didn’t want to do (possibly because it has 
> internal subclasses and can’t be final).

I think there is at least one legitimate case where you'd still want to 
implement these kinds of protocols: when you're writing unit tests and you want 
to create a mock delegate to verify that your code calls the delegate methods 
correctly.

Also, interface inheritance is much less dangerous than implementation 
inheritance; I can't think of a case where allowing external code to implement 
a protocol could lead to maintenance problems for the framework author like 
subclassing does. (Although I agree the user confusion that you described 
occurs a lot.)

Karoly
@lorentey

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


Re: [swift-evolution] [Review] SE-0120: Revise 'partition' Method Signature

2016-07-13 Thread Károly Lőrentey via swift-evolution

* What is your evaluation of the proposal?


+1; I like the new design, and I think once in a blue moon I may 
actually use the new API.


I remember looking up partition in the stdlib docs, sighing and moving 
on once or twice. It seemed easier to write an explicit loop than to 
hammer my problem into the shape of the old API.


Nitpick: In the "Impact on Existing Code", the sample code for the 
replacement ignores the return value.


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


I guess so; although it is a fix for a super minor problem, the 
proposed change is equally nonintrusive.



* 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?


As Paul noted, Haskell and Ruby have nonmutating methods for the same 
thing. It's fine to delay adding other variants for now.


	* How much effort did you put into your review? A glance, a quick 
reading, or an in-depth study?


Quick reading plus superficial research.

--
Karoly
@lorentey

On 2016-07-12 18:12:18 +, Chris Lattner via swift-evolution said:


Hello Swift community,

The review of "SE-0120: Revise ‘partition' Method Signature" begins now 
and runs through July 19. The proposal is available here:


 
https://github.com/apple/swift-evolution/blob/master/proposals/0120-revise-partition-method.md 



Reviews are an important part of the Swift evolution process. All 
reviews should be sent to the swift-evolution mailing list at


https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the 
review manager.


What goes into a review?

The goal of the review process is to improve the proposal under review 
through constructive criticism and contribute to the direction of 
Swift. When writing your review, here are some questions you might want 
to answer in your review:


* What is your evaluation of the proposal?
	* Is the problem being addressed significant enough to warrant a 
change to Swift?

* Does this proposal fit well with the feel and direction of Swift?
	* If you have used other languages or libraries with a similar 
feature, how do you feel that this proposal compares to those?
	* How much effort did you put into your review? A glance, a quick 
reading, or an in-depth study?


More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager


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



--
Károly
@lorentey


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


Re: [swift-evolution] An Alternative for Extensibility Modifiers

2016-07-12 Thread Károly Lőrentey via swift-evolution

> On 2016-07-12, at 13:29, Jonathan Hull  wrote:
>> Note that most popular OOP languages provide well-known patterns for 
>> creating sealed but public classes, where only the author is able to 
>> create subclasses. These patterns typically involve hiding class 
>> constructors from external modules. If Swift was changed to support 
>> sealed classes the same way, would you then propose a language feature 
>> to defeat access modifiers?
> All I will say is that I avoid using those languages as much as possible.  It 
> is a separate topic, but in my opinion/experience languages which encourage 
> too much planning/architecture lead to complicated programming structures (as 
> an effort to work around limitations within the rules) and nothing of worth 
> actually ends up getting accomplished.  Give me smalltalk or objC any day.

There is truly nothing wrong with preferring the 
Objective-C/Smalltalk/Ruby/Python/JavaScript class of languages to the 
Java/C++/C#/Rust/Go camp. Most reasonable people would say that lots of worth 
has been accomplished in each of them. Also, most people would say that too 
little planning/architecture can be just as damaging (or more) as too much.

But Swift is obviously in the second camp, and has been since 1.0.

I doubt there is a good middle ground between the two approaches; they seem to 
be mutually incompatible. Most concessions to “loose" languages in a “strict” 
language feel out of place, and vice versa.

Swift does provide an important concession to Objective-C in its @objc 
attribute, whose interaction with final/sealed classes could perhaps be tweaked 
to achive what you want.

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


Re: [swift-evolution] An Alternative for Extensibility Modifiers

2016-07-12 Thread Károly Lőrentey via swift-evolution

On 2016-07-12 09:12:36 +, Jonathan Hull via swift-evolution said:

With all the controversy around proposal 0117, I thought I would take a 
stab at an alternative approach that attempts to balance the concerns 
of both sides of the argument.  I don’t know that it would be 
everyone's first choice, but I think/hope it would be acceptable to the 
vast majority.


Take a look here and let me know if you think it is worth flushing out:
https://gist.github.com/jonhull/a5ac84a16b7a0ffc0c00747998f390d9


The basic idea (for those who hate clicking links) is to create 3 
levels of extensibility:
	• Open -  The class or method is open to be extended through 
subclassing/override.
	• Sealed - Attempting to subclass/override the class/method will 
result in a compiler error saying that it is not intended to be 
extended. Using the ‘unsafe' keyword will allow compilation.
	• Final - The class or method can not be subclassed/overridden. 
Attempting to do so will result in a compiler error.


These would be orthogonal to access modifiers.  Thus you would write 
‘public open’, which is admittedly two words… but together they are 
actually shorter than the single ‘subclassable’ keyword


You can also specify different levels of extensibility at different 
levels of visibility (e.g. ‘public final internal(open)’)


The default would be ‘sealed internal(open)’ which means it is publicly 
sealed, but open within the defining module.  This is similar to the 
default of 0117, except it allows overriding using the ‘unsafe’ keyword 
(where the user explicitly acknowledges that subclassing/overriding is 
not supported by the API).


It seems to me adding such an escape hatch makes the entire point of 
the proposal moot.


If I say a class I define is internal or private, you have no business 
poking at it from an external module; if I say my class is sealed or 
final, you have no business subclassing it from an external module. 
Swift provides no escape hatch that exposes internal components of a 
module; I don't see why subclassibility requirements should be treated 
otherwise.


Note that most popular OOP languages provide well-known patterns for 
creating sealed but public classes, where only the author is able to 
create subclasses. These patterns typically involve hiding class 
constructors from external modules. If Swift was changed to support 
sealed classes the same way, would you then propose a language feature 
to defeat access modifiers?


Thus, we lose some compiler optimizations in the default case (vs 
0117), but these can easily be regained by explicitly marking parts of 
the API as final.  The semantic meaning of the 0117 default is kept, 
with an escape hatch for problematic API.  Thoughtful framework writers 
would go through and mark API as either ‘public open’ or ‘public 
final’.  Less thoughtful framework authors would still get feedback 
asking them to do so, since nobody likes having the word ‘unsafe’ in 
their code when they don’t have to.


This design feels much Swiftier™ to me because it has opt-out safety 
and opt-in risk.  It protects you from accidentally causing trouble, 
but gets out of your way when you tell it you know what you are doing.



--
Károly
@lorentey


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


Re: [swift-evolution] [Review] SE-0117: Default classes to benon-subclassable publicly

2016-07-11 Thread Károly Lőrentey via swift-evolution

> On 2016-07-12, at 01:54, Colin Cornaby  wrote:
> 
>> - Slippery Slope: SE-0117 adds yet another entry to the already huge list of 
>> things in Swift that subtly or openly discourage people from subclassing. 
>> How far are we from someone seriously proposing to outright rip inheritance 
>> out of the language? Enough is enough. Stop with the anti-subclassing 
>> propaganda. Implementation inheritance is a hugely important core language 
>> feature whose popularity should be preserved and whose use should be 
>> encouraged and celebrated.
> 
> This is another reason I’m unclear on the reasoning behind this proposal, but 
> I could be missing something… Structs have been pushed in Swift primarily as 
> classes without polymorphism. One would think that one of the primary reasons 
> to adopt a class structure in Swift is polymorphism. It seems backwards to 
> make the point of a class primarily polymorphism, and then disable it by 
> default.

Classes are the only way to create a reference type in Swift. In idiomatic 
Swift code, classes are frequently employed for this exact feature alone (to 
e.g. implement copy-on-write storage).

Subtype polymorphism is an additional feature that is (while obviously 
important and useful elsewhere) frequently unwanted in this context. One can 
easily imagine a bizarro alternate universe where Swift classes do not support 
subclassing at all, and they would still remain a quite useful construct. 
Polymorphism (when needed) is often better achieved using protocols rather than 
subclassing, anyway.

(Note that we clearly do not live in that universe. I don’t think it would be a 
good idea to remove subclassing from Swift.)

> I suppose you could make the case you’d want to inherit from a parent class 
> but not allow other classes to inherit from you. This just seems like more of 
> a mess though. I could have vendors shipping me view controllers that I can’t 
> inherit from, complicating my own designs.

We already have final, so this is already the case today. For what it’s worth, 
I’ve already made many of my own view controllers final; but I’m not vending 
them out to people.

> (The other big reason I still use a lot of classes in Swift is Cocoa 
> compatibility, but I’m assuming Obj-C compatible Swift objects won’t support 
> final or final-by-default anyway.)

That is a good question; @objc and final are not mutually exclusive today. I 
think cross-module subclassibility should work the same way.

> Someone correct me if I’m missing something big here though.


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


Re: [swift-evolution] [Review] SE-0117: Default classes to be non-subclassable publicly

2016-07-09 Thread Károly Lőrentey via swift-evolution

On 2016-07-09 22:01:38 +, Károly Lőrentey via swift-evolution said:



On 2016. Jul 9., at 22:55, Goffredo Marocchi <pana...@gmail.com> wrote:

Why have they not "fixed" this issue with Java 6/7/8 if it is bad to 
have the current setup by default? Why C++ x09/x11/x14 is also not 
making everything sealed/unsubclassable by default?


I'd wager a guess that the strong desire not to break source 
compatibility with existing code explains why Java and C++ are stuck 
forever with suboptimal defaults. Some members of this list have a bit 
of background in C++ language design (understatement of the day!); 
perhaps they know more.


Quick P.S.: I just remembered that JetBrains' Kotlin exists, and it 
made final classes the default:


"By default, all classes in Kotlin are final, which corresponds to 
Effective Java, Item 17: ‘Design and document for inheritance or else 
prohibit it’."

-- https://kotlinlang.org/docs/reference/classes.html#inheritance

They even quote the same authority as I did! <3

It seems to have worked out fine in practice, except for some bad 
interactions with some standard Java packages -- which I do not expect 
to be an issue in our case.


--
Károly
@lorentey


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


Re: [swift-evolution] [swift-evolution-announce] [Review] SE-0117: Default classes to be non-subclassable publicly

2016-07-09 Thread Károly Lőrentey via swift-evolution

On 2016-07-09 04:39:01 +, Jordan Rose via swift-evolution said:

I wanted to share a concrete use case that Daniel Dunbar relayed to me. 
He was working on a closed class hierarchy like the ones discussed 
here, where all of the subclasses are within a single module, but they 
are all public. The class also has a required initializer for dynamic 
construction, so that they could write something like this:


internal struct ModelContext { /*…*/ }

public class ModelBase {
  internal required init(context: ModelContext) { /*…*/ }
  // …
}
public class SimpleModel: ModelBase {
  internal required init(context: ModelContext) { /*…*/ }
}
public class MoreComplicatedModel: ModelBase { /*…*/ }

// (within some other type)
public func instantiateModelObject(_ type: Model) -> Model {
  return type.init(context: self.context)
}

That is, a public entry point calls a required initializer with an 
internal argument type. This is the only way to instantiate Model 
objects, and the internal context type doesn’t leak out into the public 
API.


Of course, Swift doesn’t allow this. If someone outside of the module 
subclasses ModelBase, there’s no way for them to provide the 
dynamically-dispatched 'init(context:)’, because they don’t have access 
to the internal ModelContext. The author of the library has to make the 
required initializers public, and either set the ModelContext 
separately or make it public as well. Even though no one outside the 
module should be using these APIs.


Can you remind us why does Swift need required initializers to have the 
same access as the containing class?


Having only package-internal constructors in the public base class is 
the usual pattern for exporting a sealed class hierarchy in some other 
languages, like Java.


--
Károly
@lorentey


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


Re: [swift-evolution] [Review] SE-0117: Default classes to be non-subclassable publicly

2016-07-09 Thread Károly Lőrentey via swift-evolution
> On 2016. Jul 9., at 22:55, Goffredo Marocchi  wrote:
> 
> Why have they not "fixed" this issue with Java 6/7/8 if it is bad to have the 
> current setup by default? Why C++ x09/x11/x14 is also not making everything 
> sealed/unsubclassable by default?

I'd wager a guess that the strong desire not to break source compatibility with 
existing code explains why Java and C++ are stuck forever with suboptimal 
defaults. Some members of this list have a bit of background in C++ language 
design (understatement of the day!); perhaps they know more.

> Is it possible that having library authors use something like a sealed 
> keyword or similar is good enough for the default case?

Swift is to be safe by default. I believe open subclassability is a power tool 
that's unsafe without adequate training and thick protective gear; therefore, 
it is useful to require posting yellow/black hazard signs when it is in use. 
Safety first.

"Opting for safety sometimes means Swift will feel strict, but we believe that 
clarity saves time in the long run."

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


Re: [swift-evolution] [Review] SE-0117: Default classes to be non-subclassable publicly

2016-07-09 Thread Károly Lőrentey via swift-evolution

> On 2016. Jul 9., at 18:04, Tino Heth via swift-evolution 
>  wrote:
>> Of course it can be done either way.  But there are significant ecosystem 
>> robustness advantages to making sealed the default and comparatively few 
>> downsides.  Most libraries are open source (so can be modified directly or 
>> via PR if necessary)
> First:
> The claim about robustness sounds like a fact, despite being just an opinion 
> (feel free to correct me if you have any evidence at all). We should stay 
> honest with our predictions.

It has been standard advice in the Java community for at least 15 years to 
always prohibit external subclassing unless the class has been designed and 
documented to be safely subclassable, precisely because of the numerous 
problems that are caused by unforeseen subclassing.

> Second:
> Do you really believe there will be positive impact on open-source libraries?
> My forecast is that closed by default will dramatically increase trivial pull 
> request where developers ask for unsealing so that they can do as they like… 
> and I've no idea why somebody could come up with the idea that forking is 
> desirable.

I may be unusually careful in my API design, but I don't see how opening a 
class to inheritance could ever be a trivial pull request. 

Enabling open subclassing involves the creation of customization hooks: a 
formal list of methods that subclasses are allowed to override to modify the 
behavior of the superclass. These methods need to be designed and their 
override requirements precisely documented. 

Inheritance breaks encapsulation, making the API contract a lot more 
complicated to describe, understand and verify. The public API becomes tainted 
with implementation details that were previously private: for example, the 
exact sequence of overridable methods called by each public function becomes de 
facto part of the public interface. Adding/reordering/removing calls to 
overridable methods can (and, if your package is popular and/or unlucky enough, 
will) break your clients.

Trying to write unit tests to verify a subclassing interface is an exercise in 
frustration; but unless you have adequate coverage, you can't really expect 
package maintainers not to accidentally break the subclassing contract in any 
future release.

Subclassing is an important tool in Swift's toolbox, but it takes considerable 
effort to prepare a class for inheritance. It is not OK to just slap on an 
"open" keyword and call it done; and it is unsafe to let it happen purely by 
accident.

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


Re: [swift-evolution] [Review] SE-0117: Default classes to be non-subclassable publicly

2016-07-08 Thread Károly Lőrentey via swift-evolution

* What is your evaluation of the proposal?


Strong +1. I believe supporting public inheritance is the single most 
complicated thing in modern API design; thus, allowing inheritance to 
happen without explicit approval of the API designer is clearly a bad 
idea.


I'm OK with the proposed keywords (subclassable/overridable), but I 
like "open" even more.
I think "base class"/"base func" or "super class"/"super func" would 
also read well.


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


Yes. This proposal helps third-party API writers avoid a major source 
of pitfalls.



* Does this proposal fit well with the feel and direction of Swift?


Absolutely. Having sensible/safe defaults for such toggles feels like a 
major feature in Swift.


	* If you have used other languages or libraries with a similar 
feature, how do you feel that this proposal compares to those?


Java is a huge poster child for object oriented programming, which is 
often misunderstood to be primarily about inheritance. Still, 
collections of Java best practices invariably include strongly worded 
advice for preferring composition over inheritance, and I especially 
like the following rule:


Design and document for inheritance or else prohibit it.
-- Joshua Bloch: Effective Java. Addison-Wesley, 2001.

Even in Java, it is a bad idea to leave classes subclassable; but 
having to remember to add final is a chore.


SE-0117 takes this a step further by allowing package writers to use 
inheritance internally when it makes sense, without also having to take 
on the complications arising from allowing third-party inheritance -- 
such as having to write a reasonably complete unit test suite for 
superclass-subclass interactions. This is an interesting improvement 
over final-by-default (which I'd also support).


	* How much effort did you put into your review? A glance, a quick 
reading, or an in-depth study?


I carefully read it, drank a cup of my favorite beverage to celebrate 
its existence, then I collected my thoughts.


--
Karoly
@lorentey


On 2016-07-05 23:11:17 +, Chris Lattner via swift-evolution said:


Hello Swift community,

The review of "SE-0117: Default classes to be non-subclassable 
publicly" begins now and runs through July 11. The proposal is 
available here:


 
https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md 



Reviews are an important part of the Swift evolution process. All 
reviews should be sent to the swift-evolution mailing list at


https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the 
review manager.


What goes into a review?

The goal of the review process is to improve the proposal under review 
through constructive criticism and contribute to the direction of 
Swift. When writing your review, here are some questions you might want 
to answer in your review:


* What is your evaluation of the proposal?
	* Is the problem being addressed significant enough to warrant a 
change to Swift?

* Does this proposal fit well with the feel and direction of Swift?
	* If you have used other languages or libraries with a similar 
feature, how do you feel that this proposal compares to those?
	* How much effort did you put into your review? A glance, a quick 
reading, or an in-depth study?


More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

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



--
Károly
@lorentey


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


Re: [swift-evolution] [Review] SE-0104: Protocol-oriented integers

2016-06-26 Thread Károly Lőrentey via swift-evolution

> On 2016-06-25, at 14:23, Nicola Salmoria via swift-evolution 
>  wrote:
> The first comment I have to make is that, as has already been noted by plx,
> the Arithmetic protocol looks like a "bag of syntax" with loose semantics
> attached. It will be used by signed integers, unsigned integers (naturals),
> floating point numbers; and is an obvious conformance for a Rational type as
> well.
> In the proposal, there is no indication of the expected semantics of the
> four basic operations.
> - Are addition and multiplication commutative?
> - Is multiplication distributive over addition?
> - Is 'rhs != 0' a precondition for division?
> - Presumably associativity must match the associativity of the operators.
> - What is (a / b) * b?
> - Is T(exactly: n) * x guaranteed to be == (x + ... + x) n times?

I’m not sure if this has been mentioned yet, but the semantics of Integer 
operations also needs to be tied down. In particular, the expected behavior of 
the remainder operation (in all forms) when given a negative numerator and/or 
denumerator should be explicitly spelled out.

> Now about the AbsoluteValue associatedtype, which several other people have
> already shown doubts about.
> I found it useful, precisely for the reason stated in the proposal
> (generating the description of a Rational). However, it seems to be mostly
> an implementation detail, used to:
> 1) work around the fact that -Int.min isn't representable in two's complement;
> 2) provide a way to get the unsigned version of an integer type, to be used
> by the doubleWidthMultiply() return type.
> 
> These uses suggest that the Integer protocol might not be the best place for
> this associatedtype: both of the use cases above would not apply to a
> BigInt. It seems more appropriate for it to be part of FixedWidthInteger.
> It might even make sense to rename it UnsignedSelf, to make it clear that
> it's intended to be the unsigned equivalent of Self.

I think absoluteValue would be a better fit in SignedInteger or 
SignedArithmetic. But if implementation experience suggests it should be in 
Integer, I don’t mind including AbsoluteValue as an alias to Self (or BigUInt) 
in the BigInt case.

I’m also a bit suspicious of Integer's static isSigned property. What is its 
intended usecase? Why do we need it, given that we also have 
SignedInteger/UnsignedInteger protocols? (Does it ever make sense to implement 
Integer without also implementing SignedInteger or UnsignedInteger?)

> I also join Karoly's request for double-width division operations. In
> particular I would suggest:
> 
> static func doubleWidthDivideWithOverflow(_ lhs: (high: Self, low:
> AbsoluteValue), by rhs: Self) -> (partialValue: Self, overflow:
> ArithmeticOverflow)
> 
> static func doubleWidthRemainder(_ lhs: (high: Self, low: AbsoluteValue), by
> rhs: Self) -> Self
> 
> Note that I needed to use static members here, because the first argument of
> the division is not Self. Alternatively, the result of doubleWidthMultiply()
> could be a struct, so that double-width division operations could be members
> of that struct.

I suggest to combine generation of the quotient and remainder into a single 
division operation. (The implementations I know of provide both, so it makes 
sense to combine them.)

static func doubleWidthDivide(_ numerator: (high: Self, low: 
AbsoluteValue), by denumerator: Self) -> (partialQuotient: Self, remainder: 
Self, overflow: ArithmeticOverflow)

A more spoon-feeding name would be 
“doubleWidthQuotientAndRemainderWithOverflow(dividing:, by:)”, but yuck.

(I’d personally also be fine with simplifying this by requiring that the 
division not overflow, i.e., that lhs.high < rhs (assuming rhs > 0), and 
treating overflow as a precondition failure. I know Rational's addition needs 
to handle overflow, but perhaps it would be OK to move this check outside the 
function? I imagine the code is already full of branches like that.)

static func doubleWidthDivide(_ numerator: (high: Self, low: 
AbsoluteValue), by denumerator: Self) -> (quotient: Self, remainder: Self)

> These operations are difficult to implement, and are very useful.

The difficulty of their implementation might be a problem for people who want 
to implement FixedWidthInteger outside stdlib, but don’t care about supporting 
bignums or rationals. (Is that usecase desirable?) I think it would be possible 
to provide a divide-n-conquer default implementation for double-width division 
and multiplication, like the code I linked to earlier. However, without support 
for splitting a FixedWidthInteger into two narrower halves, the code for this 
would have to use nthWord, which would essentially involve implementing half of 
a bigint library. :-/

-- 
Karoly
@lorentey

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


Re: [swift-evolution] [Review] SE-0104: Protocol-oriented integers

2016-06-24 Thread Károly Lőrentey via swift-evolution
The operation I want is the inverse of doubleWidthMultiply, where you have a 
(high, low) word pair and you want to divide it by a single word, getting a 
quotient and remainder. This is an important building block for implementing 
arbitrary precision division. Intel’s DIV can do this in a single instruction, 
while doing it in code requires a lot of work:

https://github.com/lorentey/BigInt/blob/swift3/Sources/BigDigit.swift#L119-L176

> On 2016-06-24, at 20:52, Haravikk <swift-evolut...@haravikk.me> wrote:
> 
> 
>> On 24 Jun 2016, at 18:17, Károly Lőrentey via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> I’m especially stoked about `FixedWidthInteger.doubleWidthMultiply`, which 
>> will likely lead to a measurable speedup. Why is there no 
>> `doubleWidthQuotientAndRemainder` or `doubleWidthDivide`, though?
> 
> Double-width isn't needed for these as it's impossible for an integer to 
> become larger when dividing (the smallest value you can divide by and get a 
> result is 2, which will halve the value), and the remainder can't be larger 
> than the original value.
> 
> 
> Anyway, I'm hugely in favour of this proposal, it's desperately needed!

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


Re: [swift-evolution] [Review] SE-0104: Protocol-oriented integers

2016-06-24 Thread Károly Lőrentey via swift-evolution
> * What is your evaluation of the proposal?
+1 in general
> * Is the problem being addressed significant enough to warrant a change to 
> Swift?
Yes.
> * Does this proposal fit well with the feel and direction of Swift?
Yes, with some nitpicks detailed below.
> * If you have used other languages or libraries with a similar feature, how 
> do you feel that this proposal compares to those?
-
> * How much effort did you put into your review? A glance, a quick reading, or 
> an in-depth study?

An afternoon of detailed study.


As the author of a Swift package for arbitrary integers 
(https://github.com/lorentey/BigInt), I’m delighted by this proposal.

I’m especially stoked about `FixedWidthInteger.doubleWidthMultiply`, which will 
likely lead to a measurable speedup. Why is there no 
`doubleWidthQuotientAndRemainder` or `doubleWidthDivide`, though?

What is the intended behavior for `nthWord` for negative numbers? Can we 
prevent having to answer this question by e.g. moving this method down to 
UnsignedInteger? Big integer libs often use a signed magnitude representation; 
having to e.g. convert it to two’s complement on the fly to satisfy the API 
would be weird. (Also, the name `nthWord` seems unswifty to me.)

Like others on this list, I also find signBitIndex confusing. The name does not 
make much sense for unsigned integers, or signed integers that do not use an 
embedded sign bit. Is it supposed to return the width (in bits) of the binary 
representation of the integer’s absolute value? (Why -1 for zero, then? What’s 
the signBitIndex for 1?) 

I can’t find any mention of the unary bitwise not (~) operation. It should be 
in FixedWidthInteger, right?

Binary bitwise operations (or/and/xor) are in FixedWidthInteger, but I believe 
they can be implemented on big integers in a way that is perfectly consistent 
with fixed width integers. Admittedly, I don’t know of any generic algorithms 
that want these.

To support big integers better, I think IntegerLiteralConvertible should also 
be updated at some point to work in terms of machine words. (Having to 
implement StringLiteralConvertible to provide source-level support for huge 
numbers works, but it isn’t great.)

I can see myself typing foo.absoluteValue instead of abs(foo) all the time; if 
its use is to be discouraged, perhaps a less prominent name would be better.

There is a typo in the Operators section: “Arithmetic” should read “Integer” in 
these two lines:

public func % (lhs: T, rhs: T) -> T
public func %= (lhs: inout T, rhs: T)

Remark: The gyb is nice when used in moderation, but I find parts of the 
prototype overuse templating to a point that’s bordering on obfuscation. E.g., 
I found this code especially hard to read:


https://github.com/apple/swift/blob/master/test/Prototypes/Integers.swift.gyb#L1016-L1033
 


-- 
Karoly
@lorentey


> On 2016-06-23, at 02:52, Chris Lattner via swift-evolution 
>  wrote:
> 
> Hello Swift community,
> 
> The review of "SE-0104: Protocol-oriented integers" begins now and runs 
> through June 27. The proposal is available here:
> 
>   
> https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
> 
> Reviews are an important part of the Swift evolution process. All reviews 
> should be sent to the swift-evolution mailing list at
> 
>   https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> or, if you would like to keep your feedback private, directly to the review 
> manager.
> 
> What goes into a review?
> 
> The goal of the review process is to improve the proposal under review 
> through constructive criticism and contribute to the direction of Swift. When 
> writing your review, here are some questions you might want to answer in your 
> review:
> 
>   * What is your evaluation of the proposal?
>   * Is the problem being addressed significant enough to warrant a change 
> to Swift?
>   * Does this proposal fit well with the feel and direction of Swift?
>   * If you have used other languages or libraries with a similar feature, 
> how do you feel that this proposal compares to those?
>   * How much effort did you put into your review? A glance, a quick 
> reading, or an in-depth study?
> 
> More information about the Swift evolution process is available at
> 
>   https://github.com/apple/swift-evolution/blob/master/process.md
> 
> Thank you,
> 
> -Chris Lattner
> Review Manager
> 
> 
> ___
> 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] [Pitch] Retiring `where` from for-in loops

2016-06-10 Thread Károly Lőrentey via swift-evolution

On 2016-06-10 11:39:34 +, Leonardo Pessoa via swift-evolution said:

I would vow to remove where clauses altogether. Most of the times I 
used it in ifs, fors and switches I ended up thinking it hardened 
readability of my code (perhaps because of placement, but I do not 
think alternatives made it more readable) and so it was my decision to 
stop using where whenever possible in my code. Since Erica's 
performance test pointed out using guard is nearly as fast as using 
where and the core team is removing wheres from ifs, I think the ones 
in fors could go next.


Interestingly, I find where clauses in `for` to be a useful tool to 
*improve* readibility. To me, it flows much better to write & read this:


   for (start, duration) in days where calendar.isDateInWeekend(start) {
   ...
   }

rather than this:

for (start, duration) in days {
   guard calendar.isDateInWeekend(start) else { continue }
   ...
   }

or this:

for (start, duration) in days.filter({ calendar.isDateInWeekend($0.0) 
}) {
...
}

Of these three, I'd argue the first is the easiest to understand for a 
person who's never seen Swift code before. (Admittedly I doubt that's 
something languages should be optimized for, though.) The extra 
punctuation and the use of $0 instead of the loop's bindings makes the 
third approach seem especially noisy & scary.


Obviously, editorial tools like this aren't essential, and I could 
easily adapt to live without such syntactic sugar. But I do not like 
the idea of systematically ridding the language of such charming 
constructs when there is no technical reason to do so. SE-0099 fixed a 
technical problem with the syntax of a shorthand construct, without 
removing it from the language. It did not bring back Swift 1's `if` 
pyramids.




Moreover, Erica is absolutely right about `switch`: while `where` 
clauses are arguably non-essential in `for` loops, `switch` statements 
would lose a great deal of their expressive power without them. For 
example, in the following snippet (taken from a lexer in SwiftPM), all 
cases are logically at the same level. I think it's a win that Swift 
allows them to be expressed as such, and I'd strongly object to a 
proposal that removed this capability.


   switch c {
   case UInt8(ascii: "\n"): ...
   case UInt8(ascii: "#"): ...
   case let c where c.isSpace(): ...
   case UInt8(ascii: "\""): ...
   case let c where c.isNumberInitialChar(): ...
   case let c where c.isIdentifierChar(): ...
   case UInt8(ascii: ","): ...
   case UInt8(ascii: "="): ...
   case UInt8(ascii: "["): ...
   case UInt8(ascii: "]"): ...
   case UInt8(ascii: "."): ...
   default: ...
   }

Obviously, we could rewrite this to use a single `if` ladder, but I 
think most would not find that an improvement.


(The same argument applies to `catch` statements, although with less force.)

As long as `where` is kept in `switch` and `catch`, and as long the 
grammar is unambiguous, I think there is little point to removing where 
clauses from `for`. To improve consistency, I'd not mind if SE-0099 
kept `where` as an alternative way to spell `,` in `if` statements, too.


--
Károly
@lorentey


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


Re: [swift-evolution] [Review] Tuple comparison operators (was: Add a Lazy flatMap for Sequences of Optionals)

2015-12-23 Thread Károly Lőrentey via swift-evolution
+1

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

Yes.

** Does this proposal fit well with the feel and direction of Swift?

Yes, very much so. 

** If you have you used other languages or libraries with a similar feature, 
how do you feel that this proposal compares to those?

Python’s tuples are equatable and comparable the same way. This feels natural 
and useful. Rust is another example, and so is Haskell. I’m also very used to 
lexical ordering of tuples from my studies of mathematics, especially in the 
computer science branch.

The proposal fails to implement full conformance to Equatable and Comparable 
(and Hashable), but it’s a nice short-term scratch for an annoying itch.

** How much effort did you put into your review? A glance, a quick reading, or 
an in-depth study?

I read the thread and deeply considered the objections for an hour or so while 
shopping for groceries. 

** What is your evaluation of the proposal?

Equatable is a no-brainer. Even Wikipedia provides the definition of tuple 
equality, so that’s clearly OK, I think. 

Tuples emphatically aren’t the same as vectors, so I think having them sortable 
with lexical ordering is fine, and it is very convenient. (I would go so far as 
to say the same of Arrays.)

Tuple is something of a glue type — I use it when defining a named type would 
feel too verbose. As such, it is very useful to provide tuples with sensible 
semantics that make them usable in more places. 

I can also recall several instances where not having an ordering on tuples has 
inconvenienced me while writing Swift code. Having to spell out the comparator 
for the lexical order is a pain, and it is easy to get it wrong.

It is a shame we cannot yet go the full way and have tuples conform to 
Equatable, Comparable and Hashable when their components do. The proposal 
presents a weaker form of this that does not allow the use of tuples as e.g. 
keys in a Dictionary or an ordered map type, although I often want to use 
tuples in these places. But at least it allows for easy sorting of arrays 
containing tuples, which is a step in the right direction.

There is precedent in stdlib today in the form of Optional’s < overload, which 
is arguably too surprising (especially with string searching APIs returning 
Optionals). However, I don’t see a case when the tuple variant could be 
confusing like that.

The proposal doesn’t mention the nullary tuple, but I think () should also be 
comparable with itself. (And Void should naturally conform to 
Comparable/Hashable when that becomes possible.)

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