Re: [swift-evolution] SE-184 Improved Pointers

2017-08-12 Thread Taylor Swift via swift-evolution
I’ve revised the proposal based on what I learned from trying to implement
these changes. I think it’s worth tacking the existing methods that take
Sequences at the same time as this actually makes the design a bit simpler.


*The previous version
 of this
document ignored the generic initialization methods on
UnsafeMutableBufferPointer and UnsafeMutableRawBufferPointer, leaving them
to be overhauled at a later date, in a separate proposal. Instead, this
version of the proposal leverages those existing methods to inform a more
compact API design which has less surface area, and is more future-proof
since it obviates the need to design and add another (redundant) set of
protocol-oriented pointer APIs later.*

On Tue, Aug 8, 2017 at 12:52 PM, Taylor Swift  wrote:

> Since Swift 5 just got opened up for proposals, SE-184 Improved Pointers
> is ready for community review, and I encourage everyone to look it over and
> provide feedback. Thank you!
>  proposals/0184-improved-pointers.md>
>
>
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility - defaults

2017-08-12 Thread Rod Brown via swift-evolution
Yes, I see your point, and that’s something I didn’t consider. If we allowed 
extending enums, this would then clearly indicate that “final” means something 
in the present as well - you cannot add cases.

This opens up the can of worms of extending enums, but I think it’s a fair 
point if we ever want to consider it that then “final" really would make the 
most sense.


> On 12 Aug 2017, at 8:28 am, Jordan Rose  wrote:
> 
> "final"'s on my list of possible names! But it's not quite the same as 
> 'final' for classes: "closed" only talks about what might change in the 
> future, while 'final'-on-a-class also states something about the class in the 
> present: it has no subclasses now as well as not gaining any new ones in the 
> future. Still, it could be closed enough that it ends up being the best bet.
> 
> Jordan
> 
> 
>> On Aug 10, 2017, at 22:23, Rod Brown > > wrote:
>> 
>> Hi all,
>> 
>> I thought I’d chime in with my own 2c…
>> 
>> I’d probably prefer something more like “final” and vs non-final. It’s the 
>> concept we’re dancing around - can you add something to extend it?
>> 
>> In which case, final would allow exhaustive use, and non-final would require 
>> handling the default case. Currently all Swift API would convert as “final”, 
>> and all imported Obj-C API (with perhaps exceptions) would import as is and 
>> require a default handling case. This negates the open vs public issue. But 
>> it does also mean that it would become a manual issue inside the module to 
>> mark the API as final to allow exhaustive switches, unless we say 
>> “exhaustive switches allowed on internal/fileprivate/private types”.
>> 
>> Unsure how this plays into the web of things, though…
>> 
>> Thanks,
>> 
>> Rod
>> 
>> 
>> 
>>> On 11 Aug 2017, at 9:41 am, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> 
>>> 
 On Aug 10, 2017, at 13:00, David Hart > wrote:
 
 
 
 On 10 Aug 2017, at 19:19, Jordan Rose > wrote:
 
> 
> 
>> On Aug 9, 2017, at 22:46, David Hart > > wrote:
>> 
>> 
>>> On 10 Aug 2017, at 02:42, Jordan Rose >> > wrote:
>>> 
>>> :-) As you've all noted, there are some conflicting concerns for the 
>>> default:
>>> 
>>> - Source compatibility: the existing behavior for an unannotated enum 
>>> is "closed".
>>> - Intuition: if you show someone an enum without an explicit 
>>> annotation, they'll probably expect they can switch over it. (I'm going 
>>> to say this is why Zach calls it a "sensible default".)
>>> - Consistency: switches on an enum in the same module can always be 
>>> exhaustive, so having it be different across modules is a bit annoying. 
>>> (But 'public' already acts like this.)
>>> 
>>> vs.
>>> 
>>> - Library evolution: the default should promise less, so that you have 
>>> the opportunity to change it.
>>> - Flexibility: you can emulate an exhaustive switch with a 
>>> non-exhaustive switch using fatalError, but not the other way around.
>>> 
>>> All of this is why I suggested it be an explicit annotation in either 
>>> direction, but Matthew brought up the "keyword soup" problem—if you 
>>> have to write (say) "public finite enum" and "public infinite enum", 
>>> but would never write "private finite enum" or "private infinite enum", 
>>> something is redundant here. Still, I'm uncomfortable with the default 
>>> case being the one that constrains library authors, so at least for 
>>> binary frameworks (those compiled "with resilience") I would want that 
>>> to be explicit. That brings us to one more concern: how different 
>>> should binary frameworks be from source frameworks?
>> 
>> In terms of intuition and consistency, I think we should really try to 
>> learn from the simplicity of public/open:
>> 
>> * When internal, classes are sub-classable by default for convenience, 
>> but can be closed with the final keyword
>> * When public, classes are closed to sub-classing for safety, but can be 
>> opened up with the open keyword (which implies public).
>> 
>> If we try to mirror this behaviour (the keywords are just suggestions, 
>> not important):
>> 
>> * When internal, enums are exhaustive by default for convenience, but 
>> can be opened-up with the partial keyword
>> * When public, enums are non-exhaustive by default for safety, but can 
>> be made exhaustive with the exhaustive keyword (which implies public).
> 
> This is not a correct understanding of the internal/public distinction 

