Please consider the following code:
let myString: String? = "Hello"
let anyValue: Any = myString
let obj: AnyObject? = anyValue as? AnyObject // nil, since it's
Optional<String>, String being struct,
// no implicit bridge to AnyObject.
(myString as AnyObject will
// create _NSContiguousString).
if let optionalAny: AnyObject? = anyValue as? AnyObject? { // Error - can't
downcast from Any
// ...
}
if let optionalAny: AnyObject? = anyValue as? AnyObject { // nil
// ...
}
if let optionalAny: AnyObject? = asOpt(anyValue) { // Optional<AnyObject>
if let value = optionalAny { // value is _NSContiguousString
value.dynamicType
}
}
This behavior is IMHO incosistent at best. Should this be considered correct
behavior or a compiler bug?
> On Jun 22, 2016, at 5:59 PM, L. Mihalkovic <[email protected]>
> wrote:
>
>
>
> On Jun 22, 2016, at 5:51 PM, John McCall <[email protected]
> <mailto:[email protected]>> wrote:
>
>>
>>> On Jun 22, 2016, at 12:15 AM, L. Mihalkovic via swift-evolution
>>> <[email protected] <mailto:[email protected]>> wrote:
>>>
>>> Func asOpt<T>(v:Any) -> Optional<T> {
>>> If let val = v as? T {
>>> Return val
>>> }
>>> Return nil
>>> }
>>> Regards
>>> LM
>>> (From mobile)
>>
>> This is just:
>> return v as? T
>
> Had more code where i took it from... I thk it is one of these simple thgs
> that u never forget but may not be immediate to thk abt. Maybe worth adding
> to doc comment for Optional<> (forgive if is there already)
>
>>
>> John.
>>
>>>
>>> On Jun 22, 2016, at 7:11 AM, Charlie Monroe via swift-evolution
>>> <[email protected] <mailto:[email protected]>> wrote:
>>>
>>>> Unfortunately, this is not as easy, because automatic bridging won't be
>>>> applied:
>>>>
>>>> let myString: String? = "Hello"
>>>> let anyValue: Any = myString
>>>>
>>>> myString as? AnyObject // _NSContiguousString
>>>> anyValue as? AnyObject // nil, since String is struct
>>>>
>>>> let array: [String]? = ["Hello"]
>>>> let anyArray: Any = array
>>>> anyArray as? AnyObject // nil
>>>> anyArray as? [AnyObject] // nil
>>>> array as? AnyObject // ["Hello"]
>>>>
>>>> And this goes for strings, arrays, dictionaries and possibly other types.
>>>> Which means that you need to handle manually all of the bridging to ObjC
>>>> types, which has really grown in Swift 3, taking into account all the
>>>> Foundation types that are now structs.
>>>>
>>>> Should this then be considered compiler bug that bridging isn't taken into
>>>> account?
>>>>
>>>> Nevertheless, I'd still find it useful exposing the isOptional() function
>>>> as well as the asOptional which would allow a cast from Any to
>>>> Optional<Any> which is not possible at all at this moment since any such
>>>> cast will pick up the Optional first:
>>>>
>>>> let myString: String? = "Hello"
>>>> let anyValue: Any = myString
>>>> if let value = anyValue as? Any {
>>>> value.dynamicType // This is still Optional<String>, not naively just
>>>> the value of the optional
>>>> }
>>>>
>>>>
>>>>
>>>>> On Jun 21, 2016, at 8:18 PM, Joe Groff <[email protected]
>>>>> <mailto:[email protected]>> wrote:
>>>>>
>>>>> 'as?' should already do this. If you have an Any that contains an
>>>>> Optional<T> and cast 'any as? T', you'll get the value inside the
>>>>> Optional if there is one, or the cast will fail if the optional is nil or
>>>>> the type doesn't match.
>>>>>
>>>>> -Joe
>>>>>
>>>>>> On Jun 20, 2016, at 11:00 PM, Charlie Monroe via swift-evolution
>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>
>>>>>> I've recently written a CoreData editor on iOS which automatically
>>>>>> generates UI based on the model which is described using classes such as
>>>>>> PrimitiveProperty, etc. Since it automatically sets the value on the
>>>>>> entity, it needs to convert the value to AnyObject in order to pass it
>>>>>> to setValue(_:forKey:), so it needs to be able to detect whether the
>>>>>> value is Optional and in case it is, either transform the non-nil value
>>>>>> to AnyObject (String -> NSString, Array -> NSArray, ...). Which is
>>>>>> currently really hard to achieve:
>>>>>>
>>>>>> var obj: IndexPath? = IndexPath()
>>>>>> let anyValue: Any = obj
>>>>>> anyValue.dynamicType /// Optional<Foundation.IndexPath>.Type
>>>>>>
>>>>>> /// Using only anyValue, determine if it's Optional and retrieve its
>>>>>> value if
>>>>>> /// non-nil as AnyObject.
>>>>>> func isOptional(anyValue: Any) -> Bool {
>>>>>> // Error: Cannot downcast from 'Any' (aka 'protocol<>') to a more
>>>>>> // optional type 'Optional<_>'
>>>>>> return anyValue is Optional
>>>>>> return anyValue as? Optional != nil
>>>>>> ...
>>>>>> }
>>>>>>
>>>>>> Unless there are major reasons why it's not exposed, I'd propose
>>>>>> introducing a new function isOptional(anyValue: Any) -> Bool, which
>>>>>> would simply call Builtin.isOptional just like _isOptional does in
>>>>>> Builtin.swift. (which pretty much is just taking the current
>>>>>> _isOptional, removing underscore and marking it public).
>>>>>>
>>>>>> However, this still doesn't help with the issue of retrieving the value
>>>>>> of the Optional. You now know the value in `anyValue` is Optional, but
>>>>>> there is no good way to cast it to e.g. Optional<AnyObject>. Here we're
>>>>>> getting into a vicious cycle that Any can be an Optional which is Any.
>>>>>>
>>>>>> My second part of the proposal introduces another function:
>>>>>>
>>>>>> func asOptional<T>(anyValue: Any) -> Optional<T>?
>>>>>>
>>>>>> Which will:
>>>>>> - return nil if !isOptional(anyValue)
>>>>>> - return a non-nil value only if `anyValue` contains in fact an Optional
>>>>>> of type T.
>>>>>>
>>>>>> Usage:
>>>>>>
>>>>>> if let anyObjOptional: AnyObject? = asOptional(anyValue: anyValue) {
>>>>>> if let anyObj = anyObjOptional {
>>>>>> // anyObj is now the actual content of the optional.
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> As a sidenote, this is my current workaround:
>>>>>>
>>>>>> private protocol _XUOptional {
>>>>>> var objectValue: AnyObject? { get }
>>>>>> }
>>>>>>
>>>>>> extension Optional: _XUOptional {
>>>>>> var objectValue: AnyObject? {
>>>>>> switch self {
>>>>>> case .None:
>>>>>> return nil
>>>>>> case .Some(_):
>>>>>> return self! as? AnyObject
>>>>>> }
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> if let optional = anyValue as? _XUOptional {
>>>>>> let object = optional.objectValue
>>>>>> /// ...
>>>>>> }
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> [email protected] <mailto:[email protected]>
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> [email protected] <mailto:[email protected]>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> [email protected] <mailto:[email protected]>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution