What is a Function-local static in Swift?

@Douglas_Gregor mentions Function-local statics in Swift for C++ Practitioners, Part 8: Global Variables.

Wrap-up

Global and static variables in Swift are conceptually similar to those in C++, and used for much the same purpose. However, Swift takes the "Initialize on First Use" principle all the way, with all global and static variables being initialized on first use. Function-local statics in Swift work identically to those in C++, based on the same "Initialize on First Use" principle.

I thought they did not exist in Swift, but I tried it anyway:

func f () {
    static var u: Int = 7
    // error: Static properties may only be declared on a type
}

What are they?

I do not know for sure if that is what the article refers to, but you can define a function-local struct with a static property:

func f () {
    struct S {
        static var u: Int = 7
    }
}

See also:

2 Likes
func f () {
    struct S {
        static var u: Int = 7
    }

  S.u += 1 // count function cals
}

I think this should be an error in Swift 6 due to data races check

1 Like

Static property 'u' is not concurrency-safe because it is non-isolated global shared mutable state

Still usable if not variable, however.

func f() -> Int {
  enum FunctionLocalStatic {
    static let u: Int = {
      print("Prints 1 time, not 2")
      return 7
    } ()
  }

  return FunctionLocalStatic.u
}

f()
f()

Why would it be? A function-static variable is guaranteed to have the same isolation as the function, should be safe to use.

Just Task is enough to create concurrent access to non-isolated property:

func f () {
    struct S {
        static var u: Int = 7
    }

    S.u += 1
    Task.detached {
        S.u -= 1
    }
}
1 Like

That would trigger an error for a local variable and should do the same with a function-static one. I think it should be safe to treat func-statics the same way as locals in terms of concurrency safety.

Another case to consider:

protocol P {
    static var u: Int { get set }
}

func f () -> any P.Type {
    struct S: P {
        static var u: Int = 7
    }

    return S.self
}
2 Likes