It seems like that problem is a subset of the larger problem: you can't have multiple of anything that's parameterless, unless one is static and one is instance.
struct S<Whatever> {
// You get only one of these…
static func foo() { }
static var foo: Whatever { fatalError() }
// …and only one of these!
func foo() { }
var foo: Whatever { fatalError() }
}
I don't know for a fact, but I suspect that there was no concrete use case for it. Even with method overloading, the fact that you can overload method types based purely on return types (as opposed to parameter types) is a bit spooky, because it leads to code where types can change easily without one noticing. I know some people consider allowing overloading based purely on return types a design oversight/mistake.
Changing those to computed properties does not compile (as shown in the OP), but there actually are scenarios where computed properties can be overloaded too:
struct S<A> {
static var foo: Int { 123 }
// static var foo: Bool { true } // Does not compile (as expected).
}
extension S where A == UInt16 {
static var foo: Bool { true } // Compiles, but should it?
}
extension S where A == UInt32 {
static var foo: String { "abc" } // Compiles, but should it?
}
extension S where A: UnsignedInteger {
static var foo: Double { 1.23 } // Compiles, but should it?
}
extension S where A: FixedWidthInteger {
static var foo: Double { 3.21 } // Compiles, but should it?
}
func bar1<T: UnsignedInteger>(_: T.Type) -> Double { return S<T>.foo }
func bar2<T: FixedWidthInteger>(_: T.Type) -> Double { return S<T>.foo }
func test() {
print(S<UInt16>.foo as Int) // 123
print(S<UInt16>.foo as Bool) // true
print(S<UInt32>.foo as String) // abc
print(bar1(UInt16.self)) // 1.23
print(bar2(UInt16.self)) // 3.21
}
test()
Conditional and regular overloads share the same ambiguities and are effectively two sides of the same coin. With the introduction of conditional extensions, though, overloads that differ only in their generic signatures started to make a lot more sense, and at the current stage of language evolution, allowing the latter and banning Jens' example would only make the language less consistent and the compiler less uniform – actually, it had already become less consistent, since properties do support conditional overloads just like methods, and yet at some point we seem to had decided to ban the example at hand.
Edit: @Varun_Gandhi Sorry, this was not meant to be a reply to your post specifically.
Sorry, I did not word things well. What I meant by "anything" is a set of member types.
struct TypeDefinition {
enum Ownership: CaseIterable {
case `static`
case instance
}
enum Member: Hashable {
case `func`(Ownership)
case `var`(Ownership)
var ownership: Ownership {
switch self {
case .func(let ownership):
return ownership
case .var(let ownership):
return ownership
}
}
}
init(parameterlessMembersWithTheSameName: Set<Member>) throws {
guard (
Ownership.allCases.allSatisfy { ownership in
parameterlessMembersWithTheSameName
.filter { $0.ownership == ownership }
.count
<= 1
}
) else {
struct TooManyError: Error { }
throw TooManyError()
}
self.parameterlessMembersWithTheSameName = parameterlessMembersWithTheSameName
}
let parameterlessMembersWithTheSameName: Set<Member>
var hasMultipleOfAnythingThatIsParameterless: Bool {
parameterlessMembersWithTheSameName.count > 1
}
}
As for the other overloads you mentioned, I like having support for them. It's this form I'm not so sure about…
struct S<A> {
static var foo: Int { 123 }
}
extension S where A: FixedWidthInteger {
static var foo: Int { 321 }
}
func bar<T: FixedWidthInteger>(_: T.Type) -> Int {
S<T>.foo // 321.
// Can we get access to 123 somehow?
}
struct S<A> {
var foo = 123
}
extension S where A: FixedWidthInteger {
var foo: Int { 321 }
}
var voidS = S<()>()
voidS.foo = 0
voidS.foo // 0
var intS = S<Int>()
intS.foo = 0
intS.foo // 321. How can we get the zero?
struct S<A> {
var foo = 123
}
extension S where A: FixedWidthInteger {
var foo: Int { 321 }
}
var intS = S<Int>()
intS.foo = 0
print(intS.foo) // 321. How can we get the zero?
func f<T: Any>(_ s: S<T>) -> Int { s.foo } // <-- Like this.
print(f(intS)) // 0
Assuming this behaves as intended, ie it is not caused by an accepts-invalid bug:
struct S<A> {
var foo = 123
}
extension S where A: FixedWidthInteger {
var foo: Int { 321 } // Compiles, but should perhaps be
// an invalid redeclaration?
}
Then why shouldn't this compile:
struct S<A> {
var foo = 123
}
extension S where A: FixedWidthInteger {
func foo() -> Int { 321 } // ERROR: Invalid redeclaration of 'foo()'
}
?
If there's no reason why that shouldn't compile, then why shouldn't this compile:
struct S {
var foo = 123
func foo() -> Int { 321 } // ERROR: Invalid redeclaration of 'foo()'
}