Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-09 Thread Joe Groff via swift-evolution

> On May 9, 2016, at 2:28 PM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> 
>> Right, you'd need to do NSString(string) as AnyObject to explicitly bridge. 
> 
> Okay great I'm fine with that. :)
> 
>> The @objc-ness of AnyObject is more or less an implementation detail. On 
>> Darwin platforms at least, AnyObject still has the magic ability to dispatch 
>> to all @objc methods, similar to `id` in Objective-C, which vaguely defends 
>> its @objc-ness. (If we're going to rename it, my own preference would be to 
>> drop the Any and just call it `Object`, since we don't put Any in any other 
>> protocol names.) 
> 
> Did I miss something again? I checked SR-0006 and it still has protocols like 
> `Any`, `AnyIterator` or `AnyCollectionProtocol`.

"Any" is a typealias for the protocol type without any protocol requirements, 
which is natively spelled "protocol<>". "AnyIterator" and "AnyCollection" are 
both wrapper types for holding a value that conforms to the Iterator or 
Collection protocol; they aren't protocols themselves.

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-09 Thread Adrian Zubarev via swift-evolution

> Right, you'd need to do NSString(string) as AnyObject to explicitly bridge.  

Okay great I'm fine with that. :)  

> The @objc-ness of AnyObject is more or less an implementation detail. On 
> Darwin platforms at least, AnyObject still has the magic ability to dispatch 
> to all @objc methods, similar to `id` in Objective-C, which vaguely defends 
> its @objc-ness. (If we're going to rename it, my own preference would be to 
> drop the Any and just call it `Object`, since we don't put Any in any other 
> protocol names.)  

Did I miss something again? I checked SR-0006 and it still has protocols like 
`Any`, `AnyIterator` or `AnyCollectionProtocol`.  
--  
Adrian Zubarev  

Am 9. Mai 2016 um 21:38:22, Joe Groff 
(jgr...@apple.com(mailto:jgr...@apple.com)) schrieb:

