Duplicate :
|
|
Duplicate :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
Name: igT44549 Date: 02/11/99 I think Java would be a much safer language if it would support const parameters like C++. For instance: class Example { void func1(MyObject const myObject) { myObject.const_methods_only(); } } If a non-const method were called, the compiler would flag it as an error. Right now it is impossible to know if a method you call might modify the class you pass it. This would be something that the compiler can find easily, but is extremely difficult for a programmer to know until after the code has been found defective by a customer. I think adding const to the language would greatly improve the Java language in terms of how bug free Java programs would be. You already did a great job of elimating memory bugs, why not take it one step farther and help eliminate other bugs by supporting const parameters (and methods). (Review ID: 52919) ====================================================================== Name: jl125535 Date: 01/04/2002 FULL PRODUCT VERSION : java version "1.3.1" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24) Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode) FULL OPERATING SYSTEM VERSION : Windows 2000 5.00.2195 Service Pack 2 ADDITIONAL OPERATING SYSTEMS : (All others) A DESCRIPTION OF THE PROBLEM : Related bugs: 4211070, 4093718, 4069541. A COMPREHENSIVE THEORY OF ADDING 'CONST' TO JAVA [This document is also available at <http://david.tribble.com/text/javaconst.html>.] CONCEPTS A reference variable or constant declared as 'final' has a value that is immutable and cannot be modified to refer to any other object than the one it was initialized to refer to. Thus the 'final' specifier applies to the value of the variable itself, and not to the object referenced by the variable. A reference variable or constant declared as 'const' refers to an immutable object that cannot be modified. The reference variable itself can be modified (if it is not declared 'final'). Thus the 'const' specifier applies to the value of the object referenced by the variable. An object is modified whenever any of its accessible member variables are the subject of an assigment (or compound assignment) or increment/decrement operator. An object is also considered modified whenever a call is made to any of its member methods that are not declared 'const' (see below). CLASS VARIABLES Only reference (non-primitive) types can have the 'const' specifier applied to them. Primitive types that need to be declared 'const' should be declared 'final' instead. A member variable declared 'const' and declared with a reference type (i.e., any class type extending 'Object' or any interface type), or declared as an array of any type, refers to an immutable object whose value cannot be modified. The reference variable itself can be modified, provided that it is not declared 'final'. The following code fragment illustrates these rules: class Foo { int max = 100; final int LENGTH = 80; const int GREAT = 15; // Error final const int LEAST = 2; // Error Bar b = new Bar(17); final Bar bf = new Bar(23); const Bar bc = new Bar(55); final const Bar bfc = new Bar(79); } The member variable 'max' is modifiable. The member constant 'LENGTH' is not modifiable (because it is 'final'). The member variable 'b' is modifiable, and refers to an object that is modifiable. The member constant 'bf' is not modifiable (because it is 'final'), but the object to which it refers is modifiable. The member constant 'bc' is modifiable, but the object to which it refers is not modifiable (because it is 'const'). The member constant 'bf' is not modifiable (because it is 'final'), and the object to which it refers is not modifiable (because it is 'const'). ASSIGMENT EXPRESSIONS Expressions of reference type, either const or non-const, can be freely assigned to const variables of compatible reference types, and can be freely passed to methods as const arguments of compatible reference types. Expressions of const reference type can only be assigned to const variables, or passed as const arguments to methods, of compatible reference types. An expression of const reference type cannot be cast to a compatible non-const (see the Cast Expressions section below). Consider the following code fragment: class Foosball extends Bar { const Bar bc; Foosball fb; const Foosball fc; void enconst1(Foosball f) { bc = f; // Okay, implicit cast fb = f; // Okay fc = f; // Okay, implicit cast } void enconst2(const Foosball f) { bc = f; // Okay, implicit cast fb = f; // Error, f is const fc = f; // Okay } } INTERFACE CONSTANTS Since all member variables of interfaces must be declared 'final', all such member variables are actually constants. In all other respects, the rules for const member constants are the same as for const class member variables. Consider the following code fragment: interface Baz { static final Bar bf = new Bar(1); static const Bar bc = new Bar(2); static final const Bar bfc = new Bar(3); } Member methods of classes that implement interface 'Baz' cannot modify any of the three constants 'bf', 'bc', or 'bfc' (because they are final). Such methods are allowed to modify the Bar object referenced by 'bf', but cannot modify the objects referenced by 'bc' or 'bfc' (because they are const). CLASS METHODS Static member methods declared 'const' cannot modify any static class variables of their parent class. They also cannot modify any objects referenced by any static class reference variables of their parent class. Non-static member methods declared 'const' may not modify any member variables (static or not) of their parent class object ('this'). They also cannot modify any objects referenced by any class reference variables (static or not) of their parent class. A method declared 'const' declares that it cannot modify any member variables of its class, nor any objects referenced by those variables. Conversely, a method that is not declared 'const' declares that it may modify member variables of its class or objects referenced by them (and should be assumed to do so, whether it actually does or not). The following code fragment illustrates these rules (it is assumed that 'Bar.peek()' is a const method and 'Bar.poke()' is not): class Foomy { static Bar bs = new Bar(15); Bar b = new Bar(34); const Bar b2 = new Bar(53); void frob() // Not const { bs = new Bar(48); // Okay b = new Bar(81); // Okay frotz(); // Okay b.poke(13); // Okay b.peek(); // Okay b2.poke(13); // Error b2.peek(); // Okay } void fraz() const // Is const { bs = new Bar(48); // Error b = new Bar(81); // Error frotz(); // Error b.poke(13); // Error b.peek(); // Okay b2.poke(13); // Error b2.peek(); // Okay } void frotz() // Not const { ... } } Member method 'frob()' is not declared 'const', so it can modify any non-const member variables of class 'Foomy'. It cannot modify any const member variables, though, such as 'b2'. Member method 'fraz()' is declared 'const', so it cannot modify any member variables of class 'Foomy'. It also cannot indirectly modify any member of the class by calling non-const member methods, such as 'frotz()'. It also cannot indirectly modify any member by calling non-const methods on those members, such as 'b.poke()' (which is not declared 'const' in this example). Member method 'frotz()' is not declared 'const', so it must be assumed to modify member variables of class 'Foomy'. A non-static member method of a class that extends another class or implements an interface which overrides a method of the base class or implements a method of the interface must be declared with a "const-ness" that is at least as restrictive as the method it overrides. In other words, if a method in a base class is declared 'const', then all subclass methods that override that method must also be declared 'const'; on the other hand, an overriding method may be declared 'const' even if the method it overrides is not declared 'const'. (In this respect, 'const' specifiers are similar to 'throws' clauses.) The following code fragment illustrates these rules: class Foomier extends Foomy { void frob() const // Added const { ... } void fraz() const // Must be const { ... } } class Foomiest extends Foomy { void fraz() // Error, Must be const { ... } } LOCAL VARIABLES Variables local to a method body may be declared 'const', in which case the objects they refer to cannot be modified. The reference variables themselves can be modified provided they are not declared 'final'. Consider the following code fragment: void f() { Object o = new Object(); final Object fo = new Object(); const Object co = new Object(); final const Object fco = new Object(); ... } The object referenced by 'o' can be modified, and variable 'o' can be modified to refer to a different object. The object referenced by 'fo' can be modified, but variable 'fo' cannot be modified to refer to any other object (because it is 'final'). The object referenced by 'co' cannot be modified (because it is const), but variable 'co' can be modified to refer to another object. The object referenced by 'fco' cannot be modified (because it is const), and variable 'fco' cannot be modified to refer to another object (because it is 'final'). METHOD PARAMETERS The same rules apply to method parameters as to local variables. That is, a reference parameter declared 'final' cannot be modified, but the object which it references can be modified. A reference parameter declared 'const' can be modified, but the object which it references cannot be modified. CAST EXPRESSIONS A reference variable declared 'const' cannot be cast to its equivalent non-const type. Such casting would remove the "const-ness" of the object referred to, and thereby violate const type safety. Conversely, a reference variable may be implictly cast to its equivalent const type (by assignment or by passing it as an argument to a method), which adds "const-ness" to the resulting reference expression. There is no syntax for an explicit such cast, since assigning a const or non-const reference expression to a const variable does not require an explicit cast. Consider the following code fragment: class Fooberry { const Bar bc; const Bar enconst(Bar b) { bc = b; // Okay return b; // Okay } const Bar addconst(Bar b) { bc = (const Bar) b; // Error return (const Bar) b; // Error } } METHOD RETURN VALUES Methods may return non-primitive const object types, which means that the values returned by such methods cannot be modified (but that references to such objects can be assigned and passed to other methods). This implies that the return value of a method declared as returning a const type can be assigned to only a const reference variable or passed as an argument to a method taking a const reference parameter. Consider the following code fragment: class Foodor { Bar getBar() { ... } const Bar cBar() { return new Bar(); // Okay } void f() { Bar b; const Bar bc; b = getBar(); // Okay bc = getBar(); // Okay b = cBar(); // Error bc = cBar(); // Okay } } CONCLUSION Adding the 'const' specifier keyword to Java would bring new forms of type safety to the language, and simplify the semantics of "read-only" objects. This bug can be reproduced always. CUSTOMER WORKAROUND : Splitting classes into "read-only" and "writable" interfaces, which is a real pain, especially in a language without multiple inheritance. (Review ID: 137795) ======================================================================
|