3

Just for fun I tested out, if such a function is actually working:

func exampleFunction() -> Any {
    struct Example {
        let x: Int
    }
    let example = Example(x: 2)
    return example
}

And surprisingly it is. My question is now: Is it able to access for example x from the function? Of course this doesn't work:

let example = exampleFunction()
print(example.x)         
//Error: Value of type 'Any' has no member 'x'

It has to be type casted first, but with which type?

let example = exampleFunction()
print((example as! Example).x)
//Of course error: Use of undeclared type 'Example'

print((example as! /* What to use here? */).x)

Surprisingly print(type(of: example)) prints the correct string Example

pseudosudo
  • 6,270
  • 9
  • 40
  • 53
Josef Zoller
  • 921
  • 2
  • 8
  • 24
  • 2
    The scope of `Example` is only within the function. You can't use it in any way outside the function, including the function's return type. – rmaddy Jun 20 '18 at 15:56
  • 4
    "Just for fun" It _is_ a fun example. — A temporary type declared in a function can actually be quite a useful thing. For example, let's say I want a piece of info from deep in a JSON data and I retrieve it with a nest of Decodable structs. There might be a lot of throw-away intermediate structs; no point defining them at top level just to fish out that one piece of info. – matt Jun 20 '18 at 16:42
  • Very strange! This might be prevented by the sort of rust-like lifetime system Christ Lattner was hoping to build into Swift. A locally declared data type shouldn't be allowed to escape via return as "Any", because there's practically no way to use such a return value. Then again, it's such a niche scenario that it might not be worth the complexity to guard against. – Alexander Jun 20 '18 at 17:07
  • 2
    *Christ* Lattner @Alexander. LOL. I know he's practically a god in the Swift world, but isn't that taking it a bit too far? – vacawama Jun 20 '18 at 17:14
  • @vacawama You tell me: https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md – Alexander Jun 20 '18 at 17:51
  • @Alexander, I was making a joke about your misspelling of *Chris*, nothing more. – vacawama Jun 20 '18 at 18:00
  • @vacawama I just noticed it. Lmaoooo. I thought you were making some statement about how far-out an ownership model is. – Alexander Jun 20 '18 at 18:32
  • This pattern is a useful workaround for implementing [static function variables in Swift](https://stackoverflow.com/questions/25354882/static-function-variables-in-swift). – pseudosudo Nov 13 '18 at 22:09

1 Answers1

6

As @rmaddy explained in the comments, the scope of Example is the function and it can't be used outside of the function including the function's return type.

So, can you get at the value of x without having access to the type Example? Yes, you can if you use a protocol to define a type with a property x and have Example adopt that protocol:

protocol HasX {
    var x: Int { get }
}

func exampleFunction() -> Any {
    struct Example: HasX {
        let x: Int
    }
    let example = Example(x: 2)

    return example
}

let x = exampleFunction()
print((x as! HasX).x)
2

In practice, this isn't really an issue. You'd just define Example at a level that is visible to the function and any callers.

vacawama
  • 150,663
  • 30
  • 266
  • 294
  • Nice solution but not exactly what i‘ve searched for. In my view swift should definitely have a solution for this sort of problem without a protocol – Josef Zoller Jun 20 '18 at 17:25
  • Thanks. I realize it's not the perfect answer to an unanswerable question. Thanks for letting me join in on your fun. Swift is still evolving, and perhaps a future version will have a solution for this. – vacawama Jun 20 '18 at 17:29
  • 7
    "perhaps a future version will have a solution for this" A "solution" for _what_? Local is local. Swift's behavior here is exactly right. – matt Jun 20 '18 at 17:42
  • @matt, good point. One could imagine a syntax where the scope of the type could be specified (kind of like nested enums), but what would be the point in that? There isn't any missing functionality here or anything that needs fixing. – vacawama Jun 20 '18 at 18:08
  • 2
    The scope of a type _can_ be specified: declare it at the top level of another type declaration. Like nested enums! Any type declaration can declare any flavor of type declaration: that is what nested types _are_. This is _not_ a nested type. It is local to its curly braces. The end. – matt Jun 20 '18 at 18:16