I have a type which contains members/types with the same name, privately stored inside seperate extensions for the same type. However, this doesn't compile because they are clashing, despite them being privates of different scopes.
enum Foo {}
extension Foo {
private struct Bar {
var someMember = 2
}
private var foo: Int { 5 }
}
extension Foo {
private struct Bar { // 🛑 Invalid redeclaration of 'Bar'
var otherMember = 3
}
private var foo: Int { 5 } // 🛑 Invalid redeclaration of 'foo'
}
On the other hand, if I store the extensions in separate files, it compiles without issues. Why was this implemented this way?
You're seeing the first half of this sentence from SE-0169:
For purposes of access control, extensions to any given type T within a file are considered to be a single access control scope, and if T is defined within the file, the extensions use the same access control scope as T .
Despite being different lexical scopes, your two extensions are treated as a single access control scope. This was done to allow extensions of a type in the same file to access private members instead of having to declare them fileprivate.
This is a known Swift limitation. Even though the members are private, the compiler treats all extensions in the same file as a single type scope for name resolution. So it sees duplicate declarations of Bar and foo.
When the extensions are in separate files, each extension gets its own scope, so the names no longer clash.
It's annoying, but that's how Swift currently works. Many people consider it a compiler bug / design quirk.
Best workaround: keep conflicting private extensions in separate files, or rename one of them (e.g. Bar2 or privateFoo).