>  
>  
> > On May 6, 2016, at 12:04 AM, Adrian Zubarev via swift-evolution 
> >  wrote:
> >  
> > Definitely a welcome change from me (+1). But this proposal makes me 
> > curious about the impact on the `AnyObject` protocol?
> >  
> > let string = "foo"
> > let nsString = string as AnyObject
> > nsString.dynamicType // _NSCFConstantString.Type
> > NSString().dynamicType // __NSCFConstantString.Type // there are two 
> > different types?
> >  
> > This sample won’t bridge anymore if SE-0083 will be accepted.
>  
> Right, you'd need to do NSString(string) as AnyObject to explicitly bridge.
>  
> > Can we also drop the @objc from `AnyObject` protocol and leave it as an 
> > implicit protocol for classes? (Personally I’d rename `AnyObject` to 
> > `AnyReference` if Swift will introduce other reference types.)
>  
> The @objc-ness of AnyObject is more or less an implementation detail. On 
> Darwin platforms at least, AnyObject still has the magic ability to dispatch 
> to all @objc methods, similar to `id` in Objective-C, which vaguely defends 
> its @objc-ness. (If we're going to rename it, my own preference would be to 
> drop the Any and just call it `Object`, since we don't put Any in any other 
> protocol names.)
>  
> > This change might allow the replacement of the `class` keyword from 
> > protocols with the implicit `AnyObject` protocol, which can be discussed in 
> > this thread: Should we rename "class" when referring to protocol 
> > conformance?
> >  
> > One more thing I’d like to ask: is there any possibility of adding a new 
> > `bridge` keyword, which would allow explicit bridging to a different 
> > language type (ObjC, etc. if there are any more languages we can bridge to 
> > [C or maybe one day C++])?
> >  
> > T `bridge` U
> > T? `bridge` U?
>  
> One could write `bridge` as a method in most cases; it doesn't need to be a 
> keyword with special syntax, since you could write `T.bridge(U.self)` (or, if 
> we accept https://github.com/apple/swift-evolution/pull/299, `T.bridge(U)`). 
> Idiomatically, though, we generally use initializers for value-preserving 
> conversions, so U(T) would be more consistent with the rest of the standard 
> library.
>  
> -Joe
>  
> > The ugly NSError pattern could be rewritten and migrated to:
> >  
> > do {
> > try something()
> > } catch let error {
> > handle(error `bridge` NSError)
> > }
> >  
> > Is such a change complicated, what do you think?
> >  
> > --
> > Adrian Zubarev
> > Sent with Airmail
> >  
> > Am 4. Mai 2016 bei 01:50:54, Joe Groff via swift-evolution 
> > (swift-evolution@swift.org) schrieb:
> >  
> > > Thanks everyone for the initial round of feedback. I've submitted a draft 
> > > proposal:
> > >  
> > > https://github.com/apple/swift-evolution/pull/289
> > > https://github.com/jckarter/swift-evolution/blob/remove-bridging-conversion-dynamic-casts/proposals/-remove-bridging-from-dynamic-casts.md
> > >  
> > > -Joe
> > > ___
> > > 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
>  
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-09 Thread Charles Srstka via swift-evolution
> On May 6, 2016, at 2:04 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> The ugly NSError pattern could be rewritten and migrated to:
> 
> do {
>try something()
> } catch let error {
>handle(error `bridge` NSError)
> }
> 
> Is such a change complicated, what do you think?

I’ve made a pitch, "Consistent bridging for NSErrors at the language boundary”, 
which I believe would not only eliminate the need for “as” to contain bridging 
magic, but is also much less ugly than either the current pattern or the 
example above.

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016618.html
 


Charles

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-09 Thread Joe Groff via swift-evolution

> On May 6, 2016, at 12:04 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> Definitely a welcome change from me (+1). But this proposal makes me curious 
> about the impact on the `AnyObject` protocol?
> 
> let string = "foo"
> let nsString = string as AnyObject
> nsString.dynamicType // _NSCFConstantString.Type
> NSString().dynamicType // __NSCFConstantString.Type // there are two 
> different types? 
> 
> This sample won’t bridge anymore if SE-0083 will be accepted.

Right, you'd need to do NSString(string) as AnyObject to explicitly bridge.

> Can we also drop the @objc from `AnyObject` protocol and leave it as an 
> implicit protocol for classes? (Personally I’d rename `AnyObject` to 
> `AnyReference` if Swift will introduce other reference types.)

The @objc-ness of AnyObject is more or less an implementation detail. On Darwin 
platforms at least, AnyObject still has the magic ability to dispatch to all 
@objc methods, similar to `id` in Objective-C, which vaguely defends its 
@objc-ness. (If we're going to rename it, my own preference would be to drop 
the Any and just call it `Object`, since we don't put Any in any other protocol 
names.)

> This change might allow the replacement of the `class` keyword from protocols 
> with the implicit `AnyObject` protocol, which can be discussed in this 
> thread: Should we rename "class" when referring to   protocol conformance?
> 
> One more thing I’d like to ask: is there any possibility of adding a new 
> `bridge` keyword, which would allow explicit bridging to a different language 
> type (ObjC, etc. if there are any more languages we can bridge to [C or maybe 
> one day C++])?
> 
> T `bridge` U
> T? `bridge` U?

One could write `bridge` as a method in most cases; it doesn't need to be a 
keyword with special syntax, since you could write `T.bridge(U.self)` (or, if 
we accept https://github.com/apple/swift-evolution/pull/299, `T.bridge(U)`). 
Idiomatically, though, we generally use initializers for value-preserving 
conversions, so U(T) would be more consistent with the rest of the standard 
library.

-Joe

> The ugly NSError pattern could be rewritten and migrated to:
> 
> do {
>try something()
> } catch let error {
>handle(error `bridge` NSError)
> }
> 
> Is such a change complicated, what do you think?
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 4. Mai 2016 bei 01:50:54, Joe Groff via swift-evolution 
> (swift-evolution@swift.org) schrieb:
> 
>> Thanks everyone for the initial round of feedback. I've submitted a draft 
>> proposal:
>> 
>> https://github.com/apple/swift-evolution/pull/289
>> https://github.com/jckarter/swift-evolution/blob/remove-bridging-conversion-dynamic-casts/proposals/-remove-bridging-from-dynamic-casts.md
>> 
>> -Joe
>> ___
>> 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

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-09 Thread Joe Groff via swift-evolution

> On May 6, 2016, at 7:24 PM, Jose Cheyo Jimenez  wrote:
> 
> Hi Joe, 
> 
> Would I still be able to cast an AnyObject to a String or Array etc?

You would do so via constructors rather than using `as?`, something like 
String(bridging: object).

-Joe

> I am thinking about working with JSON files and using the Apple JSON Parser. 
> 
> Thanks
> 
> 
> 
>> On May 3, 2016, at 4:50 PM, Joe Groff via swift-evolution 
>>  wrote:
>> 
>> Thanks everyone for the initial round of feedback. I've submitted a draft 
>> proposal:
>> 
>> https://github.com/apple/swift-evolution/pull/289
>> https://github.com/jckarter/swift-evolution/blob/remove-bridging-conversion-dynamic-casts/proposals/-remove-bridging-from-dynamic-casts.md
>> 
>> -Joe
>> ___
>> 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] Reducing the bridging magic in dynamic casts

2016-05-06 Thread Jose Cheyo Jimenez via swift-evolution
Hi Joe, 

Would I still be able to cast an AnyObject to a String or Array etc?

I am thinking about working with JSON files and using the Apple JSON Parser. 

Thanks



> On May 3, 2016, at 4:50 PM, Joe Groff via swift-evolution 
>  wrote:
> 
> Thanks everyone for the initial round of feedback. I've submitted a draft 
> proposal:
> 
> https://github.com/apple/swift-evolution/pull/289
> https://github.com/jckarter/swift-evolution/blob/remove-bridging-conversion-dynamic-casts/proposals/-remove-bridging-from-dynamic-casts.md
> 
> -Joe
> ___
> 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] Reducing the bridging magic in dynamic casts

2016-05-06 Thread Adrian Zubarev via swift-evolution
Definitely a welcome change from me (+1). But this proposal makes me curious 
about the impact on the `AnyObject` protocol?

let string = "foo"
let nsString = string as AnyObject
nsString.dynamicType // _NSCFConstantString.Type
NSString().dynamicType // __NSCFConstantString.Type // there are two different 
types? 

This sample won’t bridge anymore if SE-0083 will be accepted. Can we also drop 
the @objc from `AnyObject` protocol and leave it as an implicit protocol for 
classes? (Personally I’d rename `AnyObject` to `AnyReference` if Swift will 
introduce other reference types.)

This change might allow the replacement of the `class` keyword from protocols 
with the implicit `AnyObject` protocol, which can be discussed in this thread: 
Should we rename "class" when referring to protocol conformance?

One more thing I’d like to ask: is there any possibility of adding a new 
`bridge` keyword, which would allow explicit bridging to a different language 
type (ObjC, etc. if there are any more languages we can bridge to [C or maybe 
one day C++])?

T `bridge` U
T? `bridge` U?

Wouldn’t this move the bridging mechanism to its own area?

The ugly NSError pattern could be rewritten and migrated to:

do {
   try something()
} catch let error {
   handle(error `bridge` NSError)
}

Is such a change complicated, what do you think?

-- 
Adrian Zubarev
Sent with Airmail

Am 4. Mai 2016 bei 01:50:54, Joe Groff via swift-evolution 
(swift-evolution@swift.org) schrieb:

Thanks everyone for the initial round of feedback. I've submitted a draft 
proposal:

https://github.com/apple/swift-evolution/pull/289
https://github.com/jckarter/swift-evolution/blob/remove-bridging-conversion-dynamic-casts/proposals/-remove-bridging-from-dynamic-casts.md

-Joe
___
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] Reducing the bridging magic in dynamic casts

2016-05-03 Thread Joe Groff via swift-evolution
Thanks everyone for the initial round of feedback. I've submitted a draft 
proposal:

https://github.com/apple/swift-evolution/pull/289
https://github.com/jckarter/swift-evolution/blob/remove-bridging-conversion-dynamic-casts/proposals/-remove-bridging-from-dynamic-casts.md

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-03 Thread Charles Srstka via swift-evolution
Here’s another argument in favor of the pitch:

Take an array:

