Recent from talks
Contribute something
Nothing was collected or created yet.
Property (programming)
View on WikipediaThis 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
__propertykeyword.[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();
int colorTmp = 0;
// ...
pen.Color = 17;
colorTmp = 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]import std;
using std::same_as;
template <typename T>
class Property {
T value;
public:
// Ensure T and T2 are the same type
template <typename U>
requires same_as<T, U>
T& operator=(const U& i) {
value = i;
return *this;
}
// Implicit conversion back to T.
operator T const&() const {
return value;
}
};
struct Foo {
// Properties using unnamed classes.
class {
private:
int value;
public:
int& operator=(const int& i) {
return value = i;
}
int operator int() const {
return value;
}
} alpha;
class {
private:
float value;
public:
float& operator=(const float& f) {
return value = f;
}
float operator float() const {
return value;
}
} bravo;
};
struct Bar {
// Using the Property<>-template.
Property<bool> alpha;
Property<unsigned int> bravo;
};
int main(int argc, char* argv[]) {
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::println("{}, {}, {}, {}", foo.alpha, foo.bravo, bar.alpha, bar.bravo);
return 0;
}
C++, Microsoft, GCC, LLVM/clang and C++Builder-specific
[edit]An example adapted from the MSDN documentation page.
// declspec_property.cpp
struct Integer {
int value;
void setValue(int j) noexcept {
value = j;
}
[[nodiscard]]
int getValue() const noexcept {
return i;
}
__declspec(property(get = getValue, put = setValue))
int prop;
};
int main() {
Integer s;
s.prop = 5;
return 0;
}
D
[edit]class Pen {
private int myColor; // private field
// public get property
public int color() {
return myColor;
}
// public set property
public void color(int value) {
myColor = value;
}
}
Pen 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 myColor; // private field
// public get property
@property
public int color() {
return myColor;
}
// public set property
@property
public void color(int value) {
myColor = 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 _color:uint = 0;
public function get color ():uint {
return _color;
}
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:
_color: int # "private" variable
def __init__(self) -> None:
self._color = 0
@property
def color(self) -> int:
return self._color
@color.setter
def color(self, color: int) -> None:
self._color = color
pen: 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]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.
Property (programming)
View on Grokipediaproperty() built-in function or @property decorator turns methods into managed attributes, allowing dynamic computation or caching of values upon access.[3]
Many modern languages, including Swift[4] and Kotlin[5], incorporate properties to associate values with classes, structures, or enumerations, distinguishing between stored properties (direct data storage) and computed properties (derived values). This feature aids in achieving principles like abstraction and immutability, with variations such as read-only properties or init-only setters to enforce design contracts. Overall, properties balance simplicity and power, making them a cornerstone of robust object-oriented design across ecosystems.
Core Concepts
Definition and Role
In object-oriented programming, a property is a special class member that serves as an intermediary for accessing or modifying a private field, typically implemented through getter and setter methods that mimic the syntax of direct field access. This construct provides a flexible mechanism to read from, write to, or even compute the value of underlying data, allowing developers to enforce rules such as validation or lazy initialization while maintaining a simple interface for clients.[2] The primary role of properties in object-oriented design is to enable controlled access to an object's internal state, thereby upholding encapsulation principles by hiding implementation details from external code. For instance, a property can perform computations on demand, trigger side effects like notifications, or restrict modifications based on conditions, all without exposing the raw data storage or altering the public API. This abstraction supports maintainable and extensible software by decoupling the object's behavior from its data representation.[2] The concept of properties originated in the 1980s with languages like Eiffel, based on the Uniform Access Principle, and gained wider adoption in the 1990s in languages such as Visual Basic 4.0, released by Microsoft in 1995, and Delphi, released by Borland in 1995. These languages introduced properties to replace verbose explicit getter and setter method pairs, offering a more intuitive way to manage object attributes in visual and rapid application development environments.[6][7] A key distinction from plain fields lies in the abstraction layer properties provide: while fields offer direct, unmediated storage of data, properties allow internal changes—such as evolving a stored value into a dynamically computed one—without breaking dependent code, thus enhancing long-term flexibility and adherence to object-oriented best practices.[2]Benefits and Design Principles
Properties in object-oriented programming offer significant benefits by enhancing encapsulation, which involves bundling data with methods that operate on it while restricting direct access to the internal state. This approach hides implementation details from external code, allowing developers to modify the underlying data structure without affecting dependent components, thereby promoting maintainability and flexibility. For instance, properties enable the exposure of data through controlled interfaces, ensuring that changes to the object's internal representation do not break the public API.[8][9] A key advantage is the ability to perform input validation within setter accessors, preventing invalid states by checking values before assignment, such as ensuring a numeric property falls within acceptable bounds. Properties also support read-only or write-only access configurations; for example, omitting a setter makes a property read-only, enforcing immutability for certain data while allowing retrieval. Additionally, since properties are typically implemented as methods under the hood, they facilitate debugging by permitting breakpoints on get or set operations, enabling developers to inspect access patterns and trace issues at specific points of interaction. This contrasts with plain fields, which lack such hooks.[8][10] Compared to plain methods, properties provide a field-like syntax for accessing computed or derived values, reducing API verbosity—for example,obj.value instead of obj.getValue()—while retaining the ability to inject logic like computation or caching. This syntactic sugar improves usability without sacrificing the encapsulation benefits of methods.[8]
Design principles for properties emphasize the principle of least privilege, granting access only to the minimum necessary operations (e.g., read access without write) to minimize security risks and unintended modifications. Properties should be used for any data that requires validation, computation, or controlled exposure, but avoided for simple, unvalidated fields to prevent unnecessary abstraction layers that complicate code without adding value. Over-reliance on properties can lead to "getter/setter hell," where classes become cluttered with trivial accessors that expose internal state excessively, violating true encapsulation. Instead, favor immutability where possible by designing objects with read-only properties, as this reduces bugs from shared mutable state and simplifies reasoning about program behavior.[11][9][12][13]
Language Support Overview
Native Property Support
Native property support refers to built-in language syntax that allows developers to define properties as a distinct construct, typically combining field-like access with method-like behavior for encapsulation. This feature enables controlled access to an object's data through getters and setters, often with automatic backing field generation for simple cases. Several programming languages provide this capability natively, integrating properties seamlessly into their object models. C# introduced properties in version 1.0, released in January 2002, allowing declaration with get and set accessors that can include custom logic or auto-implementation for backing fields.[14] Auto-implemented properties, which automatically generate private backing fields, were added in C# 3.0 in November 2007, simplifying common use cases while supporting modifiers like virtual for inheritance.[14] Delphi, based on Object Pascal, provided native property support with read and write specifiers starting from its first release in February 1995, enabling indexed and default properties alongside standard access control.[15] Python offers properties through the built-inproperty() function, introduced in version 2.2 in December 2001, which transforms methods into read-only or read-write attributes without altering the public interface.[16] The @property decorator syntax, added in Python 2.4 in 2004 via PEP 318, further streamlined this by allowing concise getter definitions with optional setter and deleter methods.[17] F#, a .NET language, has supported properties since its initial 1.0 release in March 2005, using get and set keywords for explicit or auto-generated accessors that integrate with the language's functional paradigm.[18]
Swift includes computed properties natively since its 1.0 release in June 2014, where properties can be read-only or read-write with custom computation logic, and stored properties with automatic observers for value changes. Kotlin, launched in July 2011 as a JVM-compatible language, provides native property support with custom getters and setters using dedicated syntax (e.g., var and val declarations), compiling to getter and setter methods on the JVM for interoperability with Java.[5] In languages without dedicated syntax, such as Rust (stable since 2015), getter methods serve as property analogs by providing field-like access via &self functions, though lacking syntactic sugar for setters. Core features across these implementations often include automatic code generation for backing storage in simple scenarios and integration with language attributes or modifiers, such as C#'s virtual keyword for polymorphic properties.
The concept of properties evolved from early object-oriented languages inspired by Smalltalk's message-passing model, where attributes are accessed via methods, influencing later explicit syntax in Pascal variants and .NET ecosystems. In C++, properties lack standardization in the ISO specification, remaining available primarily through vendor extensions like Microsoft's __property keyword, despite related proposals such as P1130 for modules in C++20 that do not address properties directly.
Simulated Properties via Conventions
In languages lacking native property support, developers often simulate properties through established naming conventions that mimic getter and setter behaviors, promoting consistency across codebases. A prominent example is Java's JavaBeans pattern, which standardizes the use of methods namedgetX() and setX() for accessing and modifying a property X, as defined in the JavaBeans specification released in 1997.[19] This convention enables introspection tools and frameworks to treat these methods as property equivalents, facilitating data binding and serialization without altering the core language syntax. Similarly, in Ruby, the attr_accessor method, a core feature available since the language's early versions in the 1990s, automatically generates corresponding getter and setter methods for instance variables, streamlining the creation of accessible attributes.
Beyond pure conventions, certain languages provide framework-level mechanisms to emulate properties more dynamically. In JavaScript, the Object.defineProperty method, introduced in ECMAScript 5 (ES5) in December 2009, allows developers to define getters and setters on objects, controlling property access and enabling computed or validated values without traditional method naming.[20] Likewise, PHP since version 5.0, released in November 2004, supports magic methods such as __get and __set, which intercept property read and write operations on inaccessible members, allowing custom logic for dynamic property simulation.[21] These approaches integrate seamlessly with object-oriented paradigms but rely on runtime interception rather than syntactic sugar.
While effective for enforcing uniformity, simulated properties via conventions and frameworks carry limitations, including the absence of compile-time validation, which can lead to runtime errors if methods are inconsistently implemented. For instance, Java's pattern requires manual adherence, but tools like Project Lombok mitigate this by using annotations such as @Getter and @Setter to automatically generate boilerplate getter and setter methods during compilation, reducing verbosity while preserving the bean convention.[22] This simulation fosters interoperability in ecosystems without native support but demands disciplined usage to avoid fragility.
Modern developments in these languages further blur the distinction between simulation and native support. Java introduced records as a preview feature in version 14 in March 2020, providing concise, immutable data carriers with implicitly generated accessors that resemble properties, though still built on underlying methods.[23]
Syntax Patterns
Direct Access Notation
Direct access notation, commonly known as dot notation, refers to the syntactic construct used to access or modify properties of an object as if they were direct fields, while transparently invoking underlying getter or setter methods when properties are involved.[24][2] This notation employs a period (.) to separate the object reference from the property identifier, such asobject.property, enabling developers to interact with encapsulated data without explicit method calls.[25]
The usage of dot notation is widespread in languages supporting properties, including C#, Python, and JavaScript, where it facilitates intuitive access to object members.[2][25][24] It supports method chaining, allowing sequential property accesses like object.prop1.prop2, which enhances code readability and expressiveness in object-oriented designs.[26]
Semantically, dot notation resolution varies by language typing paradigm: in static languages like C#, property access is resolved at compile-time based on the object's declared type, ensuring type safety and enabling optimizations such as inlining getters.[27] In dynamic languages like Python and JavaScript, resolution occurs at runtime, where the interpreter locates the property via attribute lookup mechanisms, potentially leading to errors if the property is undefined.[28][24] This notation also respects access modifiers, such as public, private, or internal in C#, restricting visibility and preventing unauthorized access during compilation or execution.[2]
Variations in dot notation include integration with integrated development environments (IDEs), where it supports auto-completion and IntelliSense for property names, improving developer productivity across languages.[27] For instance, C# allows access to internal properties within assemblies via dot notation, a nuance that underscores its role in modular code organization.[2] As an alternative, bracket notation enables dynamic or string-based property access, though it is less common for direct, identifier-based usage.[24]
Indirect Access Notation
Indirect access notation, commonly referred to as bracket notation, provides a mechanism for dynamically accessing object properties using an expression that evaluates to a property key, such as a string or symbol. This approach is particularly suited for scenarios involving computed keys or those derived at runtime, as seen in the syntaxobject[expression] where the expression resolves to the desired key.[24] In contrast to static access methods, it facilitates flexible property retrieval without requiring compile-time knowledge of the key.[29]
This notation has been a core feature in several programming languages, enabling dynamic property handling. In JavaScript, bracket notation has been available since ECMAScript 1, released in 1997, and is used for accessing properties with variable names stored in variables or generated dynamically.[24] Python employs equivalent functionality through the built-in functions getattr(object, name) and setattr(object, name, value), which accept string-based attribute names for runtime access and modification, making it ideal for scenarios with non-static identifiers.[30] In Ruby, dynamic access to properties is supported via bracket notation on Hash objects, which serve as flexible property containers,[31] or through methods like send for invoking attributes by name strings.[32] These mechanisms are especially valuable when property names are determined by user input, configuration data, or algorithmic computation.
Semantically, bracket notation operates through runtime evaluation of the key expression, converting it to a valid property key—typically a string in JavaScript and Python—before performing the access.[33] It explicitly supports non-identifier keys, including those with spaces, hyphens, or other special characters, such as obj['user-name'] or getattr(obj, 'user name'), which cannot be expressed using direct notation.[30] This flexibility allows for more expressive data structures but introduces risks, including runtime errors if the evaluated key is invalid or absent, and in JavaScript, vulnerabilities like prototype pollution when untrusted inputs are used as keys, potentially allowing attackers to inject or modify prototype properties.[34]
Compared to direct dot notation, which is limited to valid identifiers and static keys, indirect access prioritizes adaptability at the expense of readability and type safety.[24] While dot notation offers compile-time validation, bracket notation's dynamic nature supports broader key varieties but requires careful handling to mitigate errors or security issues, such as validating keys before access in untrusted environments.[34]
Implementation in Specific Languages
C# and .NET Ecosystem
In C#, properties provide a structured way to encapsulate private fields, allowing controlled access through getter and setter methods while appearing as direct field accesses to consumers. The basic syntax for a simple read-write property uses auto-implemented accessors, declared aspublic int Property { get; set; }, where the compiler automatically generates a private backing field and the necessary logic for retrieval and assignment. This feature, known as auto-implemented properties, was introduced in C# 3.0 in 2007 alongside .NET Framework 3.5, simplifying property declaration when no custom logic is needed in the accessors.[35][14]
For scenarios requiring additional logic, such as validation or computation, full accessor blocks can be defined explicitly. A property might include a get accessor to return a computed value and a set accessor to perform side effects, as in:
private int _value;
public int Value {
get { return _value * 2; }
set { if (value > 0) _value = value; }
}
private int _value;
public int Value {
get { return _value * 2; }
set { if (value > 0) _value = value; }
}
=> operator, such as public int ComputedValue => _value * 2;, which reduces boilerplate for single-expression logic.[2][36]
The .NET ecosystem enhances properties through metadata attributes, which allow customization for design-time tools and runtime behavior. For instance, the [Browsable(false)] attribute from System.ComponentModel hides a property from visual designers like the Properties window in Visual Studio, improving user experience in UI development. More advanced features include init-only setters, introduced in C# 9.0 with .NET 5 in 2020, which permit assignment only during object initialization via object initializers or constructors, promoting immutability: public string Name { get; init; }. Refinements in C# 12 (2023, with .NET 8) further streamlined property usage through better integration with primary constructors and collection expressions, though core property syntax remained consistent. C# 13 (2024, with .NET 9) introduced partial properties and indexers, allowing the declaration and implementation of properties to be split across partial classes, which supports source generators and large-scale code generation scenarios.[37][38][39][40]
Properties in C# integrate naturally with LINQ for querying object collections and with asynchronous programming, where properties often serve as synchronous entry points to async operations—though direct async getters or setters are not supported, recommending async methods instead for non-blocking data access. This design ensures properties remain lightweight while fitting into broader .NET patterns like data binding in WPF or Entity Framework.[41][42]
In Visual Basic .NET (VB.NET), properties follow a procedural syntax introduced with the language in 2002 alongside .NET Framework 1.0, declared as Property Name() As Type Get ... End Get Set(ByVal value As Type) ... End Set End Property. This supports both read-only (Get only) and write-only (Set only) variants, with optional parameters for indexed properties. Auto-implemented properties, mirroring C#'s convenience, were added in VB.NET 2010 (Visual Basic 10) with .NET Framework 4.0, allowing shorthand like Property Name As Type, where the compiler handles the backing field. Unlike C#, VB.NET properties emphasize explicit procedure blocks, but share .NET's attribute system for interoperability. Post-2010 updates, such as enhanced auto-implementation in VB 14 (2015), aligned VB.NET more closely with C# while preserving its verbose, beginner-friendly style.[43][44]
Python and Dynamic Typing
In Python, properties are implemented using the built-inproperty class, which leverages the descriptor protocol to customize attribute access at runtime. Introduced in Python 2.2 as part of the enhancements to new-style classes, the property mechanism allows methods to behave like attributes, enabling computed values without explicit storage or getter/setter invocation.[16] The @property decorator, a syntactic convenience added with Python's general decorator support, simplifies defining a read-only property by transforming a method into a descriptor. For example:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def diameter(self):
return 2 * self._radius
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def diameter(self):
return 2 * self._radius
circle.diameter invokes the method transparently, returning a computed value based on the underlying _radius attribute.[3] This approach supports dynamic typing by allowing attribute-like access while encapsulating logic, aligning with Python's emphasis on readability and flexibility.[45]
Properties can be extended with setter and deleter methods using corresponding decorators, also available since Python 2.2 via the property constructor's fset and fdel arguments, or through @name.setter and @name.deleter syntax. These enable validation or side effects during assignment or deletion without altering the public interface. For instance:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@radius.deleter
def radius(self):
del self._radius
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@radius.deleter
def radius(self):
del self._radius
__get__, __set__, and __delete__ methods), allowing properties to be defined at the class level but bound dynamically to instances during access. This enables flexible, runtime modifications—such as adding or overriding properties post-instantiation—without recompilation, a hallmark of Python's interpreted, dynamic typing system.[46] For example, a property can be reassigned at runtime to alter behavior, supporting metaprogramming patterns like dynamic class extension.[45]
Since Python 3.5, type hints enhance property usability by allowing annotations on getter, setter, and deleter methods, improving static analysis and IDE support while preserving runtime dynamism. Annotations like @property def radius(self) -> float: declare expected return types, and setters can similarly annotate parameters, facilitating tools like mypy for optional type checking.[47] In data classes, introduced in Python 3.7 (released in 2018), properties coexist seamlessly with automatically generated __[init](/page/Init)__ and other methods, enabling concise definitions of structured data with computed fields. For example, a dataclass might use @property for a derived attribute like full_name from first_name and last_name fields.[48] This integration streamlines boilerplate while maintaining property semantics.[49]
For performance optimization in memory-constrained scenarios, properties work effectively with the __slots__ attribute, available since Python 2.2. Properties defined in slotted classes avoid the overhead of __dict__, reducing instance size and speeding up attribute access by up to 30-50% in benchmarks for descriptor-heavy code.[50] This combination is particularly useful in high-performance applications, such as numerical computing libraries, where dynamic properties must balance flexibility with efficiency.[45]
JavaScript and ES6+
In JavaScript, properties form the core of object-oriented programming, evolving from a prototype-based model in early ECMAScript editions to more structured class syntax introduced in ES6 (ECMAScript 2015). Prior to ES6, objects were primarily manipulated through constructor functions and prototypes, where properties were added dynamically via assignment or methods likeObject.defineProperty from ES5 (ECMAScript 2009), allowing fine-grained control over property attributes such as value, writability, enumerability, and configurability.[51][52] This prototype chain enables inheritance by delegating property lookups from an object to its prototype, promoting shared behavior across instances without duplicating data.[51]
ES6 introduced class syntax as syntactic sugar over prototypes, simplifying property and method definitions while maintaining the underlying delegation model. Within classes, getters and setters can be declared using the get and set keywords, providing a concise way to define accessor properties that intercept reads and writes. For example:
class Circle {
constructor([radius](/page/Radius)) {
this.[radius](/page/Radius) = [radius](/page/Radius);
}
get [radius](/page/Radius)() {
return this._[radius](/page/Radius);
}
set [radius](/page/Radius)(value) {
if (value < 0) throw new Error("[Radius](/page/Radius) cannot be negative");
this._[radius](/page/Radius) = value;
}
get area() {
return Math.PI * this.[radius](/page/Radius) ** 2;
}
}
class Circle {
constructor([radius](/page/Radius)) {
this.[radius](/page/Radius) = [radius](/page/Radius);
}
get [radius](/page/Radius)() {
return this._[radius](/page/Radius);
}
set [radius](/page/Radius)(value) {
if (value < 0) throw new Error("[Radius](/page/Radius) cannot be negative");
this._[radius](/page/Radius) = value;
}
get area() {
return Math.PI * this.[radius](/page/Radius) ** 2;
}
}
Object.defineProperty on the prototype or instance, often with verbose descriptor objects. In ES5, the syntax for an accessor property is:
const obj = {};
Object.defineProperty(obj, 'key', {
get: function() {
return this._value;
},
set: function(value) {
this._value = value;
},
enumerable: false, // Non-enumerable by default
configurable: true
});
const obj = {};
Object.defineProperty(obj, 'key', {
get: function() {
return this._value;
},
set: function(value) {
this._value = value;
},
enumerable: false, // Non-enumerable by default
configurable: true
});
for...in loops or Object.keys(), which helps maintain cleaner APIs by hiding implementation details while still allowing direct access. Non-enumerable properties can be explicitly set using the enumerable: false flag in Object.defineProperty, serving to control iteration behavior in libraries or frameworks.[54]
ES6 also introduced the Proxy object for advanced meta-programming, allowing interception of property operations across an entire object via traps like get and set in a handler. A proxy wraps a target object, enabling custom logic such as validation or logging during property access—for instance, a get trap can return default values for undefined properties or track reads dynamically. This extends beyond individual accessors, facilitating reactive systems or transparent virtualization without modifying the target.[55]
For encapsulation, ES2022 (ECMAScript 2022) added native private fields and methods using the # prefix, restricting access to within the class declaration and preventing external interference. Private accessors follow the same pattern, prefixed with #:
class MyClass {
#privateData = 42;
get #privateGetter() {
return this.#privateData;
}
set #privateSetter(value) {
this.#privateData = value;
}
}
class MyClass {
#privateData = 42;
get #privateGetter() {
return this.#privateData;
}
set #privateSetter(value) {
this.#privateData = value;
}
}
WeakMap to associate private data with instances as keys, leveraging weak references for garbage collection and avoiding memory leaks— for example, a class could maintain a WeakMap of instance-to-private-value mappings accessed via symbols or closures. This pattern, while effective, was more verbose and lacked syntactic enforcement compared to the native # syntax.[56][57]
C++ Extensions and Standards
Standard C++ does not provide native support for properties as syntactic sugar over methods, unlike languages such as C#. Instead, developers simulate properties using getter and setter member functions, often following naming conventions likegetValue() and setValue(int) to encapsulate data access and modification.[58] These methods can be public or private, allowing fine-grained control over access, and are commonly used in classes to maintain encapsulation without direct member variable exposure. Template-based approaches, such as those in Boost libraries, can extend this simulation for more structured data handling, though they focus on hierarchical key-value stores rather than individual class members.[59]
Microsoft's Visual Studio compiler extends C++ with the __declspec(property) attribute, enabling property-like behavior for non-static data members in classes and structures. This extension treats property declarations as virtual data members, automatically converting read access (r-value) to calls to a specified getter function and write access (l-value) to a setter function, including support for array indexing. For example, a declaration like __declspec(property(get=getFunc, put=putFunc)) int prop; allows usage as obj.prop = 5;, which invokes putFunc(5). This feature is specific to MSVC and not portable to other compilers without emulation.[60]
GCC and Clang do not offer a direct equivalent to __declspec(property) for simulating properties, relying instead on standard getter/setter methods or custom attributes for related optimizations, such as function inlining or deprecation warnings on accessors. While Clang supports a subset of Microsoft extensions via compatibility modes, full property simulation remains unavailable without third-party tools or macros to abstract getter/setter calls. Developers targeting these compilers must adhere to conventional methods or use preprocessor directives for cross-compiler property emulation.[61]
Virtual properties can be implemented in standard C++ using abstract base classes, where pure virtual getter and setter functions define an interface for polymorphic access. An abstract class declares these as virtual int getValue() const = 0; and virtual void setValue(int) = 0;, preventing instantiation of the base class and requiring derived classes to provide implementations. This approach enables runtime polymorphism, where calls to properties on base class references dispatch to the appropriate derived class method.
C++20 introduces concepts, which allow constraining template parameters to ensure types provide required access patterns, indirectly supporting property-like designs in generic code. For instance, a concept like template<typename T> [concept](/page/Concept) HasGetter = requires(T t) { { t.getValue() } -> std::same_as<int>; }; verifies the existence of a getter before template instantiation, improving error messages and enabling safer property access in libraries. Concepts evaluate requirements in a global access context, decoupling them from class visibility rules.
Getters can leverage the constexpr specifier (introduced in C++11 and enhanced in later standards) to enable compile-time evaluation and computation, particularly for literal types. A constexpr getter, such as constexpr int getSize() const { return sz; } in a literal class, computes its value at compile time when invoked in a constant expression context, allowing properties to contribute to template arguments or static assertions without runtime overhead. This is limited to functions with literal return types and simple bodies, ensuring core constant expression compliance.[62]
Proposals for static reflection in C++26, such as P2996R4, aim to enhance property implementations by providing compile-time introspection of class members via std::meta::info and operators like ^ for reflection. This would allow automated generation of getters and setters through queries like nonstatic_data_members_of and define_class, reducing boilerplate for property-like access in metaprogramming. The feature is targeted for C++26, with experimental support in Clang forks, building on earlier reflection TS efforts.[63]
Other Languages
In Ruby, properties are typically implemented through class methods such asattr_reader, attr_writer, and attr_accessor, which generate corresponding getter and setter methods for instance variables. These features have been available since Ruby 1.0, released in 1995, and support dynamic definition at runtime, enabling flexible attribute management in object-oriented code.
PHP simulates properties using magic methods __get and __set, introduced in PHP 5.0 to handle access to undefined or inaccessible class members, allowing custom logic for reading and writing data. Starting with PHP 7.4 in 2019, the language added support for typed properties, which declare specific types for class fields to enhance type safety and performance.[21][64]
Objective-C introduced the @property syntax in version 2.0, released in 2007 with Mac OS X 10.5, providing a declarative way to define accessor methods and instance variables. The @synthesize directive automates the implementation of these accessors, and properties integrate seamlessly with Automatic Reference Counting (ARC), introduced in 2011, for memory management without manual retain/release calls.[65][66]
In Swift, properties are a fundamental feature supporting both stored properties (direct data storage in instances) and computed properties (derived values via getter/setter logic), introduced since Swift 1.0 in 2014. Stored properties can be variables (var) for mutable access or constants (let) for immutability, with options like lazy initialization for deferred computation. Computed properties enable dynamic behavior, such as read-only access or side effects in setters, and integrate with property observers (willSet/didSet) to react to changes. This design emphasizes safety and performance in Apple's ecosystem.[4]
Kotlin provides explicit property declarations with backing fields or custom accessors, available since Kotlin 1.0 in 2011. Properties can be val (read-only, like final) or var (read-write), with getters and setters that can include logic for validation or computation. Delegated properties, using by keyword with delegates like lazy or custom implementations, allow outsourcing storage and access, enhancing conciseness for complex scenarios like observable or vetoable properties.[5]
Several other languages offer property-like mechanisms with varying syntax. In D, @property-attributed functions serve as getters (no parameters) or setters (one parameter), enabling computed properties since the language's initial release in 2001. ActionScript 3.0, introduced in 2006, uses explicit get and set function pairs to define properties, supporting encapsulation in Flash and AIR applications. The eC language, a C superset, provides property declarations similar to C++ extensions, with getter and setter bindings for object attributes. Delphi has included property declarations since its 1995 debut, specifying read/write accessors and index parameters for array-like behavior in Pascal-based development. These approaches share common patterns of abstracting direct field access for controlled data handling across diverse ecosystems.[67][68]
Advanced Topics
Properties in Inheritance and Polymorphism
In object-oriented programming, properties defined in a base class are inherited by derived classes, allowing subclasses to access and utilize them directly unless explicitly overridden. To enable customization in subclasses, properties can be declared as virtual or abstract in the base class, permitting derived classes to provide alternative implementations using an override mechanism. For instance, in C#, a virtual property includes thevirtual keyword on its accessors, and the derived class uses override to redefine the getter or setter logic. This approach ensures that the property's interface remains consistent across the hierarchy while allowing behavioral variation.[8][69]
Access to base class properties from derived classes is facilitated through keywords like base in C#, which explicitly invokes the parent's implementation during overriding, preventing infinite recursion and enabling extension of the original behavior. In Python, properties—implemented via the @property decorator—are treated as methods and thus follow standard method overriding rules; subclasses can redefine a property by reapplying the decorator or overriding its underlying getter, setter, or deleter methods, often using super() to invoke the parent's version. This inheritance model promotes code reuse while supporting hierarchical customization.[70][3]
Polymorphism extends this capability by enabling runtime dispatch for virtual properties, where the specific implementation invoked depends on the actual object type rather than the reference type. When an object is upcast to a base class reference, accessing a virtual property resolves to the most derived override, preserving polymorphic behavior and allowing uniform treatment of heterogeneous collections. Interfaces further enhance polymorphism by defining property signatures without implementation, requiring implementing classes to provide concrete accessors; for example, a C# interface might declare int Value { get; }, which derived classes must fulfill, enabling contract-based polymorphism across unrelated types.[71][72]
Key challenges arise in distinguishing overriding from shadowing (or hiding), where a derived class redeclares a property using a modifier like new in C#, which does not participate in polymorphism and instead binds based on the reference type, potentially leading to unexpected behavior during upcasting. Access modifiers also complicate inheritance: derived classes cannot loosen restrictions (e.g., making a base private property public) without violating encapsulation, though they can add or restrict accessors in overrides. These distinctions ensure type safety but require careful design to avoid subtle bugs in polymorphic contexts.[73][74]
For example, consider a base class Shape with a virtual property Area { get; } that returns a default value; a derived Circle overrides it to compute π * radius². When stored in a Shape[] array and iterated, each element's Area invokes the appropriate override at runtime, demonstrating polymorphic property access without explicit type checks.[71]