Re: [swift-evolution] SE-184 Improved Pointers

2017-08-12 Thread Taylor Swift via swift-evolution
okay so I’m implementing  this rn, and i
just realized that the functions
UnsafeMutableRawBufferPointer.initializeMemory(as:from:count:) and
UnsafeMutableRawBufferPointer.moveInitializeMemory(as:from:count:) are
gonna be a problem. Since they take a strided buffer pointer as its
argument, should they lose the count: argument and take the count value
from source.count? However, this would go opposite of the direction in most
of the typed buffer pointer methods, where count comes from self.count, not
source.count.

On Wed, Aug 9, 2017 at 11:51 AM, Taylor Swift via swift-evolution <
swift-evolution@swift.org> wrote:

>
>
> On Wed, Aug 9, 2017 at 2:34 AM, Andrew Trick  wrote:
>
>>
>> On Aug 8, 2017, at 11:10 PM, Taylor Swift  wrote:
>>
>>
>> On Wed, Aug 9, 2017 at 1:51 AM, Andrew Trick  wrote:
>>
>>>
>>> On Aug 8, 2017, at 8:44 PM, Taylor Swift  wrote:
>>>
>>> cool,, as for UnsafeMutableRawBufferPointer.copy(from:bytes:), I cannot
>>> find such a function anywhere in the API. There is copyBytes(from:)
>>> ,
>>> but the documentation is messed up and mentions a nonexistent count:
>>> argument over and over again. The documentation also doesn’t mention what
>>> happens if there is a length mismatch, so users are effectively relying on
>>> an implementation detail. I don’t know how to best resolve this.
>>>
>>>
>>> We currently have `UnsafeMutableRawBufferPointer.copyBytes(from:)`. I
>>> don’t think your proposal changes that. The current docs refer to the
>>> `source` parameter, which is correct. Docs refer to the parameter name, not
>>> the label name. So `source.count` is the size of the input. I was pointing
>>> out that it has the semantics: `debugAssert(source.count <= self.count)`.
>>>
>>> Your proposal changes `UnsafeRawPointer.copyBytes(from:count:)` to
>>> `UnsafeRawPointer.copy(from:bytes:)`. Originally we wanted to those API
>>> names to match, but I’m fine with your change. What is more important is
>>> that the semantics are the same as `copyBytes(from:)`. Furthermore, any new
>>> methods that you add that copy into a raw buffer (e.g.
>>> initializeMemory(as:from:count:)) should have similar behavior.
>>>
>>>
>> I’m fine with switching to taking the count from the source, though I
>> think taking the count from the destination is slightly better because
>> 1) the use cases I mentioned in the other email, and 2) all the other
>> memorystate functions use self.count instead of source.count, if they
>> take a source argument. But being consistent with the raw pointer
>> version is more important.
>>
>>
>> If it’s copying from a buffer it should not take a count, if it’s copying
>> from a pointer it obviously needs to take a count. What I mean by the two
>> versions being named consistently is simply that they’re both named
>> `copyBytes`. That really isn’t important though. The overflow/underflow
>> semantics being consistent are important.
>>
>> (Incidentally, the reason “bytes” needs to be in the somewhere name is
>> because this method isn’t capable of copying nontrivial values)
>>
>> Should the methods that don’t deal with raw buffers also be modified to
>> use the source argument (i.e. UnsafeMutableBufferPointer.ini
>> tialize(from:))?
>>
>>
>> I’m not sure what you mean by this. It also allows the destination to be
>> larger than the source. Initializing from a sequence does not trap on
>> overflow because we can’t guarantee the size of the sequence ahead of time.
>> When I talk about consistent overflow/underflow semantics, I’m only talking
>> about initializing one unsafe buffer/pointer from another unsafe
>> buffer/pointer.
>>
>> Also, was there a reason why UnsafeMutableRawBufferPointer.
>> copyBytes(from:) uses the source’s count instead of its own? Right now
>> this behavior is “technically” undocumented behavior (as the public docs
>> haven’t been updated) so if there was ever a time to change it, now would
>> be it.
>>
>>
>> Mainly because partial initialization is more expected than dropping data
>> on the floor. Ultimately, this should be whatever typical developers would
>> expect the behavior to be. I would be very hesitant to change the behavior
>> now though.
>>
>> -Andy
>>
>
> The problem is I would expect to be able to safely call deinitialize() and
> friends after calling initialize(from:). If Element is a class type and
> initialize doesn’t fill the entire buffer range, calling deinitialize()
> will crash. That being said, since copy(from:bytes:) and copyBytes(from:)
> don’t do any initialization and have no direct counterparts in
> UnsafeMutableBufferPointer, it’s okay if they have different behavior than
> the other methods.
>
>
>>
>> —
>>>
>>> Another thing. The initialization methods that you’re adding to
>>> `UnsafeRawPointer` and `UnsafeRawBufferPointer` should