6 Replies
      Latest reply on Jul 12, 2019 3:11 AM by somethingelse
      somethingelse Level 1 Level 1 (0 points)

        a preambula,

         

        i created a helper function:

         

        func cast<T>(_ value: Any?, to: T.Type) -> T? {

            return value != nil ? (value as! T) : nil

        }

         

        to use it like this:

         

        let dog = cast(any, to: Dog.self)

         

        the idea is that it is a "stricter" version of the "as?" operator:

         

        let dog = any as? Dog // will return nil when a car is passed, i want a crash here in this case.

        let dog = any != nil ? (any as! Dog) // so i want this: if it is not nil it must be a dog (*)

        let dog = cast(any, to: Dog.self) // a bit shorter and less visually disturbing

         

        (* note that the extra parens around "(any as! Dog)" are there to stop a warning).

         

        now the question, probably to swift designers, but anyone's input is welcome:

         

        this cast function is not as nice as the built-in "as?" operator. i can not pass "Dog" alone in this context, I have to put it as "Dog.self". is there some deep logic why it is so? i believe in this context "Dog" alone can not mean anything else (useful), what harm it would make to treat "Dog" here as if "Dog.self" was passed?

        • Re: metatype design question
          QuinceyMorris Level 8 Level 8 (6,050 points)

          The difference between Dog and Dog.self is that "Dog" is just the name of the type, but "Dog.self" is a reference to the metatype object that represents the type. As it happens, it's possible for the compiler to distinguish between places where the name is required, and places where a metatype object is required, and it's a planned future enhancement to Swift to allow them both to be written Dog — but it's likely not a small change internally.

           

          For now, you could try using any as! Dog? to "safely" cast an unknown optional to an optional Dog. It perhaps doesn't do exactly the same thing as your "cast" function, but it should be close enough. (For example, the two techniques might produce different results for a value of type Dog?? — that's a double optional, which is an edge case you probably don't care about.)

            • Re: metatype design question
              somethingelse Level 1 Level 1 (0 points)

              > any as! Dog?

               

              wow, looks strange, but does the trick indeed!

              thanks

               

              out of curiousity, how do i create "Dog??" or "Dog???"

                • Re: metatype design question
                  QuinceyMorris Level 8 Level 8 (6,050 points)

                  The most plausible scenario of intentionally creating a multilevel optional is from a dictionary with optional values:

                   

                  let dict: [String: Dog?] = ... some values ...
                  let value = dict ["fido"]

                   

                  Looking up a value in a dictionary adds a level of optionality, so "value" would be of type Dog?? FWIW, compare the meaning of the following two lines:

                   

                  dict ["fifi"] = nil as Dog?
                  dict ["mimi"] = nil as Dog??

                   

                  The first of those puts a nil value into the dictionary under key "fifi". The second deletes the value under key "mimi".

                   

                  More abstractly, you can add as many levels of optionality as you want, if you remember that Optional is an enum. You can write things like:

                   

                  let weirdo = Optional.some(Optional.some(Optional.some(rex)))

                   

                  "weirdo" is of type Dog???

                    • Re: metatype design question
                      somethingelse Level 1 Level 1 (0 points)

                      interesting.. and this:

                       

                      dict["zizi"] = nil

                       

                      acts here the same way as "dict["zizi"] = nil as Dog??" deleting the key.

                       

                      are these two equivalent?

                      any as? Dog

                      any as? Dog?

                       

                      and these two:

                      any as! Dog

                      any! as! Dog

                        • Re: metatype design question
                          QuinceyMorris Level 8 Level 8 (6,050 points)

                          Yes,

                           

                          dict["zizi"] = nil

                           

                          deletes the entry, because the type of "nil" is inferred to be "Dog??".

                           

                          Your other pairs of example are more or less equivalent, but again I'm not sure they're exactly the same in edge cases. What's going on behaind the scenes is that the compiler has some ad-hoc rules about when it can ignore an extra level of optionality in the value being tested.

                           

                          A related example is an optional try:

                           

                          let result = try? someDog(named: "spot")

                           

                          Previously, this would have added a level of optionality to the result. If "someDog" is defined to return a Dog?, the "try" would produce a Dog??. In Swift 5, this was changed to produce only a Dog?, eliminating one of the two levels of optionality.

                           

                          The downside of this sort of thing is that it's harder to think about what's happening in terms of a simple rule. The upside is that the behavior is much more usable in typical cases.

                            • Re: metatype design question
                              somethingelse Level 1 Level 1 (0 points)

                              > The downside of this sort of thing is that it's harder to think about what's happening in terms of a simple rule.

                               

                              this is a bit worrisome. as your example with mimi vs fifi shows sometimes the number of ??? is important, and this fuzzy logic of compiler collapsing levels of optionality "with good intentions" might actually break something.