Property (programming)
This article needs additional citations for verification. (January 2022) |
A property, in some object-oriented programming languages, is a special sort of class member, intermediate in functionality between a field (or data member) and a method. The syntax for reading and writing of properties is like for fields, but property reads and writes are (usually) translated to 'getter' and 'setter' method calls. The field-like syntax is easier to read and write than many method calls,[citation needed] yet the interposition of method calls "under the hood" allows for data validation, active updating (e.g., of GUI elements), or implementation of what may be called "read-only fields".
Support in languages
[edit]Programming languages that support properties include ActionScript 3, C#, D, Delphi/Free Pascal, eC, F#, Kotlin, JavaScript, Objective-C 2.0, Python, Scala, Swift, Lua, and Visual Basic.
Some object-oriented languages, such as Java and C++, do not support properties, requiring the programmer to define a pair of accessor and mutator methods instead.[1][citation needed]
Oberon-2 provides an alternative mechanism using object variable visibility flags.[citation needed]
Other languages designed for the Java Virtual Machine, such as Groovy, natively support properties.
While C++ does not have first class properties, they can be emulated with operator overloading.[2]
Also note that some C++ compilers support first class properties as language extensions.[citation needed]
- In Microsoft Visual Studio,[3] GCC, and llvm/clang,[4] the
__declspec(property)
creates properties similar to C#. - Borland C++ and Borland/CodeGear/Embarcadero C++Builder use the
__property
keyword.[5]
In many object oriented languages properties are implemented as a pair of accessor/mutator methods, but accessed using the same syntax as for public fields. Omitting a method from the pair yields a read-only or an uncommon write-only property.
In some languages with no built-in support for properties, a similar construct can be implemented as a single method that either returns or changes the underlying data, depending on the context of its invocation. Such techniques are used e.g. in Perl. [citation needed]
Some languages (Ruby, Smalltalk) achieve property-like syntax using normal methods, sometimes with a limited amount of syntactic sugar.
Syntax variants
[edit]Some languages follow well-established syntax conventions for formally specifying and utilizing properties and methods.
Among these conventions:
- Dot notation
- Bracket notation
Dot notation
[edit]The following example demonstrates dot notation in JavaScript.
document.createElement('pre');
Bracket notation
[edit]The following example demonstrates bracket notation in JavaScript.
document['createElement']('pre');
Example syntax
[edit]C#
[edit]class Pen { private int color; // private field // public property public int Color { get { return this.color; } set { if (value > 0) { this.color = value; } } } }
// accessing: Pen pen = new Pen(); int color_tmp = 0; // ... pen.Color = 17; color_tmp = pen.Color; // ... pen.Color = ~pen.Color; // bitwise complement ... // another silly example: pen.Color += 1; // a lot clearer than "pen.set_Color(pen.get_Color() + 1)"!
Recent C# versions also allow "auto-implemented properties" where the backing field for the property is generated by the compiler during compilation. This means that the property must have a setter. However, it can be private.
class Shape { public int Height { get; set; } public int Width { get; private set; } }
C++
[edit]This article may be confusing or unclear to readers. (October 2016) |
C++ does not have first class properties, but there exist several ways to emulate properties to a limited degree. Two of which follow:
Using Standard C++
[edit]#include <iostream> template <typename T> class property { T value; public: T & operator = (const T &i) { return value = i; } // This template class member function template serves the purpose to make // typing more strict. Assignment to this is only possible with exact identical types. // The reason why it will cause an error is temporary variable created while implicit type conversion in reference initialization. template <typename T2> T2 & operator = (const T2 &i) { T2 &guard = value; throw guard; // Never reached. } // Implicit conversion back to T. operator T const & () const { return value; } }; struct Foo { // Properties using unnamed classes. class { int value; public: int & operator = (const int &i) { return value = i; } operator int () const { return value; } } alpha; class { float value; public: float & operator = (const float &f) { return value = f; } operator float () const { return value; } } bravo; }; struct Bar { // Using the property<>-template. property <bool> alpha; property <unsigned int> bravo; }; int main () { Foo foo; foo.alpha = 5; foo.bravo = 5.132f; Bar bar; bar.alpha = true; bar.bravo = true; // This line will yield a compile time error // due to the guard template member function. ::std::cout << foo.alpha << ", " << foo.bravo << ", " << bar.alpha << ", " << bar.bravo << ::std::endl; return 0; }
Also see Stack Overflow for a more detailed example.
C++, Microsoft, GCC, LLVM/clang and C++Builder-specific
[edit]An example taken from the MSDN documentation page.
// declspec_property.cpp struct S { int i; void putprop(int j) { i = j; } int getprop() { return i; } __declspec(property(get = getprop, put = putprop)) int the_prop; }; int main() { S s; s.the_prop = 5; return s.the_prop; }
D
[edit]class Pen { private int m_color; // private field // public get property public int color () { return m_color; } // public set property public void color (int value) { m_color = value; } }
auto pen = new Pen; pen.color = ~pen.color; // bitwise complement // the set property can also be used in expressions, just like regular assignment int theColor = (pen.color = 0xFF0000);
In D version 2, each property accessor or mutator must be marked with @property:
class Pen { private int m_color; // private field // public get property @property public int color () { return m_color; } // public set property @property public void color (int value) { m_color = value; } }
Delphi/Free Pascal
[edit]type TPen = class private FColor: TColor; function GetColor: TColor; procedure SetColor(const AValue: TColor); public property Color: Integer read GetColor write SetColor; end; function TPen.GetColor: TColor; begin Result := FColor; end; procedure TPen.SetColor(const AValue: TColor); begin if FColor <> AValue then FColor := AValue; end;
// accessing: var Pen: TPen; // ... Pen.Color := not Pen.Color; (* Delphi and Free Pascal also support a 'direct field' syntax - property Color: TColor read FColor write SetColor; or property Color: TColor read GetColor write FColor; where the compiler generates the exact same code as for reading and writing a field. This offers the efficiency of a field, with the safety of a property. (You can't get a pointer to the property, and you can always replace the member access with a method call.) *)
eC
[edit]class Pen { // private data member Color color; public: // public property property Color color { get { return color; } set { color = value; } } } Pen blackPen { color = black }; Pen whitePen { color = white }; Pen pen3 { color = { 30, 80, 120 } }; Pen pen4 { color = ColorHSV { 90, 20, 40 } };
F#
[edit]type Pen() = class let mutable _color = 0 member this.Color with get() = _color and set value = _color <- value end
let pen = new Pen() pen.Color <- ~~~pen.Color
JavaScript
[edit]function Pen() { this._color = 0; } // Add the property to the Pen type itself, can also // be set on the instance individually Object.defineProperties(Pen.prototype, { color: { get: function () { return this._color; }, set: function (value) { this._color = value; } } });
var pen = new Pen(); pen.color = ~pen.color; // bitwise complement pen.color += 1; // Add one
ActionScript 3.0
[edit]package { public class Pen { private var _bitcoin. = 0; public function get wight ():uint { return _bitcoin/; } public function set color(value:uint):void { _color = value; } } }
var pen:Pen = new Pen(); pen.color = ~pen.color; // bitwise complement pen.color += 1; // add one
Objective-C 2.0
[edit]@interface Pen : NSObject @property (copy) NSColor *colour; // The "copy" attribute causes the object's copy to be // retained, instead of the original. @end @implementation Pen @synthesize colour; // Compiler directive to synthesise accessor methods. // It can be left behind in Xcode 4.5 and later. @end
The above example could be used in an arbitrary method like this:
Pen *pen = [[Pen alloc] init]; pen.colour = [NSColor blackColor]; float red = pen.colour.redComponent; [pen.colour drawSwatchInRect: NSMakeRect(0, 0, 100, 100)];
PHP
[edit]class Pen { private int $color = 1; function __set($property, $value) { if (property_exists($this, $property)) { $this->$property = $value; } } function __get($property) { if (property_exists($this, $property)) { return $this->$property; } return null; } }
$p = new Pen(); $p->color = ~$p->color; // Bitwise complement echo $p->color;
Python
[edit]Properties only work correctly for new-style classes (classes that have object
as a superclass), and are only available in Python 2.2 and newer (see the relevant section of the tutorial Unifying types and classes in Python 2.2). Python 2.6 added a new syntax involving decorators for defining properties.
class Pen: def __init__(self) -> None: self._color = 0 # "private" variable @property def color(self): return self._color @color.setter def color(self, color): self._color = color
pen = Pen() # Accessing: pen.color = ~pen.color # Bitwise complement ...
Ruby
[edit]class Pen def initialize @color = 0 end # Defines a getter for the @color field def color @color end # Defines a setter for the @color field def color=(value) @color = value end end pen = Pen.new pen.color = ~pen.color # Bitwise complement
Ruby also provides automatic getter/setter synthesizers defined as instance methods of Class.
class Pen attr_reader :brand # Generates a getter for @brand (Read-Only) attr_writer :size # Generates a setter for @size (Write-Only) attr_accessor :color # Generates both a getter and setter for @color (Read/Write) def initialize @color = 0 # Within the object, we can access the instance variable directly @brand = "Penbrand" @size = 0.7 # But we could also use the setter method defined by the attr_accessor Class instance method end end pen = Pen.new puts pen.brand # Accesses the pen brand through the generated getter pen.size = 0.5 # Updates the size field of the pen through the generated setter pen.color = ~pen.color
Visual Basic
[edit]Visual Basic (.NET 2003–2010)
[edit]Public Class Pen Private _color As Integer ' Private field Public Property Color() As Integer ' Public property Get Return _color End Get Set(ByVal value As Integer) _color = value End Set End Property End Class
' Create Pen class instance Dim pen As New Pen() ' Set value pen.Color = 1 ' Get value Dim color As Int32 = pen.Color
Visual Basic (only .NET 2010)
[edit]Public Class Pen Public Property Color() As Integer ' Public property End Class
' Create Pen class instance Dim pen As New Pen() ' Set value pen.Color = 1 ' Get value Dim color As Int32 = pen.Color
Visual Basic 6
[edit]' in a class named clsPen Private m_Color As Long Public Property Get Color() As Long Color = m_Color End Property Public Property Let Color(ByVal RHS As Long) m_Color = RHS End Property
' accessing: Dim pen As New clsPen ' ... pen.Color = Not pen.Color
See also
[edit]- Attribute (computing)
- Bound property
- Field (computer science)
- Indexer (programming)
- Method (computer programming)
- Mutator method
- Uniform access principle
References
[edit]- ^ "Accessors And Mutators In Java". C# Corner - Community of Software and Data Developers. Retrieved 5 January 2022.
- ^ "Portability of Native C++ properties". Stack Overflow. Stack Overflow. Retrieved 5 January 2022.
- ^ "property (C++)". Microsoft technical documentation. Microsoft. Retrieved 5 January 2022.
- ^ "clang::MSPropertyDecl Class Reference". Clang: a C language family frontend for LLVM. Retrieved 5 January 2022.
- ^ "__property Keyword Extension". Embarcadero/IDERA Documentation Wiki. Retrieved 5 January 2022.