CSC/ECE 517 Fall 2009/wiki319 SV: Difference between revisions
Line 120: | Line 120: | ||
== '''Arguments supporting Uniform Access Principle''' == | == '''Arguments supporting Uniform Access Principle''' == | ||
In Object Oriented Programming where the programming is based on one of the principles “Encapsulation” which is to protect the integrity of the component during its external access. But most of the object-oriented programming languages provide the encapsulation feature through its getters and setters. In a programming language where an attribute is accessed through variable, the level to which the conversion from variable access to the method access depends on the support for Uniform Access Principle. In the languages which support this principle, the conversion from variable access to the method access can be achieved easily because of the principle ‘Uniform Access’. For instance, an accounting system has the Invoice class which provides the total value. The programmer has coded it in a way to store the total attribute as a separate attribute. Now to support the encapsulation, he tries to change it to method. In the accounting system, there are 15000 instances of total where to change from inv.total to inv.total() is difficult to implement. Hence with languages that provide the support for Uniform Access Principle, the change can be adapted easily. However in languages which does not support the UAP the mapping from variable access to method access can be done through getters and setters like getTotal() and setTotal(int). | In Object Oriented Programming where the programming is based on one of the principles “Encapsulation” which is to protect the integrity of the component during its external access. But most of the object-oriented programming languages provide the encapsulation feature through its getters and setters. In a programming language where an attribute is accessed through variable, the level to which the conversion from variable access to the method access depends on the support for Uniform Access Principle. In the languages which support this principle, the conversion from variable access to the method access can be achieved easily because of the principle ‘Uniform Access’. For instance, an accounting system has the Invoice class which provides the total value. The programmer has coded it in a way to store the total attribute as a separate attribute. Now to support the encapsulation, he tries to change it to method. In the accounting system, there are 15000 instances of total where to change from inv.total to inv.total() is difficult to implement. Hence with languages that provide the support for Uniform Access Principle, the change can be adapted easily. However in languages which does not support the UAP the mapping from variable access to method access can be done through getters and setters like getTotal() and setTotal(int). | ||
Below example shows how to convert from variable access to method access in the language (java) which does not support the Uniform Access Principle. | |||
class Invoice{ | class Invoice{ |
Revision as of 01:26, 19 November 2009
Problem Statement
"The principle that an access (read or write) to a feature of an object should be written the same whether the feature is an instance variable or method. Look at the current Wikipedia article on the subject and expand on it. Consider the reason for this principle and try to find countervailing arguments against it. If you do a good job, it could be submitted to Wikipedia. Since you are expanding on the current article, it is fine to lift text that is in the Wikipedia article right now."
Uniform Access Principle (UAP)
The Uniform Access Principle 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 object-oriented programming languages. In simpler form, it states that there should be no difference between working with an attribute, precomputed property, or method/query.
The Uniform Access principle simply means that if a module (the "client")is accessing a property managed by another module(the "supplier")it should not matter to the client whether the supplier keeps the property stored or computes it on demand.
Consider an example of a class Foo, and lets assume bar to be related to Foo. In a language like Java, if bar is an attribute, one would use foo.bar. If it were a function, we would use it as foo.bar(). Thus, in languages, that do not support Uniform Access Principle, the usage of bar would be different for cases when bar is an attribute or function. Due to these differences in the notational, there arises unwanted implementation details.
Also, there would be tight coupling to Foo, as when a change is made to bar from an attribute to a method, or the other way around, the the users of Foo must also be changed. The Uniform Access Principle seeks to eliminate this needless coupling. The languages that support the Uniform Access Principle do not have differences in their notations while accessing feature regardless of whether it is an attribute or a function. Thus, going with the above example, access to bar would always be in the form of foo.bar, regardless of how bar is implemented. The user or client need not bother if bar needs to be stored as an attribute or be computed on demand (function).This makes clients of Foo more resilient to change.
This example can be clearly understood below:
If a language allows access to a variable via dot-notation and assignment
Foo.bar = 5 //Assigns 5 to the object variable "bar"
then these operations should be the same :
//Assume print displays the variable passed to it, with or without parens //Assume Foo.bar = 5 for now print Foo.bar print Foo.bar()
Languages Supporting / Not Supporting Uniform Access Principle
Among Object Oriented languages, Eiffel, Ruby,Python, PHP support the Uniform Access Principle, although Smalltalk renders the distinction moot by not allowing any access to attributes from clients.
Ruby
Ruby blurs the line between names of variables and methods. The Uniform Access Principle is an excellent idea in a language where both variables and methods have to be declared and cannot overlap. But Ruby allows a symbol to identify both a variable and a method, and the disambiguation process is best described as eccentric.
class Foo attr_reader :x def initialize(x) @x = x end def squared_x return @x * @x end end y = Foo.new(2) puts y.x puts y.squared_x
This outputs
2 4
Note how even though x is an attribute and squared_x is a parameterless method call, they are accessed the same way.
Java
source: [[1]] public class Money { private double amount; public double getAmount() { return this.amount; } public void setAmount(double amount) { this.amount = amount; } }
In this example, we end up writing a lot of code to write just to define one single property, which is almost meaningless. But in Java we have to introduce getters and setters from the very beginning, or it will give problems in the future. It clearly contradicts with the DRY principle and discourages writing code that may be useless right now, but may (or may not) be needed in the future. In theory our methods should always have some meaningful behaviour, and our code should avoid trivial accessors in the public interface.
The syntax for accessing an attribute and calling a method in Java is completely different, and we can’t start with a simple public property and change it into a method later when it becomes necessary, keeping the public interface intact. So it is always advised not to use public properties and always define trivial accessors just in case.
Table showing languages that support/ don't support Uniform Access
Languages | Support for Uniform Access Principle |
Eiffel | Yes |
Smalltalk | N/A |
Ruby | Yes |
Java | No |
C# | No |
C++ | No |
Python | No |
Perl | No |
Visual Basic | Yes |
Most other languages, as well as UML, do not consider Uniform Access. They fundamentally distinguish between attributes (fields) and functions (methods). The result leads to a tricky situation. Although we can export an attribute, making [ATTRIB_ACCESS] valid if `price' is exported, this is not well accepted by most experts. This has two bad consequences. First, this is the case of putting a mechanism in a language and then discouraging people to use it. Second, people who follow the advice will have to rely on special functions whose only purpose is to return the value of the corresponding attributes. Instead of [ATTRIB_ACCESS], clients will write
(source: http://www.eiffel.com/general/column/2005/Sept_October.html) [FUNCTION_CALL] my_stock.get_price
which requires adding to STOCK a feature
(source: http://www.eiffel.com/general/column/2005/Sept_October.html) get_price: PRICE -- Return the value of `price' do Result := price end
or the equivalent in another language.
Such functions add to the noise, and make the code longer unnecessarily.
Arguments supporting Uniform Access Principle
In Object Oriented Programming where the programming is based on one of the principles “Encapsulation” which is to protect the integrity of the component during its external access. But most of the object-oriented programming languages provide the encapsulation feature through its getters and setters. In a programming language where an attribute is accessed through variable, the level to which the conversion from variable access to the method access depends on the support for Uniform Access Principle. In the languages which support this principle, the conversion from variable access to the method access can be achieved easily because of the principle ‘Uniform Access’. For instance, an accounting system has the Invoice class which provides the total value. The programmer has coded it in a way to store the total attribute as a separate attribute. Now to support the encapsulation, he tries to change it to method. In the accounting system, there are 15000 instances of total where to change from inv.total to inv.total() is difficult to implement. Hence with languages that provide the support for Uniform Access Principle, the change can be adapted easily. However in languages which does not support the UAP the mapping from variable access to method access can be done through getters and setters like getTotal() and setTotal(int).
Below example shows how to convert from variable access to method access in the language (java) which does not support the Uniform Access Principle.
class Invoice{ public int total; // Logic to compute total }
class Invoice{ private int total; public int getTotal(){ return total; } public int setTotal(int tot){ total = tot; } }
Problems with Uniform Access Principle
The Uniform Access Principle does not have a significant problem when not directly supported by the language syntax.
One potential drawback of Uniform Access is that it may hide the cost of calculation. If the calculation is expensive and/or time-consuming, but is disguised as a simple attribute, then one may risk excessively frequent accesses when a more appropriate treatment would be to copy it to a local memory variable. It would be difficult to tell the difference between what would otherwise be Game.SpectatorCount and Game.SpectatorCount()
[[2]]