let array = ["Foo", "Bar”]

We can convert this to an NSArray via the bridge:

let nsArray = array as NSArray

We can also convert this to a CFArray:

let cfArray = array as CFArray

Now, let’s convert them back.

let nsUntypedArray = nsArray as Array
let cfUntypedArray = cfArray as Array

This works, but both arrays are now Array, which probably isn’t what 
we want. Since Swift arrays care about type, and NS/CFArrays generally don’t, 
we’ll want to do a check when converting them back:

let nsToNativeArray = nsArray as? Array
let cfToNativeArray = cfArray as? Array

Checking the value of the first one there, we get a nice Optional(["Foo", 
"Bar”]), as expected. However, checking the second one reveals that it now 
contains *nil!* Worse, the bug won’t be discovered until runtime, and may be 
hard to track down, since the code above *looks* fine.

Adding an intermediate cast to NSArray, of course, makes it work fine:

let cfToNativeArray = cfArray as NSArray? as? Array // Optional(["Foo", 
"Bar"])

This may be a bug, maybe even a known one. However, if this had been done via 
initializers on Array rather than via bridging magic, the compiler would have 
thrown a type error when we tried to pass a CFArray to Array’s initializer if 
Array didn’t have an initializer that took a CFArray. The bridge, however, just 
cheerfully returns nil at runtime, leaving you with no idea something’s wrong 
until it all blows up mysteriously at runtime.

So basically, I guess I’m +1 on the pitch.

Charles

> On Apr 29, 2016, at 5:00 PM, Joe Groff via swift-evolution 
>  wrote:
> 
> When we introduced Swift, we wanted to provide value types for common 
> containers, with the safety and state isolation benefits they provide, while 
> still working well with the reference-oriented world of Cocoa. To that end, 
> we invested a lot of work into bridging between Swift’s value semantics 
> containers and their analogous Cocoa container classes. This bridging 
> consisted of several pieces in the language, the compiler, and the runtime:
> 
> Importer bridging, importing Objective-C APIs that take and return NSString, 
> NSArray, NSDictionary and NSSet so that they take and return Swift’s 
> analogous value types instead.
> 
> Originally, the language allowed implicit conversions in both directions 
> between Swift value types and their analogous classes. We’ve been working on 
> phasing the implicit conversions out—we removed the object-to-value implicit 
> conversion in Swift 1.2, and propose to remove the other direction in 
> SE–0072—but the conversions can still be performed by an explicit coercion 
> string as NSString. These required-explicit as coercions don’t otherwise 
> exist in the language, since as generally is used to force coercions that can 
> also happen implicitly, and value-preserving conversions are more 
> idiomatically performed by constructors in the standard library.
> 
> The runtime supports dynamic bridging casts. If you have a value that’s 
> dynamically of a Swift value type, and try to as?, as!, or is-cast it to its 
> bridged Cocoa class type, the cast will succeed, and the runtime will apply 
> the bridging conversion:
> 
> // An Any that dynamically contains a value "foo": String
> let x: Any = "foo"
> // Cast succeeds and produces the bridged "foo": NSString
> let y = x as! NSString 
> Since Swift first came out, Cocoa has done a great job of “Swiftification”, 
> aided by new Objective-C features like nullability and lightweight generics 
> that have greatly improved the up-front quality of importer-bridged APIs. 
> This has let us deemphasize and gradually remove the special case implicit 
> conversions from the language. I think it’s time to consider extricating them 
> from the dynamic type system as well, making it so that as?, as!, and is 
> casts only concern themselves with typechecks, and transitioning to using 
> standard initializers and methods for performing bridging conversions. I’d 
> like to propose the following changes:
> 
> Dynamic casts as?, as! and is should no longer perform bridging conversions 
> between value types and Cocoa classes.
> Coercion syntax as should no longer be used to explicitly force certain 
> bridging conversions.
> To replace this functionality, we should add initializers to bridged value 
> types and classes that perform the value-preserving bridging operations.
> The Rules of as[?]
> 
> Our original goal implementing this behavior into the dynamic casting 
> machinery was to preserve some transitivity identities between implicit 
> conversions and casts that users could reason about, including:
> 
> x as! T as! U === x as! U, if x as! T succeeds. Casting to a type U should 
> succeed and give the same result for any derived cast result.
> x as! T as U === x as! U. If T is coercible to U, then you should get the 
> same result by casting to Tand coercing to U as by 

Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-03 Thread J.D. Healy via swift-evolution
Confused about getAsNSString from bullet point 5, used again in bullet
point 8 — the function wont compile for me:


> Check whether a value is _ObjectiveCBridgeable to a class, or conversely,
> that an object is _ObjectiveCBridgeable to a value type, and perform the
> bridging conversion if so:
>
> func getAsString(value: T) -> String? {
>   return value as? String
> }func getAsNSString(value: T) -> NSString {
>   return value as? NSString
> }
>
> getAsString(value: "string") // produces "string": String
> getAsNSString(value: "string") // produces "string": NSString
> let ns = NSString("nsstring")
> getAsString(value: ns) // produces "nsstring": String
> getAsNSString(value: ns) // produces "nsstring": NSString
>
>
Drill through Optionals. If an Optional contains some value, it is
> extracted, and the cast is attempted on the contained value; the cast fails
> if the source value is none and the result type is not optional:
>
> var x: String? = "optional string"
> getAsNSString(value: x) // produces "optional string": NSString
> x = nilgetAsNSString(value: x) // fails
>
> $ 
> /Applications/Xcode-7D1010.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift
Welcome to Apple Swift version 2.2 (swiftlang-703.0.18.5
clang-703.0.31). Type :help for assistance.
  1> import Foundation
  2>
  3> func getAsNSString(value: T) -> NSString {
  4.   return value as? NSString
  5. }
repl.swift:4:16: error: value of optional type 'NSString?' not
unwrapped; did you mean to use '!' or '?'?
  return value as? NSString
   ^
 ( )!

  3>

$ 
/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a.xctoolchain/usr/bin/swift
Welcome to Apple Swift version 3.0-dev (LLVM 752e1430fc, Clang
3987718dae, Swift 36739f7b57). Type :help for assistance.
  1> import Foundation
  2>
  3> func getAsNSString(value: T) -> NSString {
  4.   return value as? NSString
  5. }
error: repl.swift:4:16: error: value of optional type 'NSString?' not
unwrapped; did you mean to use '!' or '?'?
  return value as? NSString
   ^
 ( )!

I would think the function was meant to end -> NSString?, if not for the //
fails comment in bullet 8. Could you clarify?

– J.D. Healy
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-03 Thread Joe Groff via swift-evolution

> On May 3, 2016, at 8:48 AM, J.D. Healy  wrote:
> 
> Confused about getAsNSString from bullet point 5, used again in bullet point 
> 8 — the function wont compile for me:

There's a typo. getAsNSString needs to return an optional, `NSString?`, because 
the cast produces nil if it fails.

-Joe

>  
> Check whether a value is _ObjectiveCBridgeable to a class, or conversely, 
> that an object is _ObjectiveCBridgeable to a value type, and perform the 
> bridging conversion if so:
> func getAsString
> (value: T) -> String? {
>   
> return value as
> ? String
> }
> 
> func getAsNSString
> (value: T) -> NSString {
>   
> return value as
> ? NSString
> }
> 
> getAsString(value: 
> "string") // produces "string": String
> 
> getAsNSString(value: 
> "string") // produces "string": NSString
> 
> 
> 
> let ns = NSString("nsstring"
> )
> getAsString(value: ns) 
> // produces "nsstring": String
> 
> getAsNSString(value: ns) 
> // produces "nsstring": NSString
> 
> Drill through Optionals. If an Optional contains some value, it is extracted, 
> and the cast is attempted on the contained value; the cast fails if the 
> source value is none and the result type is not optional:
> 
> var x: String? = "optional string"
> 
> getAsNSString(
> value: x) // produces "optional string": NSString
> 
> x = nil
> 
> getAsNSString(value: x) // fails
> $ 
> /Applications/Xcode-7D1010.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift
> Welcome to Apple Swift version 2.2 (swiftlang-703.0.18.5 clang-703.0.31). 
> Type :help for assistance.
>   1> import Foundation
>   2>
>   3> func getAsNSString(value: T) -> NSString {
>   4.   return value as? NSString
>   5. }
> repl.swift:4:16: error: value of optional type 'NSString?' not unwrapped; did 
> you mean to use '!' or '?'?
>   return value as? NSString
>^
>  ( )!
> 
>   3>
> 
> $ 
> /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a.xctoolchain/usr/bin/swift
> Welcome to Apple Swift version 3.0-dev (LLVM 752e1430fc, Clang 3987718dae, 
> Swift 36739f7b57). Type :help for assistance.
>   1> import Foundation
>   2>
>   3> func getAsNSString(value: T) -> NSString {
>   4.   return value as? NSString
>   5. }
> error: repl.swift:4:16: error: value of optional type 'NSString?' not 
> unwrapped; did you mean to use '!' or '?'?
>   return value as? NSString
>^
>  ( )!
> 
> I would think the function was meant to end -> NSString?, if not for the // 
> fails comment in bullet 8. Could you clarify?
> 
> – J.D. Healy
> 

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-02 Thread T.J. Usiyan via swift-evolution
+1 to this. `as` is a hairy beast.

On Mon, May 2, 2016 at 8:45 PM, Charles Srstka via swift-evolution <
swift-evolution@swift.org> wrote:

> On May 2, 2016, at 4:48 PM, Erica Sadun via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>
> On May 2, 2016, at 3:45 PM, Chris Lattner via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> NSError bridging can also be extracted from the runtime, and the same
> functionality exposed as a factory initializer on NSError:
>
> I think that this proposal is overall really great, but what does it do to
> the “catch let x as NSError” pattern?  What is the replacement?  If the
> result is ugly, we may have to subset out NSError out of this pass, and
> handle it specifically with improvements to the error bridging story.
>
>
> Grant me the serenity to accept the `NSError` I cannot change and
> the courage to change the bridging conversions I should. Grant me the
> wisdom to know the difference between a partial solution that offers a
> cleaner more predictable interface set now and a full solution that cannot
> be achieved in a reasonable timeframe.
>
> -- E
>
>
> Among the things that Billy Pilgrim could not change were the past, the
> present, and the future. Hopefully we have better luck, because the
> ErrorType to NSError bridging is currently a bit buggy.
>
> Have a look at this code, and take a guess at what the results should be:
>
> import Foundation
>
> extension ErrorType {
> public func toNSError() -> NSError {
> return self as NSError
> }
> }
>
> let error = NSError(domain: "Foo", code: -1, userInfo:
> [NSLocalizedFailureReasonErrorKey : "Something went wrong"])
>
> let ns = error.toNSError()
>
> print("Type of error was \(error.dynamicType), type of ns is
> \(ns.dynamicType)")
>
> print("error's user info: \(error.userInfo)")
> print("ns user info: \(ns.userInfo)”)
>
> --
>
> The results are a bit surprising:
>
> Type of error was NSError, type of ns is _SwiftNativeNSError
> error's user info: [NSLocalizedFailureReason: Something went wrong]
> ns user info: [:]
>
> What happened was:
>
> 1. The toNSError() method showed up for our NSError, since NSError is
> presented to Swift as conforming to ErrorType.
>
> 2. However, due to a lack of dynamism, the code in the extension assumes
> that we have a Swift native error and *not* an NSError, so it goes ahead
> and wraps the NSError inside another NSError.
>
> 3. And since Swift doesn’t currently do anything to address the userInfo
> field, the userInfo that our error had gets chopped off.
>
> Whoops.
>
> Charles
>
>
> ___
> 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] Reducing the bridging magic in dynamic casts

2016-05-02 Thread Charles Srstka via swift-evolution
> On May 2, 2016, at 4:48 PM, Erica Sadun via swift-evolution 
>  wrote:
> 
>> On May 2, 2016, at 3:45 PM, Chris Lattner via swift-evolution 
>> > wrote:
>>> NSError bridging can also be extracted from the runtime, and the same 
>>> functionality exposed as a factory initializer on NSError:
>>> 
>> 
>> I think that this proposal is overall really great, but what does it do to 
>> the “catch let x as NSError” pattern?  What is the replacement?  If the 
>> result is ugly, we may have to subset out NSError out of this pass, and 
>> handle it specifically with improvements to the error bridging story.
> 
> Grant me the serenity to accept the `NSError` I cannot change and the courage 
> to change the bridging conversions I should. Grant me the wisdom to know the 
> difference between a partial solution that offers a cleaner more predictable 
> interface set now and a full solution that cannot be achieved in a reasonable 
> timeframe.
> 
> -- E

Among the things that Billy Pilgrim could not change were the past, the 
present, and the future. Hopefully we have better luck, because the ErrorType 
to NSError bridging is currently a bit buggy.

Have a look at this code, and take a guess at what the results should be:

import Foundation

extension ErrorType {
public func toNSError() -> NSError {
return self as NSError
}
}

let error = NSError(domain: "Foo", code: -1, userInfo: 
[NSLocalizedFailureReasonErrorKey : "Something went wrong"])

let ns = error.toNSError()

print("Type of error was \(error.dynamicType), type of ns is \(ns.dynamicType)")

print("error's user info: \(error.userInfo)")
print("ns user info: \(ns.userInfo)”)

--

The results are a bit surprising:

Type of error was NSError, type of ns is _SwiftNativeNSError
error's user info: [NSLocalizedFailureReason: Something went wrong]
ns user info: [:]

What happened was:

1. The toNSError() method showed up for our NSError, since NSError is presented 
to Swift as conforming to ErrorType. 

2. However, due to a lack of dynamism, the code in the extension assumes that 
we have a Swift native error and *not* an NSError, so it goes ahead and wraps 
the NSError inside another NSError.

3. And since Swift doesn’t currently do anything to address the userInfo field, 
the userInfo that our error had gets chopped off.

Whoops.

Charles

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-02 Thread Charles Srstka via swift-evolution
> On May 2, 2016, at 5:53 PM, Joe Groff via swift-evolution 
>  wrote:
> 
> I can't think of any problems that would block us from doing that today. It'd 
> be pretty easy to write an ErrorProtocol extension that just forwards 
> NSError's interface via bridging, and I bet that'd cover most use cases for 
> 'as NSError':
> 
> extension ErrorProtocol {
>  var domain: String { return NSError(self).domain }
>  var code: Int { return NSError(self).code }
>  var userInfo: [String: AnyObject] { return NSError(self).userInfo }
>  /* etc. */
> }
> 
> -Joe

This could be fantastic if it accompanied the addition to ErrorProtocol of an 
“userInfo” property (or even _userInfo, although I’d really prefer that all 
three of these be de-underscored) that NSError(self) would pick up on when 
doing the conversion. Otherwise, we’re just going to have to keep on using 
custom .toNSError() methods instead of the official way, so it won’t matter if 
the latter is “as NSError” or “NSError(foo)” or something else.

Charles

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-02 Thread Joe Groff via swift-evolution

> On May 2, 2016, at 3:50 PM, Chris Lattner  wrote:
> 
> 
>> On May 2, 2016, at 3:43 PM, Joe Groff  wrote:
>> 
>> 
>>> On May 2, 2016, at 2:45 PM, Chris Lattner  wrote:
>>> 
>>> On Apr 29, 2016, at 3:00 PM, Joe Groff via swift-evolution 
>>>  wrote:
 I’d like to propose the following changes:
 
• Dynamic casts as?, as! and is should no longer perform bridging 
 conversions between value types and Cocoa classes.
• Coercion syntax as should no longer be used to explicitly force 
 certain bridging conversions.
• To replace this functionality, we should add initializers to bridged 
 value types and classes that perform the value-preserving bridging 
 operations.
>>> +1.  I think that this will lead to a much cleaner and more predictable set 
>>> of rules.  It will probably also define away a ton of bugs in the compiler 
>>> and runtime.
>>> 
>>> 
>>> 
 NSError bridging can also be extracted from the runtime, and the same 
 functionality exposed as a factory initializer on NSError:
 
>>> I think that this proposal is overall really great, but what does it do to 
>>> the “catch let x as NSError” pattern?  What is the replacement?  If the 
>>> result is ugly, we may have to subset out NSError out of this pass, and 
>>> handle it specifically with improvements to the error bridging story.
>>> 
>> 
>> If we remove the bridging magic and do nothing else, then the best you can 
>> do to catch any error and handle it as an NSError becomes a two-liner:
>> 
>>  do {
>>try something()
>>  } catch let error {
>>let nsError = NSError(error)
>>handle(nsError)
>>  }
>> 
>> That's definitely uglier, but just to play devil's advocate, this does have 
>> the benefit of making it much clearer that the 'catch' is exhaustive. 'as' 
>> patterns are usually refutable, and it's a weird exception that 'error as 
>> NSError' is an exhaustive match (and we do have bugs where we get this 
>> wrong, especially inside closures when we haven't fully propagated 
>> contextual types yet).
> 
> Right, that’s what I expected.  The problem here is that this is a super 
> common pattern.  The solution to this is pretty straight-forward though: we 
> should just make the most commonly used members of NSError be a protocol 
> extension on ErrorProtocol (née ErrorType).  This would eliminate the most 
> common reasons that people need this pattern.  Do you know of any issues with 
> this, or are we merely a proposal away from making this happen?

I can't think of any problems that would block us from doing that today. It'd 
be pretty easy to write an ErrorProtocol extension that just forwards NSError's 
interface via bridging, and I bet that'd cover most use cases for 'as NSError':

extension ErrorProtocol {
  var domain: String { return NSError(self).domain }
  var code: Int { return NSError(self).code }
  var userInfo: [String: AnyObject] { return NSError(self).userInfo }
  /* etc. */
}

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-02 Thread Chris Lattner via swift-evolution

> On May 2, 2016, at 3:43 PM, Joe Groff  wrote:
> 
> 
>> On May 2, 2016, at 2:45 PM, Chris Lattner  wrote:
>> 
>> On Apr 29, 2016, at 3:00 PM, Joe Groff via swift-evolution 
>>  wrote:
>>> I’d like to propose the following changes:
>>> 
>>> • Dynamic casts as?, as! and is should no longer perform bridging 
>>> conversions between value types and Cocoa classes.
>>> • Coercion syntax as should no longer be used to explicitly force 
>>> certain bridging conversions.
>>> • To replace this functionality, we should add initializers to bridged 
>>> value types and classes that perform the value-preserving bridging 
>>> operations.
>> +1.  I think that this will lead to a much cleaner and more predictable set 
>> of rules.  It will probably also define away a ton of bugs in the compiler 
>> and runtime.
>> 
>> 
>> 
>>> NSError bridging can also be extracted from the runtime, and the same 
>>> functionality exposed as a factory initializer on NSError:
>>> 
>> I think that this proposal is overall really great, but what does it do to 
>> the “catch let x as NSError” pattern?  What is the replacement?  If the 
>> result is ugly, we may have to subset out NSError out of this pass, and 
>> handle it specifically with improvements to the error bridging story.
>> 
> 
> If we remove the bridging magic and do nothing else, then the best you can do 
> to catch any error and handle it as an NSError becomes a two-liner:
> 
>   do {
> try something()
>   } catch let error {
> let nsError = NSError(error)
> handle(nsError)
>   }
> 
> That's definitely uglier, but just to play devil's advocate, this does have 
> the benefit of making it much clearer that the 'catch' is exhaustive. 'as' 
> patterns are usually refutable, and it's a weird exception that 'error as 
> NSError' is an exhaustive match (and we do have bugs where we get this wrong, 
> especially inside closures when we haven't fully propagated contextual types 
> yet).

Right, that’s what I expected.  The problem here is that this is a super common 
pattern.  The solution to this is pretty straight-forward though: we should 
just make the most commonly used members of NSError be a protocol extension on 
ErrorProtocol (née ErrorType).  This would eliminate the most common reasons 
that people need this pattern.  Do you know of any issues with this, or are we 
merely a proposal away from making this happen?

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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-02 Thread David Hart via swift-evolution
I got the reference, made me laugh :)

