In comp.lang.java.advocacy, Noah Roberts
<
[email protected]>
wrote
You just mention a difference right there in that sentance. In C++
primatives and objects act the same wrt value, pointer, and reference
semantics.
There are some languages that allow methods on primitives. Java,
sadly, is not one of them.
(Neither is C++.)
They may behave the same but there is no explicit distinction between
when they are there and when they are not...it is implicitly based on
type.
Might not be if it was true.
I believe the newest version of C now allows references. However,
I'd have to look.
Sure there is, if i is an object and not a primative. Did Java change
i or not?
int is not an object. Integer is not mutable and is final.
If one uses something like HashMap, however, all sorts of
silliness can ensue.
I don't know ... is there a way to implement the following signature in
Java? AFAIK there is not:
void foo(const I & i);
That function accepts a reference to an I object that cannot be changed
by foo without purposfully breaking the language's protections through
a const_cast. Callers can rely on the fact that i is not changed as
that definition is a statement to that effect.
There is no elegant method to enforce constness in
an *object*. One can declare a parameter final but all
that does is preclude assignment within the code to that
parameter variable; the object is still mutable.
Hence hacks such as Collections.unmodifiableMap(Map).
One can attempt cloning of an object that there are a number of
issues there too, not the least of which is performance.
Also, the following cannot be done in Java, although one can
emulate them to some extent.
A & operator = (A const &);
Assignment operator.
A(A const &);
C++ Copy constructor, guaranteed to be called whenever needed.
~A();
Destructor. One can implement the finalize() method but one
cannot forcibly delete an object without some work -- the best
I can do is a forced garbage collection.
void * operator new(size_t);
void operator delete(void *);
Java has "one size fits all" memory allocation, though internally
one might see various perturbations, depending on the information
available to the compiler. Presumably the JVM has the option of
allocating an object on stack (for objects that never get exported
therefrom), or on the heap. However, I'd have to look.
void * operator new[](size_t);
void operator delete[](void *);
Arrays of objects in Java are little more than arrays of pointers.
In fact,
A a[] = new A[10];
a[5] = null;
is perfectly legal in Java; C++ would generate a compile time error.
I think the closest you could come to that behavior is to create an
"unmutable" interface for I objects and accept that interface instead
of I and then implement it for I.
That is a choice, yes. I'd say that's one of the better methods,
especially if one wants to create a Swing Bean. In that case,
one creates three items:
- the interface containing get/set methods and maybe some constants
- the data bean, which is little more than get/set stuff
- the Swing form, which is also get/set but instead of storing
data it stores into the widgets
A fourth and fifth interface can be optionally added; the fourth
interface would implement only the get() methods, the fifth the set().
The original interface would derive from *both* of them (Java allows
multiple inheritance of interfaces, as there's no "diamond problem").
A seventh object can be added for translation from and to a
recognized format, such as XML or JDBC, or one can split this
particular item into two pieces. Or one can use java.io.Serializable
or java.io.Externalizable.
At some point, one starts to get into overengineering territory.
Of course this has to be done for
every different type of object you want to do this with...C++ contains
this interface within the class definition through the form of const
operations...a simple keyword that you place on functions that do not
alter the internals of the object...and the language won't let you do
it either unless you explicitly ask it to through casts or the mutable
keyword.
Const can turn into a bit of a mess (mostly because if one
changes a parameter from (A &) to (A const &) in a routine
declaration, implementations tend to propagate the change
down) but at least it's allowed, and in fact in two places,
in C++:
A * p; // movable pointer to changeable value
A * const p; // fixed pointer to changeable value
const A * p; // movable pointer to unchangeable value
const A * const p; // fixed pointer to unchangeable value
Casting such as (A *) p is also possible but frowned upon;
one can also do const_cast<A *>(p), which is a little
easier to search for. The syntax can get a little ugly;
in fact, there's a utility for translating English-like
declarations to the C soup of (), [], and *.
In Java, one has four bad choices, if one is using a Map
or Set (for other classes, only the first is known to
be available; the second should work for Cloneable objects,
which fortunately includes HashMap and TreeMap -- beware,
however, as clone() is *protected*):
Map p = ...;
final Map q = p; // q cannot be assigned to but all
// methods such as q.put("a","b") are legal
final Map q = (Map) q.clone(); // q is a duplicate of p
final Map q = new TreeMap(p); // q is a duplicate of p,
// and not all classes support this sort of constructor
final Map q = Collections.unmodifiableMap(p); // q cannot
// be assigned to and q.put("a","b") throws an
// UnsupportedOperationException at runtime.
You can only do that if you have control over the I object and can
cause it to 'implement' an interface. Since your language doesn't
provide the idea of const as part of the language it isn't standard to
find interfaces implemented in those terms...in C++ it is. Either way
you have good vs. bad code and in the end can get the same thing done,
but C++ offers a little better way of doing it.
And off course interfaces are just a piss poor replacement for multiple
inheritance
I don't particularly care for multiple inheritance, mostly because
of the "diamond problem". However, it can be useful, when
carefully managed. I prefer Java's solution here.
Also,
void foo(I i);
Is I changed? Certainly not in C++ where i is passed by _value_ no
matter what type it is...in Java you can't tell...someone may have
called a mutable function on it. In Java if i is an int it is copied
and the original is not changed...but if i is an object then maybe it
is, and maybe it isn't...you can't know from the signature alone.
Actually, one can, if the signature includes parameter types. Java's
blot, of course, is that int != Integer; the former is passed by value,
the latter by reference. (Of course for int and Integer it's a poor
example, since no one can modify an Integer anyway. However, other
classes, such as HashMap, are easily modified.)
It is certainly not hidden and that was a sample only.
The side effects problem is prevalent in both languages.