Methods and subscripts currently have different capabilities. But they're converging. (e.g. Subscripts gained generics/static, and callAsFunction uses the same syntax as a subscript.)
There is no reason for both to exist anymore. They came from a before-modern-Swift time. Anyone who thinks they have inherent different meaning only has that idea because they've learned it and now find it "natural". Beware the dogma.
As it is, you need to use subscripts if you want to use a value after an equals sign. If this feature ever makes it into Swift, it will probably be in the form of a "named subscript". Once people get used to that, you'll see more people, like yourself, start to ask your question.
Then, either one of the syntaxes will be deprecated, or we'll wait until Swift's successor to see that.
Here's what named subscripts look like:
final class Class {
var bools: ObjectSubscript<Class, String, Bool?> {
.init(
self,
get: { object in
{ object._bools[$0]
?? Bool(binaryString: $0)
}
},
set: { $0._bools[$1] = $2 }
)
}
private var _bools: [String: Bool] = [:]
}
let object = Class()
let ghoul = ""
XCTAssertEqual(object.bools["1"], true)
XCTAssertNil(object.bools[ghoul])
object.bools[ghoul] = false
XCTAssertEqual(object.bools[ghoul], false)
/// An emulation of the missing Swift feature of named subscripts.
/// - Note: Argument labels are not supported.
public struct ObjectSubscript<Object: AnyObject, Index, Value> {
public typealias Get = (Object) -> (Index) -> Value
public typealias Set = (Object, Index, Value) -> Void
public unowned var object: Object
public var get: Get
public var set: Set
}
public extension ObjectSubscript {
init(
_ object: Object,
get: @escaping Get,
set: @escaping Set
) {
self.object = object
self.get = get
self.set = set
}
subscript(index: Index) -> Value {
get { get(object)(index) }
nonmutating set { set(object, index, newValue) }
}
}
var set: Set = [1, 2, 3]
XCTAssert(set.contains[3])
set.contains[1] = false
XCTAssertEqual(set, [2, 3])
var contains = set.contains
contains[3].toggle()
XCTAssertEqual(set, [2])
contains.set = { _, _, _ in }
contains[2].toggle()
XCTAssertEqual(set, [2])
var four: Set = [4]
withUnsafeMutablePointer(to: &four) {
contains.pointer = $0
XCTAssert(contains[4])
}
public extension SetAlgebra {
var contains: ValueSubscript<Self, Element, Bool> {
mutating get {
.init(
&self,
get: Self.contains,
set: { set, element, newValue in
if newValue {
set.insert(element)
} else {
set.remove(element)
}
}
)
}
}
}
/// An emulation of the missing Swift feature of named subscripts.
/// - Note: Argument labels are not supported.
public struct ValueSubscript<Root, Index, Value> {
public typealias Pointer = UnsafeMutablePointer<Root>
public typealias Get = (Root) -> (Index) -> Value
public typealias Set = (inout Root, Index, Value) -> Void
public var pointer: Pointer
public var get: Get
public var set: Set
}
public extension ValueSubscript {
init(
_ pointer: Pointer,
get: @escaping Get,
set: @escaping Set
) {
self.pointer = pointer
self.get = get
self.set = set
}
subscript(index: Index) -> Value {
get { get(pointer.pointee)(index) }
nonmutating set { set(&pointer.pointee, index, newValue) }
}
}