Mutator method

Last updated

In computer science, a mutator method is a method used to control changes to a variable. They are also widely known as setter methods. Often a setter is accompanied by a getter (together also known as accessors), which returns the value of the private member variable.

Contents

The mutator method is most often used in object-oriented programming, in keeping with the principle of encapsulation. According to this principle, member variables of a class are made private to hide and protect them from other code, and can only be modified by a public member function (the mutator method), which takes the desired new value as a parameter, optionally validates it, and modifies the private member variable. Mutator methods can be compared to assignment operator overloading but they typically appear at different levels of the object hierarchy.

Mutator methods may also be used in non-object-oriented environments. In this case, a reference to the variable to be modified is passed to the mutator, along with the new value. In this scenario, the compiler cannot restrict code from bypassing the mutator method and changing the variable directly. The responsibility falls to the developers to ensure the variable is only modified through the mutator method and not modified directly.

In programming languages that support them, properties offer a convenient alternative without giving up the utility of encapsulation.

In the examples below, a fully implemented mutator method can also validate the input data or take further action such as triggering an event.

Implications

The alternative to defining mutator and accessor methods, or property blocks, is to give the instance variable some visibility other than private and access it directly from outside the objects. Much finer control of access rights can be defined using mutators and accessors. For example, a parameter may be made read-only simply by defining an accessor but not a mutator. The visibility of the two methods may be different; it is often useful for the accessor to be public while the mutator remains protected, package-private or internal.

The block where the mutator is defined provides an opportunity for validation or preprocessing of incoming data. If all external access is guaranteed to come through the mutator, then these steps cannot be bypassed. For example, if a date is represented by separate private year, month and day variables, then incoming dates can be split by the setDate mutator while for consistency the same private instance variables are accessed by setYear and setMonth. In all cases month values outside of 1 - 12 can be rejected by the same code.

Accessors conversely allow for synthesis of useful data representations from internal variables while keeping their structure encapsulated and hidden from outside modules. A monetary getAmount accessor may build a string from a numeric variable with the number of decimal places defined by a hidden currency parameter.

Modern programming languages often offer the ability to generate the boilerplate for mutators and accessors in a single lineas for example C#'s public string Name { get; set; } and Ruby's attr_accessor :name. In these cases, no code blocks are created for validation, preprocessing or synthesis. These simplified accessors still retain the advantage of encapsulation over simple public instance variables, but it is common that, as system designs progress, the software is maintained and requirements change, the demands on the data become more sophisticated. Many automatic mutators and accessors eventually get replaced by separate blocks of code. The benefit of automatically creating them in the early days of the implementation is that the public interface of the class remains identical whether or not greater sophistication is added, requiring no extensive refactoring if it is. [1]

Manipulation of parameters that have mutators and accessors from inside the class where they are defined often requires some additional thought. In the early days of an implementation, when there is little or no additional code in these blocks, it makes no difference if the private instance variable is accessed directly or not. As validation, cross-validation, data integrity checks, preprocessing or other sophistication is added, subtle bugs may appear where some internal access makes use of the newer code while in other places it is bypassed.

Accessor functions can be less efficient than directly fetching or storing data fields due to the extra steps involved, [2] however such functions are often inlined which eliminates the overhead of a function call.

Examples

UML mutator method.svg

Assembly

studentstructagedd?studentends
.codestudent_get_ageprocobject:DWORDmovebx,objectmoveax,student.age[ebx]retstudent_get_ageendpstudent_set_ageprocobject:DWORD,age:DWORDmovebx,objectmoveax,agemovstudent.age[ebx],eaxretstudent_set_ageendp

C

In file student.h:

#ifndef _STUDENT_H#define _STUDENT_Hstructstudent;/* opaque structure */typedefstructstudentstudent;student*student_new(intage,char*name);voidstudent_delete(student*s);voidstudent_set_age(student*s,intage);intstudent_get_age(student*s);char*student_get_name(student*s);#endif

In file student.c:

#include<stdlib.h>#include<string.h>#include"student.h"structstudent{intage;char*name;};student*student_new(intage,char*name){student*s=malloc(sizeof(student));s->name=strdup(name);s->age=age;returns;}voidstudent_delete(student*s){free(s->name);free(s);}voidstudent_set_age(student*s,intage){s->age=age;}intstudent_get_age(student*s){returns->age;}char*student_get_name(student*s){returns->name;}

In file main.c:

