It is currently not possible to add a setter to a computed property through an extension there that property also works properly outside the module (i.e. in other modules who import the extension).
CGRect for example has two read-only computed properties height and width.
Through an extension these properties can be shadowed by read-write computed properties like this:
extension CGRect {
public var height: CGFloat {
get { return size.height }
mutating set { size.height = newValue }
}
public var width: CGFloat {
get { return size.width }
mutating set { size.width = newValue }
}
}
and then be used like this:
var rect = CGRect()
rect.height = 1
rect.width = 2
var height = rect.height
var width = rect.width
It works fine in the same module as where the extension was defined.
It does not work however in other modules which import that extension. While the setters work fine, the getters will be considered "ambiguous" (between the original and the extension's implementations) and Swift provides no way to disambiguate this:
import ModuleProvidingTheExtension
var rect = CGRect()
rect.height = 1 // works
rect.width = 2 // works
var height = rect.height // Ambiguous use of 'height'
var width = rect.width // Ambiguous use of 'width'
There is no workaround for this problem.
Possible solutions:
Swift could provide a way to disambiguate the property access
at the call-site (would add weird syntax though)
at the import-site (e.g. import ModuleProvidingTheExtension.CGRect or ModuleProvidingTheExtension.CGRect.width - potentially very verbose)
by declaring that symbols in extensions always have precedence over symbols in the type being extended (won't work since CoreGraphic's CGRect.height/width is also added through extension)
by declaring symbol precedence depending on the order of module imports (potentially dangerous/unexpected?)
Swift could allow property getters to have a lower visibility than property setters which allowed for hiding the ambiguous getter (private get … in the extension)
Swift could allow adding a property setter through an extension without providing a getter
The last solution (providing a setter without getter) would easily fix this issue. It maintains source-compatibility and introduces no new syntax.
Example:
extension CGRect {
public var height: CGFloat {
mutating set { size.height = newValue }
}
public var width: CGFloat {
mutating set { size.width = newValue }
}
}
It adds a setter to the existing read-only properties.
Providing just a setter is only allowed if the property being affected is already defined somewhere - i.e. already has a getter.
This could be extended to allowing subclasses to override only the setter of a property without having to override the getter just to call super's implementation. Same for protocol conformances where the getter would already be covered by a default implementation.
--
I consider this to be more a bug than a feature request because overwriting the property in an extension leads to an unresolvable ambiguous access error in the getter only.
If necessary I'll re-post this on the Swift Evolution Mailing List.
Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 1 | |Component/s | | |Labels | Improvement, LanguageFeatureRequest | |Assignee | None | |Priority | Medium | md5: 51a30ea6603f4c1be8bc14581c1df11aIssue Description:
It is currently not possible to add a setter to a computed property through an extension there that property also works properly outside the module (i.e. in other modules who import the extension).
CGRect
for example has two read-only computed propertiesheight
andwidth
.Through an extension these properties can be shadowed by read-write computed properties like this:
and then be used like this:
It works fine in the same module as where the extension was defined.
It does not work however in other modules which import that extension. While the setters work fine, the getters will be considered "ambiguous" (between the original and the extension's implementations) and Swift provides no way to disambiguate this:
There is no workaround for this problem.
Possible solutions:
Swift could provide a way to disambiguate the property access
at the call-site (would add weird syntax though)
at the import-site (e.g.
import ModuleProvidingTheExtension.CGRect
orModuleProvidingTheExtension.CGRect.width
- potentially very verbose)by declaring that symbols in extensions always have precedence over symbols in the type being extended(won't work since CoreGraphic's CGRect.height/width is also added through extension)by declaring symbol precedence depending on the order of module imports (potentially dangerous/unexpected?)
Swift could allow property getters to have a lower visibility than property setters which allowed for hiding the ambiguous getter (
private get …
in the extension)Swift could allow adding a property setter through an extension without providing a getter
The last solution (providing a setter without getter) would easily fix this issue. It maintains source-compatibility and introduces no new syntax.
Example:
It adds a setter to the existing read-only properties.
Providing just a setter is only allowed if the property being affected is already defined somewhere - i.e. already has a getter.
This could be extended to allowing subclasses to override only the setter of a property without having to override the getter just to call super's implementation. Same for protocol conformances where the getter would already be covered by a default implementation.
--
I consider this to be more a bug than a feature request because overwriting the property in an extension leads to an unresolvable ambiguous access error in the getter only.
If necessary I'll re-post this on the Swift Evolution Mailing List.