> On 03 May 2016, at 00:21, Erica Sadun via swift-evolution 
>  wrote:
> 
> 
>> On May 2, 2016, at 4:15 PM, Chris Lattner > > wrote:
>> 
>>> 
>>> On May 2, 2016, at 2:48 PM, Erica Sadun >> > wrote:
>>> 
>>> 
 On May 2, 2016, at 3:45 PM, Chris Lattner via swift-evolution 
 > wrote:
> NSError bridging can also be extracted from the runtime, and the same 
> functionality exposed as a factory initializer on NSError:
> 
 
 I think that this proposal is overall really great, but what does it do to 
 the “catch let x as NSError” pattern?  What is the replacement?  If the 
 result is ugly, we may have to subset out NSError out of this pass, and 
 handle it specifically with improvements to the error bridging story.
>>> 
>>> Grant me the serenity to accept the `NSError` I cannot change and the 
>>> courage to change the bridging conversions I should. Grant me the wisdom to 
>>> know the difference between a partial solution that offers a cleaner more 
>>> predictable interface set now and a full solution that cannot be achieved 
>>> in a reasonable timeframe.
>> 
>> I’m not sure what you’re saying.
>> 
>> -Chris
> 
> It's a message of support, riffing on the famous Serenity Prayer 
> (https://en.wikipedia.org/wiki/Serenity_Prayer 
> ), agreeing with you and 
> saying that partial implementation of a good idea (limiting bridging 
> conversions between value types and a subset of Cocoa classes) is to be 
> preferred to a full implementation of an idea that requires extraordinary 
> effort for one special case (NSError).
> 
> -- E
> 
> 
> ___
> 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] Reducing the bridging magic in dynamic casts

