============================= Stored and Computed Variables ============================= .. warning:: This document has not been updated since the initial design in Swift 1.0. Variables are declared using the ``var`` keyword. These declarations are valid at the top level, within types, and within code bodies, and are respectively known as *global variables,* *member variables,* and *local variables.* Member variables are commonly referred to as *properties.* Every variable declaration can be classified as either *stored* or *computed.* Member variables inherited from a superclass obey slightly different rules. .. contents:: :local: Stored Variables ================ The simplest form of a variable declaration provides only a type:: var count : Int This form of ``var`` declares a *stored variable.* Stored variables cause storage to be allocated in their containing context: - a new global symbol for a global variable - a slot in an object for a member variable - space on the stack for a local variable (Note that this storage may still be optimized away if determined unnecessary.) Stored variables must be initialized before use. As such, an initial value can be provided at the declaration site. This is mandatory for global variables, since it cannot be proven who accesses the variable first. :: var count : Int = 10 If the type of the variable can be inferred from the initial value expression, it may be omitted in the declaration:: var count = 10 Variables formed during pattern matching are also considered stored variables. :: switch optVal { case .Some(var actualVal): // do something case .None: // do something else } Computed Variables ================== A *computed variable* behaves syntactically like a variable, but does not actually require storage. Instead, accesses to the variable go through "accessors" known as the *getter* and the *setter.* Thus, a computed variable is declared as a variable with a custom getter:: struct Rect { // Stored member variables var x, y, width, height : Int // A computed member variable var maxX : Int { get { return x + width } set(newMax) { x = newMax - width } } // myRect.maxX = 40 In this example, no storage is provided for ``maxX``. If the setter's argument is omitted, it is assumed to be named ``value``:: var maxY : Int { get { return y + height } set { y = value - height } } Finally, if a computed variable has a getter but no setter, it becomes a *read-only variable.* In this case the ``get`` label may be omitted. Attempting to set a read-only variable is a compile-time error:: var area : Int { return self.width * self.height } } Note that because this is a member variable, the implicit parameter ``self`` is available for use within the accessors. It is illegal for a variable to have a setter but no getter. Observing Accessors =================== Occasionally it is useful to provide custom behavior when changing a variable's value that goes beyond simply modifying the underlying storage. One way to do this is to pair a stored variable with a computed variable:: var _backgroundColor : Color var backgroundColor : Color { get { return _backgroundColor } set { _backgroundColor = value refresh() } } However, this contains a fair amount of boilerplate. For cases where a stored property provides the correct storage semantics, you can add custom behavior before or after the underlying assignment using "observing accessors" ``willSet`` and ``didSet``:: var backgroundColor : Color { didSet { refresh() } } var currentURL : URL { willSet(newValue) { if newValue != currentURL { cancelCurrentRequest() } } didSet { sendNewRequest(currentURL) } } A stored property may have either observing accessor, or both. Like ``set``, the argument for ``willSet`` may be omitted, in which case it is provided as "value":: var accountName : String { willSet { assert(value != "root") } } Observing accessors provide the same behavior as the two-variable example, with two important exceptions: - A variable with observing accessors is still a stored variable, which means it must still be initialized before use. Initialization does not run the code in the observing accessors. - All assignments to the variable will trigger the observing accessors with the following exceptions: assignments in the init and destructor function for the enclosing type, and those from within the accessors themselves. In this context, assignments directly store to the underlying storage. Computed properties may not have observing accessors. That is, a property may have a custom getter or observing accessors, but not both. Overriding Read-Only Variables ============================== If a member variable within a class is a read-only computed variable, it may be overridden by subclasses. In this case, the subclass may choose to replace that computed variable with a stored variable by declaring the stored variable in the usual way:: class Base { var color : Color { return .Black } } class Colorful : Base { var color : Color } var object = Colorful(.Red) object.color = .Blue The new stored variable may have observing accessors:: class MemoryColorful : Base { var oldColors : Array<Color> = [] var color : Color { willSet { oldColors.append(color) } } } A computed variable may also be overridden with another computed variable:: class MaybeColorful : Base { var color : Color { get { if randomBooleanValue() { return .Green } else { return super.color } } set { print("Sorry, we choose our own colors here.") } } } Overriding Read-Write Variables =============================== If a member variable within a class as a read-write variable, it is not generally possible to know if it is a computed variable or stored variable. A subclass may override the superclass's variable with a new computed variable:: class ColorBase { var color : Color { didSet { print("I've been painted \(color)!") } } } class BrightlyColored : ColorBase { var color : Color { get { return super.color } set(newColor) { // Prefer whichever color is brighter. if newColor.luminance > super.color.luminance { super.color = newColor } else { // Keep the old color. } } } } In this case, because the superclass's ``didSet`` is part of the generated setter, it is only called when the subclass actually invokes setter through its superclass. On the ``else`` branch, the superclass's ``didSet`` is skipped. A subclass may also use observing accessors to add behavior to an inherited member variable:: class TrackingColored : ColorBase { var prevColor : Color? var color : Color { willSet { prevColor = color } } } In this case, the ``willSet`` accessor in the subclass is called first, then the setter for ``color`` in the superclass. Critically, this is *not* declaring a new stored variable, and the subclass will *not* need to initialize ``color`` as a separate member variable. Because observing accessors add behavior to an inherited member variable, a superclass's variable may not be overridden with a new stored variable, even if no observing accessors are specified. In the rare case where this is desired, the two-variable pattern shown above__ can be used. __ `Observing Accessors`_