#include<stdio.h>#include"student.h"intmain(void){student*s=student_new(19,"Maurice");char*name=student_get_name(s);intold_age=student_get_age(s);printf("%s's old age = %i\n",name,old_age);student_set_age(s,21);intnew_age=student_get_age(s);printf("%s's new age = %i\n",name,new_age);student_delete(s);return0;}

In file Makefile:

all:out.txt; cat $< out.txt:main; ./$< > $@ main:main.ostudent.omain.o student.o:student.hclean:;$(RM) *.oout.txtmain

C++

In file Student.h:

#ifndef STUDENT_H#define STUDENT_H#include<string>classStudent{public:Student(conststd::string&name);conststd::string&name()const;voidname(conststd::string&name);private:std::stringname_;};#endif

In file Student.cpp:

#include"Student.h"Student::Student(conststd::string&name):name_(name){}conststd::string&Student::name()const{returnname_;}voidStudent::name(conststd::string&name){name_=name;}

C#

This example illustrates the C# idea of properties, which are a special type of class member. Unlike Java, no explicit methods are defined; a public 'property' contains the logic to handle the actions. Note use of the built-in (undeclared) variable value.

publicclassStudent{privatestringname;/// <summary>/// Gets or sets student's name/// </summary>publicstringName{get{returnname;}set{name=value;}}}

In later C# versions (.NET Framework 3.5 and above), this example may be abbreviated as follows, without declaring the private variable name.

publicclassStudent{publicstringName{get;set;}}

Using the abbreviated syntax means that the underlying variable is no longer available from inside the class. As a result, the set portion of the property must be present for assignment. Access can be restricted with a set-specific access modifier.

publicclassStudent{publicstringName{get;privateset;}}

Common Lisp

In Common Lisp Object System, slot specifications within class definitions may specify any of the :reader, :writer and :accessor options (even multiple times) to define reader methods, setter methods and accessor methods (a reader method and the respective setf method). [3] Slots are always directly accessible through their names with the use of with-slots and slot-value, and the slot accessor options define specialized methods that use slot-value. [4]

CLOS itself has no notion of properties, although the MetaObject Protocol extension specifies means to access a slot's reader and writer function names, including the ones generated with the :accessor option. [5]

The following example shows a definition of a student class using these slot options and direct slot access:

(defclassstudent()((name:initarg:name:initform"":accessorstudent-name); student-name is setf'able(birthdate:initarg:birthdate:initform0:readerstudent-birthdate)(number:initarg:number:initform0:readerstudent-number:writerset-student-number)));; Example of a calculated property getter (this is simply a method)(defmethodstudent-age((selfstudent))(-(get-universal-time)(student-birthdateself)));; Example of direct slot access within a calculated property setter(defmethod(setfstudent-age)(new-age(selfstudent))(with-slots(birthdate)self(setfbirthdate(-(get-universal-time)new-age))new-age));; The slot accessing options generate methods, thus allowing further method definitions(defmethodset-student-number:before(new-number(selfstudent));; You could also check if a student with the new-number already exists.(check-typenew-number(integer1*)))

D

D supports a getter and setter function syntax. In version 2 of the language getter and setter class/struct methods should have the @property attribute. [6] [7]

classStudent{privatechar[]name_;// Getter@propertychar[]name(){returnthis.name_;}// Setter@propertychar[]name(char[]name_in){returnthis.name_=name_in;}}

A Student instance can be used like this:

autostudent=newStudent;student.name="David";// same effect as student.name("David")autostudent_name=student.name;// same effect as student.name()

Delphi

This is a simple class in Delphi language which illustrates the concept of public property for accessing a private field.

interfacetypeTStudent=classstrictprivateFName:string;procedureSetName(constValue:string);public/// <summary>/// Get or set the name of the student./// </summary>propertyName:stringreadFNamewriteSetName;end;// ...implementationprocedureTStudent.SetName(constValue:string);beginFName:=Value;end;end.

Java

In this example of a simple class representing a student with only the name stored, one can see the variable name is private, i.e. only visible from the Student class, and the "setter" and "getter" are public, namely the "getName()" and "setName(name)" methods.

publicclassStudent{privateStringname;publicStringgetName(){returnname;}publicvoidsetName(StringnewName){name=newName;}}

JavaScript

In this example constructor-function Student is used to create objects representing a student with only the name stored.

functionStudent(name){var_name=name;this.getName=function(){return_name;};this.setName=function(value){_name=value;};}

Or (using a deprecated way to define accessors in Web browsers): [8]

functionStudent(name){var_name=name;this.__defineGetter__('name',function(){return_name;});this.__defineSetter__('name',function(value){_name=value;});}

Or (using prototypes for inheritance and ES6 accessor syntax):

functionStudent(name){this._name=name;}Student.prototype={getname(){returnthis._name;},setname(value){this._name=value;}};

Or (without using prototypes):

varStudent={getname(){returnthis._name;},setname(value){this._name=value;}};

Or (using defineProperty):

functionStudent(name){this._name=name;}Object.defineProperty(Student.prototype,'name',{get:function(){returnthis._name;},set:function(value){this._name=value;}});

ActionScript 3.0

package{publicclassStudent{privatevar_name:String;publicfunctiongetname():String{return_name;}publicfunctionsetname(value:String):void{_name=value;}}}

Objective-C

Using traditional Objective-C 1.0 syntax, with manual reference counting as the one working on GNUstep on Ubuntu 12.04:

@interfaceStudent : NSObject{NSString*_name;}-(NSString*)name;-(void)setName:(NSString*)name;@end@implementationStudent-(NSString*)name{return_name;}-(void)setName:(NSString*)name{[_namerelease];_name=[nameretain];}@end

Using newer Objective-C 2.0 syntax as used in Mac OS X 10.6, iOS 4 and Xcode 3.2, generating the same code as described above:

@interfaceStudent : NSObject@property(nonatomic,retain)NSString*name;@end@implementationStudent@synthesizename=_name;@end

And starting with OS X 10.8 and iOS 6, while using Xcode 4.4 and up, syntax can be even simplified:

@interfaceStudent : NSObject@property(nonatomic,strong)NSString*name;@end@implementationStudent//Nothing goes here and it's OK.@end

Perl

packageStudent;subnew{bless{},shift;}subset_name{my$self=shift;$self->{name}=$_[0];}subget_name{my$self=shift;return$self->{name};}1;

Or, using Class::Accessor

packageStudent;usebaseqw(Class::Accessor);__PACKAGE__->follow_best_practice;Student->mk_accessors(qw(name));1;

Or, using the Moose Object System:

packageStudent;useMoose;# Moose uses the attribute name as the setter and getter, the reader and writer properties# allow us to override that and provide our own names, in this case get_name and set_namehas'name'=>(is=>'rw',isa=>'Str',reader=>'get_name',writer=>'set_name');1;

PHP

PHP defines the "magic methods" __getand__set for properties of objects. [9]

In this example of a simple class representing a student with only the name stored, one can see the variable name is private, i.e. only visible from the Student class, and the "setter" and "getter" is public, namely the getName() and setName('name') methods.

classStudent{privatestring$name;/**     * @return string The name.     */publicfunctiongetName():string{return$this->name;}/**     * @param string $newName The name to set.     */publicfunctionsetName(string$newName):void{$this->name=$newName;}}

Python

This example uses a Python class with one variable, a getter, and a setter.

classStudent:# Initializerdef__init__(self,name:str)->None:# An instance variable to hold the student's nameself._name=name# Getter method@propertydefname(self):returnself._name# Setter method@name.setterdefname(self,new_name):self._name=new_name
>>> bob=Student("Bob")>>> bob.nameBob>>> bob.name="Alice">>> bob.nameAlice>>> bob._name="Charlie"# bypass the setter>>> bob._name# bypass the getterCharlie

Racket

In Racket, the object system is a way to organize code that comes in addition to modules and units. As in the rest of the language, the object system has first-class values and lexical scope is used to control access to objects and methods.

#lang racket(definestudent%(classobject%(init-fieldname)(define/public(get-name)name)(define/public(set-name!new-name)(set!namenew-name))(super-new)))(defines(newstudent%[name"Alice"]))(sendsget-name); => "Alice"(sendsset-name!"Bob")(sendsget-name); => "Bob"

Struct definitions are an alternative way to define new types of values, with mutators being present when explicitly required:

#lang racket(structstudent(name)#:mutable)(defines(student"Alice"))(set-student-name!s"Bob")(student-names); => "Bob"

Ruby

In Ruby, individual accessor and mutator methods may be defined, or the metaprogramming constructs attr_reader or attr_accessor may be used both to declare a private variable in a class and to provide either read-only or read-write public access to it respectively.

Defining individual accessor and mutator methods creates space for pre-processing or validation of the data

classStudentdefname@nameenddefname=(value)@name=valueendend

Read-only simple public access to implied @name variable

classStudentattr_reader:nameend

Read-write simple public access to implied @name variable

classStudentattr_accessor:nameend

Rust

structStudent{name: String,}implStudent{fnname(&self)-> &String{&self.name}fnset_name(&mutself,name: String){self.name=name}}

Smalltalk

age:aNumber" Set the receiver age to be aNumber if is greater than 0 and less than 150 "     (aNumberbetween:0and:150)        ifTrue: [ age:=aNumber ] 

Swift

classStudent{privatevar_name:String=""varname:String{get{returnself._name}set{self._name=newValue}}}

Visual Basic .NET

This example illustrates the VB.NET idea of properties, which are used in classes. Similar to C#, there is an explicit use of the Get and Set methods.

PublicClassStudentPrivate_nameAsStringPublicPropertyName()GetReturn_nameEndGetSet(ByValvalue)_name=valueEndSetEndPropertyEndClass

In VB.NET 2010, Auto Implemented properties can be utilized to create a property without having to use the Get and Set syntax. Note that a hidden variable is created by the compiler, called _name, to correspond with the Property name. Using another variable within the class named _name would result in an error. Privileged access to the underlying variable is available from within the class.

PublicClassStudentPublicPropertynameAsStringEndClass

See also

Related Research Articles

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. It is one way to follow the open/closed principle.

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. It is a kind of lazy evaluation that refers specifically to the instantiation of objects or other resources.

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern as well as to the Open-Closed Principle, by allowing the functionality of a class to be extended without being modified. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.

In software design and engineering, the observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change, but the object's state appears unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

A method in object-oriented programming (OOP) is a procedure associated with a message and an object. An object consists of state data and behavior; these compose an interface, which specifies how the object may be utilized by any of its various consumers. A method is a behavior of an object parametrized by a consumer.

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. Function objects are often called functors.

In class-based, object-oriented programming, a constructor is a special type of function called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.

In computing based on the Java Platform, JavaBeans is a technology developed by Sun Microsystems and released in 1996, as part of JDK 1.1.

In object-oriented programming, a member variable is a variable that is associated with a specific object, and accessible for all its methods.

In some programming languages, const is a type qualifier that indicates that the data is read-only. While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in being part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking. In other languages, the data is not in a single memory location, but copied at compile time on each use. Languages which use it include C, C++, D, JavaScript, Julia, and Rust.

The uniform access principle of computer programming was put forth by Bertrand Meyer. It states "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation." This principle applies generally to the syntax of object-oriented programming languages. In simpler form, it states that there should be no syntactical difference between working with an attribute, pre-computed property, or method/query of an object.

In computer programming, a forward declaration is a declaration of an identifier for which the programmer has not yet given a complete definition.

A class in C++ is a user-defined type or data structure declared with keyword class that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class is private. The private members are not accessible outside the class; they can be accessed only through methods of the class. The public members form an interface to the class and are accessible outside the class.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

A property, in some object-oriented programming languages, is a special sort of class member, intermediate in functionality between a field 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, yet the interposition of method calls "under the hood" allows for data validation, active updating, or implementation of what may be called "read-only fields".

In computer science, a value object is a small object that represents a simple entity whose equality is not based on identity: i.e. two value objects are equal when they have the same value, not necessarily being the same object.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

In computer programming, a constant is a value that should not be altered by the program during normal execution, i.e., the value is constant. When associated with an identifier, a constant is said to be "named," although the terms "constant" and "named constant" are often used interchangeably. This is contrasted with a variable, which is an identifier with a value that can be changed during normal execution, i.e., the value is variable.

Objective-C is a high-level general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language. Originally developed by Brad Cox and Tom Love in the early 1980s, it was selected by NeXT for its NeXTSTEP operating system. Due to Apple macOS’s direct lineage from NeXTSTEP, Objective-C was the standard programming language used, supported, and promoted by Apple for developing macOS and iOS applications until the introduction of the Swift programming language in 2014.

References

  1. Stephen Fuqua (2009). "Automatic Properties in C# 3.0". Archived from the original on 2011-05-13. Retrieved 2009-10-19.
  2. Tim Lee (1998-07-13). "Run Time Efficiency of Accessor Functions".
  3. "CLHS: Macro DEFCLASS" . Retrieved 2011-03-29.
  4. "CLHS: 7.5.2 Accessing Slots" . Retrieved 2011-03-29.
  5. "MOP: Slot Definitions" . Retrieved 2011-03-29.
  6. "Functions - D Programming Language" . Retrieved 2013-01-13.{{cite web}}: CS1 maint: url-status (link)
  7. "The D Style" . Retrieved 2013-02-01.
  8. "Object.prototype.__defineGetter__() - JavaScript | MDN". developer.mozilla.org. Retrieved 2021-07-06.
  9. "PHP: Overloading - Manual". www.php.net. Retrieved 2021-07-06.