Java Forum / General / December 2005
java final vs. c++ const
Nan Li - 01 Dec 2005 15:32 GMT Hello, In C++, when you say const A* p, it means the object that p points to is a constant, while A* const p means p is a constant. I have noticed in Java, 'final A p' is equivalent to the second form in C++, where p is not reassignable. Does any one know if there is a way to achieve the first form in java ? Thanks a lot.
Sample programs:
//ConstantTest.java class A { public int i; }
public class ConstantTest {
public static void main( String[] args ) { final A a = new A(); a.i = 5; a = new A(); //not OK } } -------------------------------- //ConstantTest.cpp //there is mem leak in the code, demo only.
class A { public: int i; };
int main() { A* const a = new A(); const A* ya = new A(); a->i = 5; a = new A(); //not OK ya->i = 5; //not OK ya = new A(); return 0; }
Oliver Wong - 01 Dec 2005 15:41 GMT > Hello, > In C++, when you say const A* p, it means the object that p [quoted text clipped - 38 lines] > return 0; > } Don't know much about C++, but from your example, it seems like "const A* ya" is syntactic sugar for marking all of the member fields as final. You can achieve that in Java like this:
<wontCompile> class A { final public int i; } </wontCompile>
But if you do that, you need to make sure that i gets initialized somehow; e.g., via a constructor:
<betterCode> class A { final public int i;
public A(int initialValueForI) { this.i = initialValueForI; } } </betterCode>
- Oliver
Nan Li - 01 Dec 2005 16:10 GMT > > Hello, > > In C++, when you say const A* p, it means the object that p [quoted text clipped - 63 lines] > > - Oliver Making data members final is not quite the same as declaring object constant in C++. With the first approach, class designer forces the constness, while the second one the users of the class have freedom to decide whether it should be const or not.
Leroy42 - 01 Dec 2005 16:40 GMT You cannot do this in Java :-(
Starting programming in Java, I first missed this construct, but you can live without it.
Hovewer if you want to assure that the compiler forbids you when ANY method changes the contents of an instance when the method isn't allowed you can use a "dirty workaround".
1. Declare all members of the class private or protected. 2. Define an Interface with similar name that ONLY defines those methods that don't changes the "contents" of an instance. 3. Tell your original class to implement this interface. 4. Use the interface instead of the original class for local vars or parameters if you want to have them "const"
Example:
public class Const { public static void main(String[] args) { Klasse k = new Klasse(); normal(k); konst(k); }
static void normal(Klasse k) { k.set(-42); k.negate(); System.out.println(k.get()); }
static void konst(KlasseC kC) { kC.set(-42); // Compile-Error kC.negate(); // Compile-Error System.out.println(kC.get()); // OK } }
interface KlasseC { public int get(); } class Klasse implements KlasseC { protected int i;
public void set(int i) {this.i = i;} public int get() {return i;} public void negate() {i = -i;} }
But this is only a "dirty" solution. If one of the "get"-methods of your methods return an object itself, this wan't work in "deep"
Leroy42
Chris Smith - 01 Dec 2005 17:12 GMT > In C++, when you say const A* p, it means the object that p > points to is a constant, while A* const p means p is a constant. I > have noticed in Java, 'final A p' is equivalent to the second form in > C++, where p is not reassignable. Does any one know if there is a way > to achieve the first form in java ? No.
There are, however, various patterns and idioms for handling the requirement. These include:
1. The simplest way to make on object "constant" is to only give out copies of the object. That way, the other side can modify their private copy all they like, without having any impact on program correctness. There are obvious performance costs.
2. The other option is to use a single object, but arrange for different interfaces to that object based on const-ness. This requires that you separate the exposed API of the object into interfaces in the first place. There are three variations:
* Variation 2a: "False Unmodifiability"
Here, you define two interfaces and a class.
public interface UnmodifiableValue { public String getName(); }
public interface Value extends UnmodifiableValue { public void setName(String name); }
public class ValueImpl implements Value { ... }
You can then pass around references of type Value or UnmodifiableValue. It's "false" because a simple cast would allow someone to treat an unmodifiable value as modifiable. Of course, the same is true of const-ness in C++, where const_cast<T> can be used to accomplish this goal. This is, in fact, the closest thing Java has to C's const when applied to objects.
* Variation 2b: "Optional Operations"
Here, you write an adapter that just throws exceptions from some operations. This is poor OO design, but nevertheless is sometimes used when simplicity is valued above correctness of the exposed interface.
public interface Value { public String getName(); public void setName(String name); }
public class ValueImpl implements Value { ... }
// and a method somewhere static Value unmodifiableValue(final Value base) { return new Value() { public void setName(String name) { throw new UnsupportedOperationException(); }
public String getName() { return base.getName(); }
}; }
This is used in the Collections API, for example.
Variation 2c. "Interface Adapter"
This is a combination of the previous two. 2a provide compile-time const-ness. 2b provides runtime const-ness. This provides both.
public interface UnmodifiableValue { public String getName(); }
public interface Value extends UnmodifiableValue { public void setName(String name); }
public class ValueImpl implements Value { ... }
// and a method somewhere static UnmodifiableValue unmodifiableValue(final Value base) { return new Value() { public String getName() { return base.getName(); }
}; }
Hopefully, one of the above will meet your needs.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Oliver Wong - 01 Dec 2005 18:22 GMT > Variation 2c. "Interface Adapter" > [quoted text clipped - 24 lines] > }; > } I personally don't like the idea that a modifiable value extends an unmodifiable value. Suppose the client code receives something which they assume is unmodifiable and uses it as the key of a HashMap, for example?
I prefer a 3-class design, like the following:
<code> abstract class Value { public String getName(); }
class UnmodifiableValue extends Value {
final private String name;
public UnmodifiableValue(String name) { this.name = name; }
public UnmodifiableValue(Value v) { this.name = v.getName(); }
@Override public String getName() { return this.name; } }
class ModifiableValue extends Value { private String name;
public ModifiableValue(Value v) { this.name = v.getName(); }
@Override public String getName() { return this.name; }
public void setName(String name) { this.name = name; } } </code>
Note the "copy-constructors" that allow you to create an equivalent ModifiableValue given an UnmodifiableValue and vice versa.
- Oliver
AndyRB - 01 Dec 2005 18:51 GMT ...
> You can then pass around references of type Value or UnmodifiableValue. > It's "false" because a simple cast would allow someone to treat an > unmodifiable value as modifiable. Of course, the same is true of > const-ness in C++, where const_cast<T> can be used to accomplish this > goal. If the goal is simply "to treat an unmodifiable value as modifiable" then yes you are right. However, if the goal is for the program to retain well-defined semantics and not produce some random output as well as to treat an unmodifiable value as modifiable, const_cast will only accomplish that particular goal in a couple of specific circumstances.
C++ often allows you to lie to the compiler and at that point...you're on your own!
Chris Smith - 01 Dec 2005 19:29 GMT > ... > > You can then pass around references of type Value or UnmodifiableValue. [quoted text clipped - 9 lines] > only accomplish that particular goal in a couple of specific > circumstances. Care to explain? In what contexts (aside from String literals and static or global const values) would const_cast<T> produce undefined results when used to cast away const-ness of the target of a pointer?
I'm really asking... I don't know the C++ spec well enough to answer, and it's unfortunately no publicly available.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
AndyRB - 01 Dec 2005 22:19 GMT > > ... > > > You can then pass around references of type Value or UnmodifiableValue. [quoted text clipped - 13 lines] > static or global const values) would const_cast<T> produce undefined > results when used to cast away const-ness of the target of a pointer? Well technically it is not the const_cast itself which invokes undefined beahviour, but any subsequent attempt to modify *any* const object through the pointer.
void foo(const int * cp) { int * p = const_cast<int*>(cp); // cast required
*p = 4; // undefined if the underlying object is a const object }
int main() { const int ci = 3; int i = 2; foo(&i);//cast and assignment in foo OK, //underlying object is not const. foo(&ci);//cast OK subsequent assignment in foo not OK, //underlying object is still const. }
The code in foo is therefore unsafe, as you have no way of ensuring that the int which cp points to is really non-const.
> I'm really asking... I don't know the C++ spec well enough to answer, > and it's unfortunately no publicly available. [quoted text clipped - 5 lines] > Chris Smith - Lead Software Developer/Technical Trainer > MindIQ Corporation Chris Smith - 01 Dec 2005 23:34 GMT > Well technically it is not the const_cast itself which invokes > undefined beahviour, but any subsequent attempt to modify *any* const > object through the pointer. Ah, now I understand. Does this also apply to const instance fields of non-const objects?
In any case, the point is the same regarding my original post... except that the C++ code is slightly less statically safe in that its behavior is completely undefined, while a similar Java application may still obtain defined behavior but would be unable to exhibit *sensible* behavior since the assumptions of the remaining application are broken.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
AndyRB - 02 Dec 2005 10:09 GMT > > Well technically it is not the const_cast itself which invokes > > undefined beahviour, but any subsequent attempt to modify *any* const > > object through the pointer. > > Ah, now I understand. Does this also apply to const instance fields of > non-const objects? Yes, if the data member is defined as const then it cannot be safely modified.
> In any case, the point is the same regarding my original post... except > that the C++ code is slightly less statically safe in that its behavior > is completely undefined, while a similar Java application may still > obtain defined behavior but would be unable to exhibit *sensible* > behavior since the assumptions of the remaining application are broken. I would largely agree with that. In c++ it is an example of by-passing the type system, something that you can't do in Java, but is necessary in c++ in order to be able to write certain low-level code.
> -- > www.designacourse.com > The Easiest Way To Train Anyone... Anywhere. > > Chris Smith - Lead Software Developer/Technical Trainer > MindIQ Corporation Luc The Perverse - 02 Dec 2005 10:49 GMT > I would largely agree with that. > In c++ it is an example of by-passing the type system, something that > you can't do in Java, but is necessary in c++ in order to be able to > write certain low-level code. Being able to receive a copy of an object without any additional help is probably a huge inefficiency in C++ - since the overhead of creating a copy is high.
But I do miss it a little.
I would say though - it's not a reason not to use Java.
I've never considered it "necessary" though. You can make a copy of an object in Java if you want to, you just have to do it explicitly by creating a new object (same as C++ does transparently). What low level code are you refering to?
-- LTP
:) AndyRB - 03 Dec 2005 11:59 GMT > > I would largely agree with that. > > In c++ it is an example of by-passing the type system, something that > > you can't do in Java, but is necessary in c++ in order to be able to > > write certain low-level code. My post was refering to casting not copying but...
> Being able to receive a copy of an object without any additional help is > probably a huge inefficiency in C++ - since the overhead of creating a copy > is high. It is generally very inefficient if the object is large and particularily if it contains a dynamically allocated buffer. For other User defined types it is generally less efficient, how much largely depends on the compiler, a good optimiser may be able to optimise out many copies.
> But I do miss it a little. not being able to do the equivalent of - foo(const &object) - please ignore the reference (I'm not refering to pass-by-reference here) seems far more important to Java...
> I would say though - it's not a reason not to use Java. I don't think this kind of copying (using value semantics) is even relevant to Java objects, as they are always polymorphic.
> I've never considered it "necessary" though. You can make a copy of an > object in Java if you want to, you just have to do it explicitly by creating > a new object (same as C++ does transparently). If you are dealing with polymorphic objects in c++, you would use a similar cloning technique so that you get reference sematics. Value semantics and polymorphic objects generally don't mix, remember in c++ the default object is a non-polymorphic (no inheritance, member functions non-virtual by default) and it is for these objects that the kind of copying in c++ you are refering to makes sense.
>What low level code are you > refering to? I was refering to using casting to bypass the type system (specifically with reinterpret_cast in mind), i.e. dealing with raw memory that has to be reinterpreted as different data types.
> -- > LTP > > :) Roedy Green - 01 Dec 2005 18:37 GMT >In C++, when you say const A* p, it means the object that p >points to is a constant, while A* const p means p is a constant. I >have noticed in Java, 'final A p' is equivalent to the second form in >C++, where p is not reassignable. Does any one know if there is a way >to achieve the first form in java ? Thanks a lot. the closest to that is as immutable object. The next best thing is an interface-style reference to an object with no mutating methods.
There are several others tricks.
see http://mindprod.com/jgloss/immutable.html
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|