dynamicType of optional chaining not the same as assignment

Binarian

Optional chaining returns always an optional value.

To reflect the fact that optional chaining can be called on a nil value, the result of an optional chaining call is always an optional value, even if the property, method, or subscript you are querying returns a nonoptional value.

The Swift Programming Language

Why the heck does in a playground the type not optional?

let stringOptEmpty: String? = ""
stringOptEmpty?.isEmpty // is true
stringOptEmpty?.isEmpty.dynamicType // Bool.Type

But the following code is

let isOk = stringOptEmpty?.isEmpty.dynamicType
isOk.dynamicType // Optional<Bool.Type>.Type
dfrib

TLDR;

The playground sidebar/column will dynamically resolve expressions in the playground, be it values assigned to variables (mutables/immutables) or just "free-floating" non-assigned values.

Your first example applies dynamicType to a value, which will resolve to the type of that specific value (true.dynamicType: Bool.Type).

Your second example, on the other hand, applies dynamicType to a variable (an immutable, but I'll use variable here to differ from value), which must have a concrete type, and hence will resolve to a type that can hold any kind of wrapped values (true or false) as well as nil (here, nil is, specifically, Optional<Bool.Type>.None), no matter what value the variable actually holds. Hence, the dynamicType will resolve to Optional<Bool.Type>.Type in your second example.


Details

The value displayed in the playground sidebar/column generally follows the following display rules:

  • For an assignment expression, the value shown in the sidebar is the value assigned, e.g.

    var a = 4 // shows '4'
    a = 2     // shows '2'
    let b: () = (a = 3)
              /* shows '()': the _value_ assigned to 'b', which is the _result_
                 of the assignment 'a = 3', to which a _side effect_ is that 'a'
                 is assigned the value '3'. */
    
  • For an expression that contains no assignment, the value shown in the sidebar is generally the result of the expression, e.g.

    true          // shows 'true'
    1 > 3         // shows 'false'
    let c = 3
    c             // shows '3'
    c.dynamicType // shows 'Int.Type'
    

In your first example (lines 2-3), we have no assignment, and the playground will dynamically resolve the value(/result) of the expression prior to resolving the dynamicType of that value. Since we're dealing with optionals, the value is either simply the value of the wrapped type (in this case, true), or the value is a type specific .None. Even if the playground shows e.g. the result of let a: Int? = nil as just nil in the sidebar, the value shown is in fact not the same .None (nil) as for say let b: String = nil

  • For let a: Int? = nil, the value of a is in fact Optional<Int.Type>.None,
  • whereas for let b: String? = nil, the value of b is Optional<String.Type>.None

With this in mind, it's natural that the resolved dynamicType of a non-nil value will be the concrete wrapped type (in your example, Bool.Type is naturally the type of true), whereas the resolved dynamicType of a nil value will include both the general optional and the wrapped type information.

struct Foo {
    let bar: Bool = true
}

var foo: Foo? = Foo()

/* .Some<T> case (non-nil) */
foo?.bar             // true <-- _expression_ resolves to (results in) the _value_ 'true'
foo?.bar.dynamicType // Bool.Type <-- dynamic type of the _result of expression_
true.dynamicType     // Bool.Type <-- compare with this

/* .None case (nil) */
foo = nil
foo?.bar.dynamicType // nil <-- _expression_ resolves to the _value_ 'Optional<Foo.Type>.None'
Optional<Foo.Type>.None.dynamicType
                     // Optional<Foo.Type>.Type <-- compare with this

Now, if you assign the values to a variable, naturally the variable must have a concrete type. Since the value we assign at runtime can be either .None or .Some<T>, the type of the variable must be one that can hold values of both these cases, hence, Optional<T.Type> (disregarding of whether the variable holds nil or a non-nil value). This is the case which you've shown in your second example: the dynamicType of the variable (here, immutable, but using variable to differ from value) isOk is the type that can hold both .None and .Some<T>, no matter what the actual value of the variable is, and hence dynamicType resolves to this type; Optional<Bool.Type>.Type.


Wrapping expressions in parantheses escapes the runtime introspection of the Swift Playground?

Interestingly, if an expression is wrapped in parantheses prior to applying .dynamicType, then the playground sidebar resolves .dynamicType of the wrapped expression as the type of the expression, as if its actual value was unknown. E.g., (...) in (...).dynamicType is treated as a variable with a concrete type rather than a runtime-resolved value.

/* .Some case (non-nil) */
foo?.bar               // true
(foo?.bar).dynamicType /* Optional<Bool>.Type <-- as if (...) 
                          is a _variable_ of unknown value         */

/* .None case (nil) */
foo = nil
(foo?.bar).dynamicType /* Optional<Bool>.Type <-- as if (...) 
                          is a _variable_ of unknown value         */

We can further note that any lone expression wrapped in parantheses in the playground will not resolve to anything at all (in the sidebar). It's as if we escape the sidebar:s runtime introspection if wrapping expressions in parantheses (which would explain why the dynamicType of expressions wrapped in parantheses will resolve as if the playground cannot make use runtime information of these expressions)

var a = 4 // shows '4'
(a = 2)   // shows nothing; can't expand or get details in sidebar

Tbh, I cannot explain why this is, and will categorize it as a peculiarity of the Swift playground.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Optional chaining used in left side of assignment in Swift

From Java

Optional chaining (?.) in nashorn

From Dev

Optional Chaining returning an Int

From Dev

Swift 3.0 Optional Chaining

From Dev

Optional Chaining in JavaScript

From Dev

swift optional chaining with cast

From Dev

Optional Chaining Not Working As Expected

From Dev

Optional chaining with Swift strings

From Dev

Chaining Optional.orElseThrow

From Dev

Optional chaining and Array in swift

From Dev

Optional chaining for constructor calls?

From Dev

Optional chaining not working for optional protocol requirements

From Dev

Is there an equivalent to optional chaining with arithmetic operators?

From Dev

Optional.ofNullable and method chaining

From Dev

Optional Chaining or ternary expression in Swift?

From Dev

Swift tuple to Optional assignment

From Dev

Optional assignment in Swift not working?

From Dev

Method chaining with the same method

From Dev

chaining method of same object

From Dev

Why does using dynamicType on a force unwrapped nil optional value type work?

From Dev

Combining chaining and assignment by reference in a data.table

From Dev

Swift optional chaining doesn't work in closure

From Dev

Java8 Optional with Function chaining expression

From Dev

Is there something like the swift optional chaining in javascript?

From Dev

How to know where Optional Chaining is breaking?

From Dev

Optional chaining question mark after function name

From Java

How to use optional chaining with array in Typescript?

From Dev

how to extend optional chaining for all types

From Dev

Accessing boolValue in a NSNumber var with optional chaining (in Swift)

Related Related

HotTag

Archive