2016-05-02 Thread Erica Sadun via swift-evolution

> On May 2, 2016, at 4:15 PM, Chris Lattner  wrote:
> 
>> 
>> On May 2, 2016, at 2:48 PM, Erica Sadun > > wrote:
>> 
>> 
>>> On May 2, 2016, at 3:45 PM, Chris Lattner via swift-evolution 
>>> > wrote:
 NSError bridging can also be extracted from the runtime, and the same 
 functionality exposed as a factory initializer on NSError:
 
>>> 
>>> I think that this proposal is overall really great, but what does it do to 
>>> the “catch let x as NSError” pattern?  What is the replacement?  If the 
>>> result is ugly, we may have to subset out NSError out of this pass, and 
>>> handle it specifically with improvements to the error bridging story.
>> 
>> Grant me the serenity to accept the `NSError` I cannot change and the 
>> courage to change the bridging conversions I should. Grant me the wisdom to 
>> know the difference between a partial solution that offers a cleaner more 
>> predictable interface set now and a full solution that cannot be achieved in 
>> a reasonable timeframe.
> 
> I’m not sure what you’re saying.
> 
> -Chris

It's a message of support, riffing on the famous Serenity Prayer 
(https://en.wikipedia.org/wiki/Serenity_Prayer 
), agreeing with you and saying 
that partial implementation of a good idea (limiting bridging conversions 
between value types and a subset of Cocoa classes) is to be preferred to a full 
implementation of an idea that requires extraordinary effort for one special 
case (NSError).

-- E


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


Re: [swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-05-02 Thread Chris Lattner via swift-evolution

> On May 2, 2016, at 2:48 PM, Erica Sadun  wrote:
> 
> 
>> On May 2, 2016, at 3:45 PM, Chris Lattner via swift-evolution 
>> > wrote:
>>> NSError bridging can also be extracted from the runtime, and the same 
>>> functionality exposed as a factory initializer on NSError:
>>> 
>> 
>> I think that this proposal is overall really great, but what does it do to 
>> the “catch let x as NSError” pattern?  What is the replacement?  If the 
>> result is ugly, we may have to subset out NSError out of this pass, and 
>> handle it specifically with improvements to the error bridging story.
> 
> Grant me the serenity to accept the `NSError` I cannot change and the courage 
> to change the bridging conversions I should. Grant me the wisdom to know the 
> difference between a partial solution that offers a cleaner more predictable 
> interface set now and a full solution that cannot be achieved in a reasonable 
> timeframe.

I’m not sure what you’re saying.

-Chris

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


[swift-evolution] [Pitch] Reducing the bridging magic in dynamic casts

2016-04-29 Thread Joe Groff via swift-evolution
When we introduced Swift, we wanted to provide value types for common 
containers, with the safety and state isolation benefits they provide, while 
still working well with the reference-oriented world of Cocoa. To that end, we 
invested a lot of work into bridging between Swift’s value semantics containers 
and their analogous Cocoa container classes. This bridging consisted of several 
pieces in the language, the compiler, and the runtime:

Importer bridging, importing Objective-C APIs that take and return NSString, 
NSArray, NSDictionary and NSSet so that they take and return Swift’s analogous 
value types instead.

Originally, the language allowed implicit conversions in both directions 
between Swift value types and their analogous classes. We’ve been working on 
phasing the implicit conversions out—we removed the object-to-value implicit 
conversion in Swift 1.2, and propose to remove the other direction in 
SE–0072—but the conversions can still be performed by an explicit coercion 
string as NSString. These required-explicit as coercions don’t otherwise exist 
in the language, since as generally is used to force coercions that can also 
happen implicitly, and value-preserving conversions are more idiomatically 
performed by constructors in the standard library.

The runtime supports dynamic bridging casts. If you have a value that’s 
dynamically of a Swift value type, and try to as?, as!, or is-cast it to its 
bridged Cocoa class type, the cast will succeed, and the runtime will apply the 
bridging conversion:

// An Any that dynamically contains a value "foo": String
let x: Any = "foo"
// Cast succeeds and produces the bridged "foo": NSString
let y = x as! NSString 
Since Swift first came out, Cocoa has done a great job of “Swiftification”, 
aided by new Objective-C features like nullability and lightweight generics 
that have greatly improved the up-front quality of importer-bridged APIs. This 
has let us deemphasize and gradually remove the special case implicit 
conversions from the language. I think it’s time to consider extricating them 
from the dynamic type system as well, making it so that as?, as!, and is casts 
only concern themselves with typechecks, and transitioning to using standard 
initializers and methods for performing bridging conversions. I’d like to 
propose the following changes:

Dynamic casts as?, as! and is should no longer perform bridging conversions 
between value types and Cocoa classes.
Coercion syntax as should no longer be used to explicitly force certain 
bridging conversions.
To replace this functionality, we should add initializers to bridged value 
types and classes that perform the value-preserving bridging operations.
The Rules of as[?]

Our original goal implementing this behavior into the dynamic casting machinery 
was to preserve some transitivity identities between implicit conversions and 
casts that users could reason about, including:

x as! T as! U === x as! U, if x as! T succeeds. Casting to a type U should 
succeed and give the same result for any derived cast result.
x as! T as U === x as! U. If T is coercible to U, then you should get the same 
result by casting to Tand coercing to U as by casting to U directly.
x as T as! U === x as! U. Likewise, coercing shouldn’t affect the result of any 
ensuing dynamic casts.
x as T as U === x as U.
The interaction of these identities with the bridging conversions, as well as 
with other type system features like implicit nonoptional-to-Optional 
conversion, occasionally requires surprising behavior, for instance the 
behavior of nil Optional values in https://github.com/apple/swift/pull/1949. 
These rules also inform the otherwise-inconsistent use of as to perform 
explicit bridging conversions, when as normally only forces implicit 
conversions. By simplifying the scope of dynamic casts, it becomes easier to 
preserve these rules without bugs and unfortunate edge cases.

The Abilities of as? Today

In discussing how to change the behavior of dynamic casts, it’s worth 
enumerating all the things dynamic casts are currently able to do:

Check that an object is an instance of a specific class.

class Base {}; class Derived: Base {}

func isKindOfDerived(object: Base) -> Bool {
  return object is Derived
}

isKindOfDerived(object: Derived()) // true
isKindOfDerived(object: Base()) // false
Check that an existential contains an instance of a type.

protocol P {}
extension Int: P {}
extension Double: P {}

func isKindOfInt(value: P) -> Bool {
  return value is Int
}
isKindOfInt(value: 0) // true
isKindOfInt(value: 0.0) // false
Check that a generic value is also an instance of a different type.

func is(value: T, kindOf: U.Type) -> Bool {
  return value is U
}

is(value: Derived(), kindOf: Derived.self) // true
is(value: Derived(), kindOf: Base.self) // true
is(value: Base(), kindOf: Derived.self) // false
is(value: 0, kindOf: Int.self) // true
Check whether the type of a value conforms to a protocol, and