|
Comments
|
Submitted On 31-AUG-1999
andythomascramer
Yes, yes, yes, for efficient large-scale development we need const parameters,
const methods, const return instances, and const members -- for instances of
user-defined types as well as primitive types.
Java currently only supports a small subset of const-correctness checking:
const primitive types and constant references to non-const user-defined types.
Const-correctness checking is similar in importance and concept to
type-checking. Just as the lack of strong type-checking in some other languages
increases costs, so does the lack of const-checking in Java.
We are <em>not</em> seeking a run-time check of constness, just a
compile-time check of a const qualifier to type.
The workarounds suggested by Sun and others (copying, immutable classes,
subclassing from an immutable interface, and wrapping with an immutable class)
all increase development, maintenance and/or performance costs, and aren't
always feasible.
Yes, const is implemented in C++ syntax, but the concept of const is generic
to language.
The longer const is withheld from the language, the larger the body of
const-incorrect legacy code that's being generated. Please fix it as soon as
possible.
Submitted On 09-OCT-1999
Zoso
Design By Contract features allow for much safer programming, which has been a
Java goal. Any support that the language can provide makes DBC much more
practical, since support by convention requires a higher degree of developer
knowledge and skill as well as more development effort. The ability to specify
C++-like const features would move closer to supporting DBC in Java by allowing
a more complete contract definition for method declarations. I would also
suggest looking into other DBC features like pre- & post-conditions and
invariants. See the Eiffel language implentation for other ideas.
Submitted On 21-OCT-1999
sonstone
I have a need for this type of functionality when it comes to object
inspection. It
would be nice to look at a java bean's getter methods and automatically call
the
get methods to know what these values return, but there is no way that I can
tell
if the get method will modify the state of the object. I think this feature
would help
out significally when using dynamic method calls and the such.
Submitted On 18-NOV-1999
billrobertson
It has been pointed out that immutable super interfaces are a good work around.
It has also been pointed out that that can not be used all of the time. In
addtion, that amounts to more work for the developers.
The key here is that Java does not properly support const correctness, and that
amounts to a lot of extra work for the users of the language. More work spent
either adding and passing around immutable interfaces, or more work spent
debugging because someone unknowingly diddled with an object that (s)he
shouldn't have.
Java needs proper support for const correctness. Const object references and
const methods do a good job at that IMHO.
Vote for this RFE. :)
Submitted On 15-DEC-1999
aleclee
I'm a fan of const correctness too, but then you need a mechanism like the
"mutable" keyword in C++ to notify the compiler of member data that
may be modified without violating the spirit of const.
Submitted On 17-DEC-1999
sdempsey
One vote from me. Use const to mark an object as immutable & to mark
methods
as non-mutating. (I know there are design patterns for using immutable
interfaces
but these are clunky). Note that Java itself "cheats" and stipulates
String
as being const.
Having confusing C++ syntax isn't a problem because
there's already a "final" keyword with a different meaning.
Submitted On 17-JAN-2000
schapel
Note that if this feature were implemented in Java like it is in C++, that it
would tell the
compiler that it may not modify an object *through a const reference*. It would
*not*
tell the compiler that an object itself is const. For example, if there were
one const and
one non-const reference to the same object, we could not modify the object by
using the
const reference, but we *could* modify the object through the non-const
reference.
In C and C++ I used pointers to const objects often, and if this feature were
added to
Java, I think it would help me produce code that documents itself better and
that would
tend to have fewer bugs.
Submitted On 20-JAN-2000
derbyshire16
I agree. Const correctness should be supported. Add the const keyword -- use
final on reference types as is, to indicate they can't be re-pointed at new
referents, and make final and const synonymous on primitives. Const on objects
would restrict to invoking const methods only and not modifying ivars except if
these were flagged mutable. Const on instance methods would indicate they don't
modify the underlying object. Const on a class would assert that the pbjects
were immutable -- same as const on its non-constructor methods and non-private
ivars. There'd be a mutable keyword for cached or transient data to be flagged
as such -- stuff that is computed or transient and doesn't affect the object's
identity or API, just its performance, e.g. caching a matrix inverse with the
matrix but lazily computing it only when it is desired.
Submitted On 25-JAN-2000
andythomascramer
The desired enhancement is not a particular
keyword or syntax, but increased const semantics.
Used for const methods, interfaces:
- Are an incomplete workaround using
type-checking in place of const-checking.
- Double the complexity of the class model.
- Don't support static consistency checking by
the compiler of const method
implementation.
- May decrease performance by preventing
optimization of "final" methods on const
references.
- Don't support const arrays. (Ask me about
caching an array of 40,000 doubles ...).
- Increase the code base.
- Increase development and maintenance effort.
- Aren't used in practice, even by Sun.
Submitted On 26-JAN-2000
brettporter
Yes, I would like const parameters and methods. I don't know how many times I
mess up classes or arrays by forgetting to make copies.
Submitted On 26-FEB-2000
jonathanfinn
schapel is right - the semantics of const needs very
careful thought before adding it to the language. e.g.
consider a function
static void add(Matrix a, const Matrix b) {...}
// adds b to a, leaving b unchanged
We then invoke it somewhere like this:
add(x,y); // y unchanged
But in one case y has in fact changed, because x and y
refer to the same object. The C++ const semantics are easy
to implement but not very useful - it's fairly useless to
know that add() can't change y directly if it can change it
indirectly! So C++-style const can only protect you against
some types of const bug.
Submitted On 28-FEB-2000
andythomascramer
static void add(Matrix a, const Matrix b) {...}
// adds b to a, leaving b unchanged
On the contrary, it's very useful to know, from the
standpoint of someone calling this method, that an object
can't be modified ***through the pointer passed to the
formal b argument***. In the usual case of a call to add
(x,y), where x and y point to different, independent
objects, the caller knows that the physical object pointed
to by y can't be modified by the method through y. In the
case of a call to add(x,x), the caller knows that the
object may be modified, because it's passed through the non-
const pointer.
Submitted On 01-MAR-2000
dkf
The above example illustrates just why const is *not*
enough, since what you (or at least I) would like instead is
to state that the second argument is not modified and must
never be the same as the first argument, and this
restriction is not enforced by the use of const. Instead,
it would be better to have Eiffel-like pre/post conditions
and invariants., and since these would form part of the
contract entered into by the class or method, this would be
far easier to maintain.
Plus, it is all to easy to get swamped under "const creep"
in C++ so not having any of that stuff is refreshing in
Java!
(Also, what about immutable objects? etc.)
Submitted On 02-MAR-2000
andythomascramer
Pre/post conditions and invariants would _also_ be nice.
However, const type qualifiers are easily checked at
compile time and suffer little, if any, runtime costs. And
they can be used in more general situations than method
calls (e.g., an instance can store a const pointer). Both
const type qualifiers and method invariants have their
advantages, and neither precludes the other.
And no, what I would like is not necessary a guarantee of
invariance during a method call, but rather a restriction
against variance _ever_ through a const pointer provided to
any object or method. If I provide _any_ non-const pointers
to the same object, I know that the object can be modified.
Submitted On 18-MAR-2000
Ixchel
Another issue related to 'const' that I haven't seen
anybody mention yet:
The "Simple Assertion Facility" proposal (#JSR-000041,
currently underway in the Sun Community Process) proposes
the addition of an 'assert' keyword which can be used to
check various conditions that a software engineer thought
would be true, like so:
assert <boolean-expression>;
However, these checks are not supposed to have side effects
on the state of the program, since asserts can
be 'disabled' which would cause their expressions to not be
evaluated. Unfortunately, however, there is currently no
way to enforce a lack of side effects in Java. Why? Because
someone could write code that looks like this:
assert anObject.someFunction(anotherObject) > 5;
and the someFunction method could modify either anObject or
anotherObject, which would cause the assert statement to
have different behavior depending on whether or not asserts
were enabled.
Now, if const-correctness were instituted in the language,
we could define 'assert' like so:
assert <const-boolean-expression>;
where const-boolean-expression was an expression which had
the following limitations:
1) No side effect operators (+=, ++, --, =, etc.) were
allowed.
2) Only 'const' methods taking only 'const' or pass-by-
value parameters could be invoked.
This would eliminate the possibility of someone
creating 'assert' statements that had side-effects (or at
least would force them to cast-away-const to do it), and
would substantially reduce the probability of bugs
introduced due to 'assert'.
Submitted On 21-MAR-2000
Derek Foster
As another issue to consider: When arrays are being
returned from methods, it is common practice to make copies
of them (via clone()) to return, like this:
private final int [] myPrivateArray = ???;
int [] aMethodReturningAnArray()
{
return (int [])myPrivateArray.clone();
}
This extra copy is done just to make sure that the caller
of the method doesn't screw up the object that the method's
data is called on (by modifying the returned array, and
hence modifying the object's private data).
With const arrays, this extra copy could be eliminated
(since the caller couldn't modify the array), resulting in
more efficient code. The result would look like this:
private const int const [] myPrivateArray = ???;
int const [] aMethodReturningAnArray()
{
return myPrivateArray;
}
Incidentally, I am not particularly enamored of the 'const'
keyword, because it seems to imply to me that something
will be truly constant (unchanging over time), rather than
just constant with respect to a particular reference to it
which is declared 'const'. I'd rather it were called
something else that carried implications of "You can't
modify it through me".
Also incidentally, what syntax should be used? I don't like
C++'s syntax (too vague: Most people don't know the
difference between "const int *" and "int const *" and "int
* const") I suggest that it consistently be prefixed to the
particular item it is to apply to, so declarations can be
read left-to-right:
const Thing [] x; // array of constant Things
Thing const [] x; // constant array of non-constant Things
final Thing [] x; // fixed reference to non-constant
array of non-constant Things
final const Thing const [] x; // fixed reference to
constant array of constant Things
It might be helpful (less typing) to use some kind of piece
of punctuation (e.g. @, #, or such) instead of a 'const'
keyword for this. Otherwise, declarations can get rather
long and unwieldy.
Submitted On 29-MAR-2000
abies
const Thing [] x; // array of constant Things
Thing const [] x; // constant array of non-constant
Things
I know that it is done in such way in C++, but I would hate
to see it in java.
It is way too puzzling for beginners and even for more
experienced programmer it requires a moment of thinking
instead of just 'look-and-know' which is true for most java
constructs.
Note that this only affects arrays - in all other cases
there is no reason
for having two positions for const, given 'final' keyword.
It also does not
cope fully with java multidimensional arrays - const
int[][][] const const x; ??
I would suggest forgetting about having constant arrays and
stick just to
arrays pointing to const objects. Why ? You can easily do
constant array
by wrapping it into constant Vector/ArrayList, but you are
unable to to do
the ArrayList returning constant Objects.
And this gives second problem - I suppose that there would
have to be
number of collection classes, like ConstCollection,
ConstIterator etc +
corresponding methods in all classes (constantIterator()
etc). Unfrotunately it would require doubling a some other
methods like addAll(Collection). It would be best if addAll
could work both on Collection and ConstCollection, but I'm
afraid it is impossible to do with current semantics (maybe
with
covariant (const versus non-const in this case) return types
it would be possible ?).
Submitted On 31-MAR-2000
dkf
The only way you can properly handle asserts is to specify
that any methods called have no detectable side-effects.
Which is very tough to detect, since you may have an object
whose exterior appearance is that of immutability, but whose
actual implementation does all sorts of things that are not
constant (talking to a database, for example.) No amount of
playing around with a "const" keyword will add this check
either; only DBC (or anything stronger than that, of course)
can offer these sorts of guarantees. You could prohibit
method calls (const would only ever tell you about what
you're doing to parameters and results, and nothing about
what is really going on) in asserts, but that is just too
restrictive - I'd like to assert things about strings...
Given that "const" doesn't solve many problems (it only
helps when you're passing around arrays that shouldn't be
assigned to) and it introduces plentiful problems of its own
(creeping constism plagues C++, making it harder to write
code than it ought to be) we're better off without it. If
you put side-effects in your asserts or muck around
inappropriately with arrays, your code will break. But it
is impossible to stop people from writing bad code; all you
can do is make it easier to write good code...
Submitted On 05-MAY-2000
mcharsley
I agree, much needed in a language where any object is
passed by reference - just as long as we have a mutable
keyword for those lazily-evaluated member variables. I
can't understand why the Java authors appeared to view it
as being as bad as goto.
The only problem is that there's so much existing Java code
out there that doesn't support const, that we'd probably
need some abomination like const_cast, just as C++ needed
it to be able to use all the existing C code.
Submitted On 08-MAY-2000
dkf
What good would "const" do anyway? There are three cases to
consider:
1) const primitive types - These can be done quite happily
through other mechanisms already present in Java; the values
themselves are immutable (42 is always 42!) and variables
containing these values can always be declared to be final.
This applies equally to a reference to an object or array.
2) const objects - What exactly *is* a const object? Is it
one that doesn't change any of its fields? Is it one who's
public interface has no set methods and no writable public
fields? Is it one that always gives the same answers for
any of its method calls (given the same inputs, of course.)
The first of these operations is unduly restrictive; the
object would not even be able to keep a record of the number
of times it has been accessed. The second is just plain
laughable as the object could just call those methods
something else. The third requires much more sophisticated
analysis to enforce, and is clearly not robust in the
presence of accesses outside the current Java environment.
The only solution to this sort of thing is something like
Design By Contract, but integrating that with Java means
integrating it with the whole of the Java libraries too,
which is a lot of work.
3) const arrays - this is the only case where it would have
any value, but there are still problems, since what happens
if the array is changed by some other route (another thread,
or just a separate non-const reference in this thread)?
Life is not a bed of roses and things will still go wrong.
Unless you forbid mixing between const arrays and non-const
arrays (a ridiculous suggestion, I'm sure you would agree!)
I just don't see a nice way of handling constant arrays,
though there are certainly possibilities (c.f.
http://www.javasoft.com/aboutJava/communityprocess/review/jsr041/)
if you are willing to go the DBC-like way of using
assertions.
Looking at the above, I'd say that the chances that const is
going to add anything particularly valuable to the Java
language are small. One thing it could do is already
covered by existing constructs, another requires a
completely different strategy, and the third doesn't offer
nearly enough. And it would open up a morass of mess as the
const typing propagates through libraries, causing problems
for loads of existing code.
Please, no const. The costs are too high for the meagre
benefits offered.
Submitted On 17-MAY-2000
epovazan
I'll add my vote for the const modifier, to be used as C++
uses it. Besides, it's already reserved in Java, so use it!
const is a DESIGN tool. It is also a SPECIFICATION as to
what an object does, just like exceptions are specified in
the interface.
Anyone who is a C++ coder has found problems when passing a
const object to a method requiring a non const object. In
99% of the cases, it show a design flaw in the libraries.
There is always a workaround in the 1%, including
const_cast when used with caution.
At the moment I have to resort to implementing a constant
interface (only getters) for most of my objects.
And I bet the garbage collector would get a break ... how
many libraries simply new() an object when they return it,
to prevent the accidental modification of members.
Submitted On 23-MAY-2000
danfuzz
I'll add my vote for the functionality, but I have to say I
absolutely hate the term "const" as used in C++ because
it's so misleading (misleading enough that in my past I've
had to work around bugs in C++ compilers that mistook it
to mean "immutable"). I'll put forward two suggestions:
"readonly" and "sensory." As for the latter, there is some
history of the use of that term in capability systems for
the
proposed meaning. (See, for example,
<http://www.cis.upenn.edu/%7EKeyKOS/OSRpaper.html>.)
But I think the former is reasonably contrastive to
"immutable"
(which I'll also suggest should be a concept supported by
the language and VM) and has that all-lowercase-look made
so popular by the "instanceof" keyword and "arraycopy"
method.
Submitted On 25-MAY-2000
svenmeier
Please no const - keep the Java syntax simple.
(I totally agree with "dkf".)
There should be a way to vote *against* a so called "rfe"
in the bug database...
Submitted On 30-MAY-2000
andythomascramer
Dkf's protests against const objects are not relevant to
this RFE. This RFE requests a compile-time-checked
qualifier for references that restricts the operations that
may be performed through them -- not a run-time-checked
guarantee of object immutability.
Support for such references can be added without
modifying existing libraries to be const-correct. Whether
and how to modify existing libraries is a separate issue.
Submitted On 09-AUG-2000
jdesmet
As the JVM is an interpreter the const should definitly not
be only a Compile Time thing. It should be consistant with
the Reflection API, as the const is part of your method
signature. Not everything is yet resolved at compile time.
Submitted On 18-AUG-2000
frankbranch
A better approach would be to declare particular instances
as immutable. Why you may ask? Supose we create a class
that represent color. A programmer may want to create a
color instance that would change as various states in the
application change. However, the class designer would like
to be able to produce singletons that represent specific
colors that could never be changed (ie. red, blue, etc...)
Current you have to create two classes one class that
represent color and another that exends color with all of
the accessor methods disabled.
Alternately, you could create one class and add a readonly
internal boolean, and create constructors that set this
flag.
A language based solution would be better and more
consistant.
For example:
public class color
{
public static final Color red = new immutable Color
(255,0,0);
}
Any attempt to change internal member varibles or red would
result in an ObjectImmutabilityException. If another
programmer needed a color that they could change. They
would just use the old delclaration.
Color statusLight = new Color(255, 0, 0);
if (status.equals("Warning")
{
statusLight.setRGB(128,128,0);
}
Submitted On 22-AUG-2000
andythomascramer
On the other hand, the misuse of instances marked immutable
frequently could not be detected at compile-time, and
checking them at run-time would add an additional run-time
cost to every method call, even on instances of classes not
using the feature.
Personally, I'd rather have my compiler complain than my
clients, and I don't want Java to run any slower.
For immutable instances of classes with mutators, cheaper
options are available.
* You cite one that provides run-time checking.
* Switching the inheritance relationship so that the
immutable interface is the superclass allows compile-time
checking.
* The typical Java approach is simply not to not provide
mutators -- at the cost to performance of creating a new
object whenever modifications are desired.
* With const-restricted references, a programmer could
provide an effectively immutable instance by providing only
const-restricted references to it -- unless casting-away-
const were supported.
Submitted On 22-AUG-2000
guill
Please don't add const in the Java syntax.
Of course their is case where the const would be usefull, the same also stand for all the feature of the C++,
or any other language. I think sun make a good job in choosing the language feature that are really usefull
to most programmer and putting away the one that are usefull only in specific situation or very confusing.
It`s a lot simpler to understand someone else code in Java language that in C++, thanks to the confusing
features that don't exist in Java.
There is other language extension that will prevent a lot more mistake and create a lot less confusion :
generic type, covariant return type, pre and post condition...
Submitted On 30-AUG-2000
bmckeever
The type of programming that the lack of const engenders can be seen in the Collection API. One of the
things about it that drives me crazy is the idea of (e.g.) static List Collection.unmodifiableList(List list). The
iterator() for this collection throws an UnsupportedOperationException if you call its remove() method. It is
quite likely that this won't be detected until runtime, and quite unlikely that there will be a handler for this
exception (since it's unchecked). On the other hand, using C++-like const, you could have a const
Collection return a const iterator, and have remove() be a non-const method. Then the above error is
caught at *compile-time*. I would much rather have a compiler tell me that something is not quite right
than have a user tell me.
Submitted On 30-AUG-2000
amorrowcrcg
Has anyone discovered any third party tools for doing
compile time const checking?
Many of the RFE's in the top ten have associated third
party precompilers - GJ for genericity, iContract for DBC,
aspectJ for AOP (although that is not an RFE). I would be
very interested in finding an analogous tool for const
correctness.
I'm also curious as to whether any work has been done on
designing a generic framework for compiler/language
extensions. It would be very usefull to have a tool that
combined the above technologies and allowed new plugins,
perhaps using JavaML and XSL... any info or comments?
Submitted On 10-SEP-2000
javabandit
YES. Please add const (or an enhanced 'final') to the Java
language.
In large applications (especially MDI apps), it is
important to be able to control the mutability of objects
across different contexts.
The current implementation of using the 'final' modifier
with a parameter is really useless. It only keeps the
reference from being reassigned. Very silly... which is
why it is hardly ever used in this context.
Writing an interface or a wrapper to handle this kind of
functionality is very expensive and promotes code bloat.
The concept of objects/primitives being flagged as read-
only is nothing new to OOP. There is no reason why Java
should NOT have this fundamental capability, IMHO.
Although, people seem to only want compile-time checking, I
will stand up (as I have in other forums) and say that in
this age of distributed computing and EJBs, it becomes
increasingly important to have runtime checking as well.
Only requiring compile-time checking is fine, but it really
is thinking 'inside of the box'.
The ability to control the mutability of an object/EJB
across distributed platforms would be ideal.
This gets my vote.
Submitted On 12-SEP-2000
javabandit
Andy,
You are correct that the RFE does not explicity state that
a read-only marker be placed on objects, but if you read
the all of the RFEs (and I know you have -- because I've
seen your posts), you'll see that the evaluations/solutions
are rarely exactly what the RFE asked for in the first
place.
Using your own example, I think it would be highly useful
to be able to declare an object as 'final' (or const)
within the scope of that method call:
double distance = MyClass.distance(final p1, final p2);
And you are correct. That is not to say that the object
itself is globally immutable; rather, that it is only
immutable within the scope (or context) of the distance()
method.
Being able to declare the arguments as const within the
signature of the distance() method itself would be greatly
helpful. Java does support this syntax, but it is severely
limited. Unfortunately. I REALLY like the idea of being
able to pass an immutable marker along with the reference
to an object.
Hopefully they lay the groundwork to get this in by 1.5. I
don't see them supporting runtime checking at all (with
respect to const/strict/parameterized-type checking). Its
probably too much of a major overhaul.
But one can always hope...
--Rick
Submitted On 18-SEP-2000
andythomascramer
Rick and I discussed this at length over email.
I misunderstood Rick's post. He was requesting the ability
to mark references as restricted to read-only operations --
the basis of this RFE – not the the ability to mark objects
as read-only.
We also have different assumptions. I assume that the
compiler would not allow copying a const-restricted
reference to a non-const-restricted reference (e.g., an
argument copied to a parameter in a method call). This
enables compile-time checking, for example, that a const-
restricted formal parameter is not modified in either its
method _or_ the call graph descending from its method.
Rick does not make this assumption, and specifically wants
to be able to pass const-restricted references to
references not marked const-restricted -- so that such
references could be passed to non-const-correct recipients
without modifying the recipients. (Rick emphasizes its
utility in distributed programming, where making the
recipient const-correct might not be feasible.) His desire
for runtime checking is a logical consequence.
Submitted On 04-OCT-2000
hwc
I, too, get confused by the different possible meanings
of 'const'. C++ introduces the idea of const methods, then
immediately adds 'mutable' and 'const_cast<>' to get round
it: not a good idea. const function parameters may seem a
good idea but are of limited value without const methods.
As a way of solving this problem, and others, I would much
rather be able to pass objects into a function by value as
well as by reference (see also RFE 4213096).
Submitted On 07-OCT-2000
derbyshire16
Just Say No to passing objects by value. This is the #1 cause of poorly-performing C++ programs -- large
structures and objects being passed by value. It also raises issues of copying semantics for various classes.
Const-correctness need not involve the "const methods" confusion in C++. We don't need a keyword at all,
because Java stores metadata in its classes. A "const-correct" future version of javac can, in compiling a
non-static method, note whether it changes non-<code>transient</code> fields of the object, and if so,
flag it as modifying, and otherwise as non-modifying. It could check method calls on constant references for
being to methods flagged as modifying, and report an error if so. For interoperability with older versions, it
would ignore methods not flagged either way (those from older implementations), and optionally produce
warnings. Javadoc could be modified to indicate in generated documentation methods that don't modify the
object and classes that have no modifying methods. Alternatively, one could add new keywords, say
"nomod" to indicate a method that is nonmodifying and "immutable" to indicate a class whose instances are
supposed to be immutable, as convenient indicators that can show up in javadoc generated documentation
and to force the programmer to pay attention to what they are doing. This would produce better
correctness, as the programmer must in declaring certain methods and classes explicitly state their
intentions for them, but makes interoperability and backward compatibility harder to maintain, particularly
because of using new keywords. Reusing existing keywords, of course, would also be confusing -- the
multiple meanings of "const" in C++ have been described as such. Even better alternative for future
const-correctness: mark not the immutable classes and nonmodifying methods, but the mutable classes and
modifying methods. This will really force programmers to specify their intentions -- they will have to declare
all mutators as modifying, and any class of mutable objects as mutable. Agan, though, interoperability and
backwards compatibility might be an issue.
<p>We do already have a way to indicate instance variables that are not intrinsic to an object's identity
(<code>transient</code>). However, we might want to separately specify data not serialized and data that
isn't part of a constant object's identity. Certainly, we will need a new keyword to indicate references that
can't be written through -- "constant" presumably -- since "<code>final Foo bar</code>" indicates andt
<code>bar</code> can't be re-aimed and <code>public final Foo bar ()</code> indicates that
<code>bar</code> can't be overridden.
<p>Immutable classes -- These would be enforced at compile time to only contain nonmodifying methods,
aside from constructors of course. Non-<code>transient</code> (or whatever) fields would have to be
declared <code>final constant</code>.
<p>Non-modifying methods -- Inside of these, the <code>this</code> reference would be treated as
<code>constant</code>. One consequence would be that if the method returned <code>this</code> it
would have to be declared as returning a <code>constant</code> whatever.
<p>Constant references -- A <code>constant</code> reference could be re-aimed if not
<code>final</code>, but could not be modified -- only nonmodifying methods could be called on it and any
non-<code>transient</code> (or whatever) fields inside would be treated as <code>constant final</code>.
<p>Primitive types -- For these, <code>constant</code> would be synonymous with <code>final</code>/
Submitted On 09-OCT-2000
andythomascramer
Derbyshire raises some good points, and is right on target
about the negative aspects of passing objects by value.
Objects and call stacks can both be big! I’d like to
discuss just a few points.
“Constant reference” seems misleading, so I’ll use the term
“const-restricted reference” instead.
Explicit identification of immutable classes has been
proposed at least by Gosling (see
http://java.sun.com/people/jag/FP.html#overloading ).
Perhaps all methods of immutable classes should be
implicitly const-restricted?
Const-restricted methods require explicit identification.
Automated identification is not sufficient, because a
method that’s logically non-const may be physically const
one day and not the next. The const-restriction of a method
is part of its public interface, and shouldn’t depend on
its implementation (though the reverse may be true). In
addition, Java has no means of identifying logically const-
restricted methods – only physically const-restricted.
It’s best to identify const-restricted references and
methods explicitly, rather than non-const, because it makes
the language more accessible to beginning users. This
accessibility to beginners continues to be vital to Java’s
success as a language.
A new keyword is not _necessary_ to identify const-
restricted references and methods (though it might be
desired). The following syntax is offered solely as a
counter-example.
Examples of existing syntax:
final int myInt // Constant primitive.
final MyClass myRef // Constant reference to
object
final MyClass myMethod() // Method which may not be
overridden.
Examples of syntax without new keyword for identifying
const-restricted references and methods (combinations of
these are possible):
MyClass final myRef // Variable, const-restricted
reference.
// Only const-restricted
methods can be
// called through it.
MyClass final myMethod( ) // Method that returns a
const-restricted reference.
int myMethod() final // Const-restricted method;
compile-time checked.
double[ final ] myArrayRef // Array whose member
primitives may not be
// modified through
myArrayRef.
MyClass[ final ] myArrayRef // Array whose member
_references_ may not be
// modified through
myArrayRef.
MyClass[ ] final myArrayRef // Array of const-restricted
references.
Submitted On 20-OCT-2000
Ixchel
With regards to the above comment, I agree that in C++ this
is a significant problem. In C++, it is often necessary to
write both a const and a non-const version of the same
method in order to satisfy the compiler, e.g.
// Non-const method returns a reference to a non-
constant Thing
Thing & operator [] (int index) {
return array[index];
}
// Const method returns a reference to a constant Thing
const Thing & operator [] (int index) const {
return array[index];
}
However, it has occurred to me that this problem could be
solved if there were a keyword which indicated what I will
call, for lack of a better term, 'covariant const'. In
other words, the keyword would indicate constness if the
object in question (the one that the method is being
defined on) was const, and would indicate nonconstness if
the object was non-const. This should be resolvable using
static types at compile time.
For instance, in place of the declarations above, one might
write:
covconst Thing & operator [] (int index) covconst {
return array[index];
}
The above method would be invokable both on a const object
and on a non-const object. For purposes of static
typechecking, if invoked on a const object, it would be
considered to return a reference to a const Thing, but if
invoked on a non-const object, it would be considered to
return a reference to a non-const Thing.
Of course, someone can probably find a better keyword than
the 'covconst' that I used in the above example. Also, I am
not particularly fond of the C++ syntax for declaring
methods to be const -- I think a more readable syntax could
be found.
Submitted On 23-OCT-2000
hlovatt
Java and 'const'
Below is a proposal that adds a 'const' type construct to Java that is without
the problems associated with the C++ 'const' construct, needs little new
syntax, does not need new keywords, breaks little old code (compiler switch
for old code), and does not need runtime support.
In summary I propose that 'm.inv()' means 'm' may change, whereas 'inv(m)'
guarantees that the fields of 'm' don't change. Note 'inv(m)' is not a call to a
static method but a call to an instance method. The proposal formalizes in the
language the concept that method calls don't have side effects by making the
fields of all method arguments constant. To help the compiler and the runtime,
all method arguments are made implicitly 'final'. More details below.
The debate in this discussion group demonstrates that their is support to add
some sort of constant assurance to Java. The debate also demonstrates that
there is also considerable opposition to adding the C++ type of 'const'
construct because of problems people have encountered with this construct.
Therefore I think Sun are wise in resisting adding a new construct until
something better than the C++ 'const' is discovered.
The debate in the forum has centred on two different types of constant
assurance. Firstly a form of design contract that assures the user of a method
that objects don't change. Secondly a form of final for class objects. The
second type of suggestion is typified by:
Type t = new immutable Type();
This proposal deals with the first form, a design contract. This is what
this RFE was originally concerning (I think - original posting not 100% clear on
this). I am not dismissing the need for immutable class objects but think this
extension is best handled in another forum.
There are many problems with the C++ 'const' construct as already discussed
in this forum. So many as to easily justify Sun's decision not to add 'const' to
Java. I will not review all the problems here, read the other postings if you are
interested in seeing the problems people have encountered.
This proposal, like the others in this forum, deals almost exclusively with class
objects, leaving primitive semantics largely unchanged. The only change to
primitive semantics is that arguments are implicitly 'final'. My ideas stem from
thinking about why 'const' is a problem in C++, since it seems so good when I
first encountered it. I, like many others, started to change all my code to use
'const' everywhere when it was first introduced in C/C++. That is until I
discovered the problems that are now well documented, I now use 'const'
sparingly. I think the problem is that it is a feature for the class writer, whereas
what is required is a feature for the class user. Also the feature is a mixture of
design by contract and immutable object whereas these different concepts are
best treated separately.
By way of example I will use a hypothetical 'Matrix' class that has methods to
invert a matrix ('inv'), to add matrices, etc. The matrix class could store the
elements of the matrix in a 'double[rows][colums]' array one array element for
each value or if the matrix was sparsely populated use a smaller
'double[rows][varable_length]' array and implicitly assume the missing elements
are zero. The point is that it doesn't matter what the internal storage structure is
to the user, therefore this class is a good example of a general problem.
The idea is that a non-static method invoked with the new syntax
'method_name(object_name, ...)', e.g. 'inv(m)', guarantees that the fields of 'm'
don't change. Whereas the existing non-static method invocation
'object_name.method_name(...)', e.g. 'm.inv()', makes no such guarantee on 'm'
(but formal arguments are guaranteed not to change). Note: 'inv(m)' is not a call
to a static method, static method syntax is unchanged, i.e.
'class_name.method_name(...)' or 'unused_obj
Submitted On 23-OCT-2000
andythomascramer
I was greatly mistaken. Method calls can occur on the lhs
of an assignment statement in Java. (For example, a method
could return a reference to an array, which could be
subscripted on the lhs of an assignment statement.) And
there are other situations in which both const and non-
const versions of a method may be desired. However, in
practice, at least for me, such doubling occurs rarely.
Submitted On 23-OCT-2000
andythomascramer
Jcb seems to suggest that each method requires a const
and non-const version, merely to allow calling the method
through both const-restricted and unrestricted references.
This is not true, because const-restricted methods can be
called on both const-restricted and unrestricted references.
Jcb's comments about the doubling up of methods apply
only to methods used on the left-hand-side of an assignment
statement. This is possible in C++, given operator
overloading (e.g., of operator[]), but not in Java. His
concern about the "doubling up of everything" is hence
unwarranted. Ixchel's solution would not be required for
Java. (And, IMHO, though nice, it would not be used
frequently enough in C++ to offset the costs of its
inclusion in C++. This is off-topic, so let's discuss this
via private email, if desired.)
Jcb's comments about defining two versions of iterators
are true. However, iterators are defined infrequently --
I've defined several in the last decade -- whereas const-
restricted references and methods could be used in every
Java class.
Submitted On 24-OCT-2000
andythomascramer
While hlovatt’s proposal might be interesting for a new
language, it isn’t feasible for inclusion in Java. Contrary
to his assertions, a great deal of existing code does
modify objects to which references are passed as formal
parameters.
For example, consider one class: java.util.Collections.
Here we find methods fill(), copy(), reverse(), shuffle()
and sort(), all of which modify the objects pointed to by
references passed as formal parameters. Its companion
java.util.Collection contains toArray(Object[ ]). And is
there really little existing code using System.arrayCopy()?
In addition, his proposal doesn’t provide const-restriction
for references returned from methods. Some of such methods
require two versions in C++. Hlovatt eliminates the need
for duplicate versions by eliminating the functionality
that led to their requirement! Ixchel’s elegant solution
eliminates the need without eliminating the functionality.
As well, without const-restricted references in general,
how does one return, given a const-restricted reference to
a composite object, a const-restricted reference to a part
of the composite? How does a compiler verify a method
doesn’t save a copy of a reference parameter for later
abuse?
Also, hlovatt’s proposal does not cover const-restriction
of array contents. Consequently, the proposal does not
provide a means for a class to expose arrays for reading
but not writing. This is highly important for efficiency.
Const-restricted references and methods can be implemented
in Java without breaking _any_ code, and with greater
functionality.
Submitted On 25-OCT-2000
andythomascramer
Hlovatt's proposal doesn't conflict with this RFE; my
criticism was for infeasibility and incompleteness. I
overlooked ambiguity.
In addition to breaking much existing code, hlovatt's
proposed syntax for calls of const-restricted methods is
ambiguous. Let alpha be a reference to an instance of class
Alpha. Let a call "inv(alpha)" exist in a class Beta. Is
the call to a const-restricted method of alpha, or to a non-
const-restricted method of Beta? It isn't possible to tell
from the call alone, and any resolution based on available
methods in the two classes results in fragile code.
Also, note that special syntax for the call is unnecessary.
Given const-restricted references, a caller could already
mark a call as const-restricted either by using an existing
const-restricted reference -- the usual case -- or casting
to a const-restricted reference. Using the syntax I showed
above, both calls of aMethod() below indicate that aMethod
() must be const-restricted:
void someMethod( MyObject final o ) {
o.aMethod(); // Must be a const-restricted method.
}
void anotherMethod( MyObject o ) {
((MyObject final) o).aMethod(); // Must be a const-
restricted method
}
Finally, note that Java is neither a procedural nor
functional language. There are frequent cases in which it
is useful for instance-based methods to modify objects
pointed to by formal parameters.
Submitted On 25-OCT-2000
hwc
hlovatt's suggestion seems to be a variation of the common
convention that functions should not modify their arguements
whereas procedures may. Sticking with the example of matrix
inversion, if a matrix method is declared void inv() or as
static void inv(matrix m) is likely to invert the matrix
in place whereas a member declared matrix inv() or a static
method matrix inv(matrix m) should return a new object.
Rather than extending Java's syntax to create a new type of
function, I would find it useful to have a tool that warned
me when a class I was using might be breaking these rules.
This would be difficult for the compiler to do accurately
but that wouldn't matter - as a user, all I need to know is
that a function call *might* modify one its parameters.
Submitted On 30-OCT-2000
Ixchel
Oops. In that last comment, I accidentally reversed the
names 'source' and 'destination'. Clearly, the const
parameter should be the one being copied FROM. :-)
Submitted On 30-OCT-2000
hlovatt
I would like to thank everyone for their thoughtful comments concerning my
proposal, which I will address below. However first I would like to digress.
In this forum a number of postings (including mine) have alluded to the fact that a
C++ style 'const' is possible using a wrapper. However no one has spelt this out,
in "Java Platform Performance Strategies and Tactics" a good example of a
wrapper that adds C++ 'const' functionality is given (page 95). I have slightly
modified their example below to illustrate the use of wrappers.
public class Location {
protected int x, y;
public Location() {}
public Location(int x, int y) {this.x = x; this.y = y;}
public final int getX() {return x;}
public final int getY() {return y;}
public final Location max(Location l) {...}
...
}
public class MutableLocation extends Location {
public MutableLocation() {}
public MutableLocation(int x, int y) {super(x, y);}
public final void setX(int x) {this.x = x;}
public final void setY(int y) {this.y = y;}
public final MutableLocation add(MutableLocation m) {...}
...
}
You use 'Location' where you want a 'const' and 'MutableLocation' where you
don't want 'const'. You can also cast away 'const', e.g. if 'm1', 'm2', and 'm3' are
all of type 'MutableLocation' then you can write
'((MutableLocation)(m1.max(m2))).add(m3)'. Note the use of inheritance allows
the call 'm1.max(m2)' without needing any casts even though 'm1', and 'm2' are
of type 'MutableLocation' and the arguments of 'max' are of type 'Location'. This
wrapper construct is better than the C++ 'const' in three ways: the declaration
syntax is clearer, the cast is type checked, and you can declare 'MutableLocation'
private if you want users of your class to only have access to the immutable
form. This later improvement (private mutable form) over C++ is apparently used
in Sun libraries, e.g. the 'BigNumber' classes. Internally 'BigNumber' classes uses
a mutable object for efficiency reasons but to keep the interface clean only the
immutable form is made public. This wrapper technique and other forms, e.g. see
'Collection' classes, can be applied to primitive arrays to give any desired degree
of control over access.
To get back to my original posting, the reason for wanting the change I proposed
is that adding a C++ 'const' construct gives us little we don't already have using
wrappers. The change I proposed, as well as helping the user of a class also
helped the runtime optimize the code. Two people have pointed out that they
would like to write static methods that changed at least one argument (none static
methods can change 'this' in my proposal already using the form 'm.inv()'). I
would therefore suggest a change to my proposal, the first argument of static
methods is not forced to have unchanging fields. I.E. 'Matrix.inv(m)' in this
modified proposal is analogous to 'm.inv()' but still quite different to 'inv(m)', in my
original proposal 'Matrix.inv(m)' was analogous to 'inv(m)'. This does not allow
arbitrary arguments to change, only 'this' in the form 'm.inv()' and the first
argument of a static method, e.g. 'Matrix.inv(m)', are allowed to change - all
others arguments are constant. This maybe not what everyone want but I think it
is good practice and is what is most comonly done, allowing arbitrary changing
only encourages bad practice.
As one posting has pointed out the intention can be infered from the return type
(if it is void it is an in-situ change) otherwise it returns a copy. This is essentially
the same suggestion, it just depends on which set of syntax people prefer.
Another posting raised concern re. name hiding, I don't think this is a problem, the
existing methods of qualifying a name (e.g. 'this.<method_name>', etc.) can be
used.
In subsequent thought about my proposal I came up with two problems
Submitted On 30-OCT-2000
Ixchel
Hmm. My main concern regarding hlovatt's proposal is that
it defines methods in which ALL parameters are const, or NO
parameters are const, but it allows no mixing of the two.
So, for instance, I have no way to declare a method like
the following C++ method:
void copyArray(int * source, const int * destination,
int howmany);
Note that this method has one const parameter and one non-
const parameter. There would be no way to write such a
method in Java using hlovatt's proposal.
This one fact alone kills the proposal for me right there.
It is quite common to want to declare some method
parameters const while allowing others to remain non-const.
Submitted On 05-NOV-2000
pmurray
I think this is a bad idea, and a non OO way to go. Java
already has a way to stop other classes modifying your
class in ways you didn't expect - it's
called "encapsulation". If other classes are modifying your
class in ways you didn't expect, you haven't coded your
class properly. If calling a getter method makes a class
change state, then someone is not using the "get/set"
accessor method paradigm properly.
Flashy features are no substitute for good coding practise.
I don't want to see java become a heavyweight language like
C++, ADA and Cobol.
Submitted On 05-NOV-2000
pmurray
The other way to keep other classes from modifying your
class is by correct use of the security mechanism. If you
don't want someone else's method calling a method on a
parameter you pass, then what you are looking at is a
security issue. Yes, signing your code and putting security
checks in place is complicated, but its more general, more
flexible and it's already in the language.
Submitted On 06-NOV-2000
andythomascramer
Encapsulation protects the representation of a class from
being modified in ways not expected by the class.
However, that is not the goal of this RFE. This RFE seeks a
means to restrict certain references to operations which
don't change the referenced object's logical state.
For example, encapsulation protects the representation of
subclasses of java.util.Collection. Compare that to a const-
restricted reference to an instance of a Collection; it
could be used to call Collection.isEmpty() -- if it were
marked const -- but not Collection.add(Object).
This RFE seeks a simple, compile-time checked means of
const-restricting references. Java's security mechanism is
run-time checked, adds run-time costs, and would require
greater development and maintenance costs. It's a worse
hack than splitting a logical class into two physical
classes.
Submitted On 10-NOV-2000
VWorksS
Yep, this is a good idea. Anything that emphasizes Design
By Contract as opposed to Design By Convention or Design By
Gambling is a good thing.
How to implement it, however, is another issue. I don't
think the 'const' keyword from c++ is the optimal way to
go.
Submitted On 19-NOV-2000
naansoft
I agree to the need of having const in as many aspects as possible. Not only will this give a better protetion
during programming - it should also enable compilers, JVM's and gc's to do more intelligent work.
Submitted On 29-NOV-2000
hounsome
C++ style const can be added in a backward compatible way
provided only that overloading based on constness is not
allowed.
The compiler could have a flag to treat const violation as
a warning.
The jvm would not even know that it existed.
The reason that I would like it added is so that I can
efficiently dole out some of my class's internal data to
clients without them being able to modify it.
Submitted On 30-NOV-2000
vailant
I vote stricty against having const!
As can be learned from C++ with the late
introduction of mutable, the subject is much
more complicated then it looks like.
Keep it Simple!
Submitted On 18-DEC-2000
pvloon
Please no const for Objects.
If an Object should not be changed, it should be reflected in its methods.
If you want two types of Objects, one that can be changed, and one that can't,
please create two classes to do this.
If you really want somebody not to change the internals of your particalur object,
give them a copy.
In C++ code I have seen, const is a mess, ending up in too much code that starts
casting const away again.
This just adds complications to Java and doesn't solve problems that can be solved right now.
Submitted On 22-DEC-2000
andythomascramer
Pvloon's comments about const objects don't apply to this
RFE, which seeks const-restricted references, not constant
objects. His or her comments about copying as a workaround
ignore the significant performance hit.
Submitted On 24-DEC-2000
pillayd
Keep it simple - Java should NOT support const parameters. I like strong semantics. I have even been burnt by unintentionally modified objects. However, turning Java into Eiffel for DBC is as silly as turning it into Prolog for backward chaining. Delegation is sufficient for individual objects decide constant correctness. Java provides Exceptions for semantic infringements. Why not use them and avoid the ambiguity C++ const creates?
Submitted On 28-DEC-2000
andythomascramer
This RFE requests the addition of a simple language
feature; this is part of the normal evolution of a
language. It does not request that Java be turned into DBC.
Delegation increases complexity of programs; it is not the
simple approach. Exceptions are runtime phenomena; this RFE
seeks a compile-time verification to reduce risks.
Submitted On 10-JAN-2001
dkf
Having thought about this a bit more, I suppose you could
argue reasonably for const array references (i.e. an array
reference through which it is impossible to assign to
elements of the array) especially since there is only one
mutator for arrays (i.e. assignment - System.arraycopy can
be regarded as a wrapper round this) whose behaviour is
universally understood.
Immutability of classes/objects is much less useful,
particularly since you might have non-transient fields that
potentially need updating on every method call but which are
still not part of the ostensible state of the object (e.g.
that are used to log the number of accesses to the object.)
The problem of constant objects is that the meaning of
constant is non-trivial, and might only apply to a
particular view of an object - it is a matter for the
class's contract (especially as it might actually depend on
the behaviour of other classes as well) and consequently for
a DBC system. These simple language hacks are always going
to be less-than-perfect by comparison, and given the
confusion over the different interpretations of const in
this discussion and the C++ community (as well as the fact
that it is not a critical feature as it can be handled by
adequate software engineering procedures) I have to say that
Sun's position is absolutely correct.
I also dislike both hlovatt's and andythomascramer's
syntax. Once of the most unpleasant problems with C++'s
const are the subtle differences between its meanings,
depending on exactly where in the declaration you put it,
and having a formal "this" parameter seems to be utterly at
odds with the language as it stands (IMHO, of course.)
Submitted On 17-JAN-2001
Ixchel
In regards to the last comment, a couple of observations:
1) C++ 'const' does not attempt to enforce immutability. It
attempts to enforce immutability through a given reference
to an object. This is an entirely different matter. It is
perfectly permissible to have a const reference and a non-
const reference to the same object, and to have the non-
const reference be used to modify the object, thus changing
the state observed by the const reference. In fact, I would
prefer a keyword 'readonly' to be used instead of 'const'
for this reason. It would be less prone to
misinterpretation over its meaning.
2) Despite the fact that the above is true, constness
(or 'readonlyness') is still quite powerful at catching
design-time bugs at compile time. It is certainly not full
Design By Contract, but it can be a useful component of
such a system. Despite some of the above comments, its
semantics can easily be made well defined: A method
declared as 'const' may not change the observable state of
the interface it is called on. (Note that internal caching,
etc. may technically change the state of the object without
actually changing the observable state of a given
interface). Likewise, an interface reference declared
as 'const' may not be used to do anything to modify the
observable state of the interface it references.
Also note that a lot of the things that the 'const' keyword
indicates must generally be specified via comments for
languages that don't have 'const'. Since specifying these
things in English (or whatever language) generally takes
much more text than specifying them with a single keyword,
and cannot be checked automatically at compile time, this
creates more work, not less, for the software developer.
Incidentally, I would also like a 'notnull' keyword to
create a similar compile-time check that a given reference
cannot ever be null. C++ has this (in the form of reference
arguments), and it is quite nice for eliminating argument
validity checks which otherwise waste time.
Note that if the 'const' keyword existed in Java, by the
way, that the whole concept of 'const wrappers' from the
Java Collections Classes could be eliminated, resulting in
an increase in runtime efficiency when using immutable
collections.
In fact, I wonder if a similar use of the 'synchronized'
keyword could eliminate the need for synchronization
wrappers from the libraries as well...
Submitted On 24-JAN-2001
dkf
It is deeply unsafe to eliminate synchronized like that.
Submitted On 24-JAN-2001
dkf
The problem comes from the complexity of specifying which
methods are const-preserving, and which are not (as opposed
to which return const object references.) Sure, you could
do it with different positions of the keyword, but that's
really going to just confuse more people than it helps.
Hmm. If you have non-mutating methods, do you allow two
adjacent calls to the same non-mutating method to be
coalesced into a single call?
Submitted On 07-MAR-2001
tbreuel
PLEASE keep it simple. In the right language, I'm all for
immutable types. I love functional programming. But Java
isn't that kind of language. Retrofitting the language, the
compilers, and the programmers would be a major
undertaking. I think there are bigger, more pressing issues
to address than this.
Submitted On 07-MAR-2001
Ixchel
The const keyword as it is used in C++ has nothing to do
with immutable types, nor with functional programming. It
allows compiler-enforced read-only references to particular
objects. This does not affect the types of those objects,
and does not recast Java as a functional programming
language (unless you intend to make ALL of your references
const...)
Submitted On 20-MAR-2001
hugg
No! Java is what it is, and what it is is not C++.
Retrofitting the class libraries with const would break
every single program ever created. For that matter, lets
add asserts, guard statements, theorem proving...
Submitted On 23-MAR-2001
andythomascramer
Languages grow over time. Java is no exception. The asserts
hugg mentions, for example, are being added in merlin (see
bug ID 4290640).
Language features are not automatically bad merely because
they're found in C++. For example, C++ includes
typechecking.
As noted in a previous comment, this RFE does _not_ request
modification of existing libraries; that's a separate issue.
Submitted On 10-APR-2001
enicholas
I'd like to add yet another request for a negative vote capability -- I do *not* want this feature added to
the language!
Submitted On 03-MAY-2001
lukaszczyk
I do *NOT* want this feature in the language. The numerous
arguments presented by fellow developers are proof
that "CONST" will be inconsistently used. We have found
that using true immutable objects (such as String) can in
fact be used to enforce the desired behavior both at
compile-time and at run-time. And yes, we have heard all
the "but-copying-is-not-optimal" arguments associated with
this philosophy by those not comfortable with immutability.
If you really care not to change an object's state, then
make the object protect itself. "Immutability by policy" is
not a safe way to design a system. When properly
architected,a system relying on immutable entity objects
can be made nearly as efficient as one that does not, and
as for "maintenance" costs, it is much safer to allow those
unfamiliar with a system to add code that operates with
immutable objects than to expect them to remember to
type "const".
Submitted On 03-MAY-2001
hwc
As far as I can see, nobody is suggesting that the user of a class
needs to put 'const' anywhere. Rather, it allows the class's author
to specify when a method might have unforseen side effects:
1) a const method does not change the state of its object;
2) a method cannot change the state of const parameters;
3) a const returned value cannot be changed by the method
that it has been returned too.
Immutable classes will often be documented as such; making
'const' part of the language lets the compiler in on the secret
so that it can better support the programmer intention.
Further restrictions may (or may not) allow optimisation.
For example: repeated calls to a const method should return the
same result if they aren't allowed to modify any class variables,
so the result needn't be re-calculated, but only when it can
be sure that the object cannot be modifed by another thread.
or: objects can be created on the stack, rather than the heap,
if they are only passed to other methods by const references,
providing that such objects cannot be assigned to instance or
class variables (they would need to be cloned)
or: const parameters cannot alias other parameters.
The point being that careful consideration of the rules the
compiler enforces can help provide slightly more efficient,
slightly better documented, slightly more reliable code.
Submitted On 05-MAY-2001
tfhudso
Interesting reading... Anyone else notice that the
discussion about what const is has become terribly
complicated?
It has been argued that const could lower maintenance and
development costs. I don't see how it can lower maintenance
costs. Since maintenance programmers generally are not your
crack programmers, I rather expect it would cost more for
them to find a bug caused by lack-of-const, or to fix bugs
they introduce because their understanding of const is
inadequate.
Immutabilty costs copying. We build large digital signal
processing systems in Java and have found that clone-in
clone-out on the data costs us about 10% in speed. This is
nothing compared to the 300% hit we take for going from C++
to Java. The position we have taken is that if you really
need that 10%, upgrade your computer - hardware is cheaper
than software. And if you really need that 300%, go back to
C++.
The development cost increase is real. It takes time for a
programmer to step back and think about what he's doing
instead of just slapping out the first solution that comes
to mind. This is money I don't mind spending on
development. I have never had anyone offer me a way to
reduce development costs that didn't end up costing
exponentially more in maintenance.
Another nice thing about immutability is that it forces
programmers to separate data and operations. It have seen
some truly horrible objects done by amateurs that would
represent the fundamental object along with file-io and all
the operations they could ever think of to perform on that
object. Using "immutable entity objects" as the core of
what's being passed around for data, and moving every
operation on that data (that can be) to utility classes,
you enforce a partitioning that maintainers can handle and
that makes the system MUCH less brittle.
In short, immutability is very easy to understand. Some
people may not like it, but I everyone can use it reliably.
const will be very hard to understand, even if it settles
down to a single definition. Some will like it, most won't
understand it, and you'll be one step further down the road
of making Java into another C++ or Ada.
Submitted On 08-MAY-2001
andythomascramer
This RFE does not request an "immutable" qualifier for
objects. There are no object variables in Java. This RFE
requests a type qualifier for _references_ which restricts
the operations which may be performed through them
to “const” operations.
The immutable objects suggested by Lukaszczyk and tfhudso
are sometimes an appropriate workaround for the lack of
const-restricted references. But usually the interface-hack
is better. Consider java.util.Vector. A reasonable
implementation using the immutable-object approach would
require a pair of classes, ConstVector and Vector, the
former immutable and the latter not, a la String and
StringBuffer. The size of the class hierarchy is doubled
(as it would be with the interface hack as well). To pass a
mutable vector to a method that accepted an immutable
vector would require the _caller_ to copy the Vector to a
ConstVector - extra code and an O(n) cost avoided with
either const-restricted references or the interface-hack.
Lukaszczyk is concerned about maintenance
programmers “remembering to type const.” I’m unclear in
what exactly what situation a maintenance programmer would
fail to “type const”, and not have it caught by the
compiler, when they _would_ remember to work with immutable
objects.
Tfhudso waves away the costs to performance with the
suggestion to buy better hardware. It may be reasonable to
accept constant-factor performance decreases in in-house
software. It might not be for linear performance decreases
in software developed for external clients.
Tfhudso is concerned const-restricted references will be
too difficult for most programmers to understand. I beg to
differ. Most programmers are acquainted with read-write
permissions various users have with mutable files. I think
we can just barely grasp read-write permissions various
references have with mutable objects.
Finally, as with the interface hack, the immutable object
approach is not usually used in real code because of the
extra costs in development, maintenance, performance and
understandability. The practical result is the anarchy
approach we see in java.util.Vector.
Submitted On 12-MAY-2001
tfhudso
Have you discussed with Bill Joy the meaning of "interface
hack"?
Submitted On 16-MAY-2001
hlovatt
I think that the discussions in this forum have shown how
difficult it would be to introduce a const reference into
Java. Therefore I would like to vote against it. The only
issues that have often arose from the 'pro const camp' are
performance, arrays, and typing. Consider the example below.
class IntArray extends ReadOnlyIntArray {
public IntArray(int size) {super(size);}
public final void set(int index, int value) {array
[index] = value;}
}
public class ReadOnlyIntArray {
protected int[] array;
public ReadOnlyIntArray(int size) {array = new int
[size];}
public final int get(int index) {return array[index];}
public final int length() {return array.length;}
// Test performance
private static int value;
private static long time;
private static void inBuilt(int length) {
long start = System.currentTimeMillis();
int[] array = new int[length];
for (int i = 0; i < length; i++) array[i] = i;
value = 0;
for (int i = 0; i < length; i++) value += array[i];
time = System.currentTimeMillis() - start;
}
private static void readOnly(int length) {
long start = System.currentTimeMillis();
IntArray array = new IntArray(length);
for (int i = 0; i < length; i++) array.set(i, i);
value = 0;
ReadOnlyIntArray rOArray = array;
for (int i = 0; i < length; i++) value +=
rOArray.get(i);
time = System.currentTimeMillis() - start;
}
public static void main (String args[]) {
final int length = 1000000;
inBuilt(length);
System.out.println("In-built test 1: value = " +
value + " time = " + time);
inBuilt(length);
System.out.println("In-built test 2: value = " +
value + " time = " + time);
readOnly(length);
System.out.println("Read-only test 1: value = " +
value + " time = " + time);
readOnly(length);
System.out.println("Read-only test 2: value = " +
value + " time = " + time);
}
}
When run using the IBM JVM 1.3 on my PC I get:
In-built test 1: value = 1783293664 time = 80
In-built test 2: value = 1783293664 time = 61
Read-only test 1: value = 1783293664 time = 70
Read-only test 2: value = 1783293664 time = 60
Therefore performance is not an issue. The example shows
read-only arrays, therefore these are not an issue. As for
typing even such a contrived and small example as this
required little extra typing. Object versions of arrays
could be added to java.util.Array and other libraries
expanded to use them. Surely this shows that const isn't
worth adding!
Submitted On 17-MAY-2001
Ixchel
Sigh. Hlovatt, I have to say, that if you really think that
the example that you have given demonstrates that const is
not worthwhile, you really don't understand it.
The major issues to do with const are architectural issues,
not performance issues. In many cases, usage of const can
cut the number of classes and interfaces that need to be
written for a large library in half, or better.
Furthermore, it prevents lots and lots of bugs.
I have used the "const interface" hack. I have used
constness decorators (like the Java collections). I have
used a variety of other ways to get around the fact that
Java doesn't have const. And, frankly, in many cases, they
suck. They don't work well when you try to apply them to a
large tree of interrelated classes and interfaces. They
introduce a huge amount of complexity into programs, they
slow programs down, and they often create huge typing
messes (of weirdly interconnected interfaces, with every
one having to have a const and a non-const version) that
can't be resolved in any reasonable fashion. These
workarounds work OK for trivial examples, but they simply
don't scale well for large projects.
I've used const with C++ for many years, and it is by far
preferable to these kinds of problems. It's not hard to
understand -- it can be explained to someone in five
minutes. And it works.
Most of the opposition I'm seeing from the people here
against const seems to come from people who don't really
understand how it's used and what it's for, and what the
large-scale architectural impact of it (or of not having
it) is.
For example, try passing one of your "read-only arrays" to
a method that someone else wrote which takes a
java.lang.Object [] which it doesn't modify. What will you
do if you need to deal with a library which you don't have
source for? Etcetera. In the real world, rewriting every
class you need to have a const interface for just isn't
practical, and won't work. Only if we agree on how const
will be implemented can code interoperate. And only by
having it as part of the language can we const-restrict ALL
types in the language without having to implement lots and
lots of scaffolding code just to achieve basic data safety.
Submitted On 20-MAY-2001
hlovatt
Ixchel, thank you for your comments. I would like to take
your example of passing a 'const' array to an existing
function that does not declare its argument 'const'. For
example 'static int f(int[] array)', using a C++
like 'const' notation you would write:
const int[] array = {1, 2, 3};
int result = SomeClass.f( (const_cast)array );
Note that you need to cast away the 'const' because you
can't, in your example, re-write the function 'f' and it
doesn't accept a 'const' array. Even though we know
that 'f' doesn't change the array, the problem is that the
compiler thinks it does because the array is not
declared 'const'.
In my case I would write:
ConstIntArray array = new ConstIntArray( {1, 2, 3} );
int result = SomeClass.f( array.constCast() );
Note in the first line above I have taken the liberty of
using one of the new Java 1.4 initialisers. The
method 'constCast()' returns the underlying primitive array.
For both your method and my method there is a problem if we
are wrong about 'f' and it changes the array. This is the
same as C++ where the results are implementation dependent
if a 'const' is changed.
If you can re-write the function 'f', then in both cases
the call becomes:
int result = SomeClass.f(array);
As you can see there is virtually no difference between the
two methods in either case (able to re-write 'f' or
not).
There is a very good discussion on 'const' in: Stroustrup,
The Design and Evolution of C++, sections 13.3 and 14.3.4.
If you follow the discussion given by Stroustrup you will
see that in addition to requiring 'const' and 'const_cast'
you will probably also want 'mutable'. The introduction of
all these key words is avoided by using the design pattern
suggested by myself and others. What is more, this design
pattern is already in use and the convenience the key words
add is minimal. Note that the key words do not add any
functionality.
Submitted On 22-MAY-2001
vor23
It is a shame that this RFE mentioned C++, because what this
RFE
calls for is much simpler than the mess that const is in
C++. It seems
to me that the request calls for the following only:
1. If an object A contains a method declared const, then
that method
cannot assign to any field in A, nor can it call any
non-const method
in A, nor can it pass A to any method that does not take A
as a
const parameter.
2. A method that takes a const parameter B cannot assign to
any
field in B, nor can it call any non-const methods in B, nor
can it
pass B to any method that does not take B as a const
parameter.
That is it. In this form, I fully support this RFE.
Submitted On 25-MAY-2001
andythomascramer
Vor23 has stated this RFE succinctly. He doesn’t include
mutable members -- and they’re not required, since any
logically mutable members can be implemented through
references to component objects. I myself, however, would
like to see const-restricted references to Java’s object-
like arrays included as part of the RFE; it would be highly
valuable, and the rules are as simple as those for const-
restricted references to objects.
Hlovatt’s suggestion for API-based emulation of const-
restricted arrays has several flaws, including but not
limited to the following:
First, Hlovatt’s array class doesn’t support the common
array indexing operator [ ], since Java doesn’t support
operator overloading. Consequently, it’s less friendly to
those of us who use arrays frequently in complex
expressions.
Second, it doesn’t support multidimensional arrays. This
could be solved by adding methods within Hlovatt’s IntArray
class, or introducing new classes such as IntArray2 and
IntArray3 for each number of dimensions. The former is more
friendly but may suffer additional performance costs (the
cheapest representation in space and time would be a single
Object reference, and all methods would downcast it as
appropriate). The latter introduces new class library
complexity. Both limit the number of dimensions supported
by an IntArray.
Third, either language supported arrays would continue to
be used or not. If they were, then conversion costs would
be encountered between language-supported arrays and API-
based arrays. If they were not, then current array syntax
could be redirected to refer to the API-based arrays --
which would require a syntatic const qualifier on arrays.
Fourth, it requires at least 18 classes to implement -- a
pair of read/write classes for arrays of each primitive
type, and a pair of read/write classes for arrays of the
Object type. Until generics are introduced in 1.5,
downcasts are necessary from accessors provided by the
Object array class.
We know the language _allows_ use of const-restricted
constructs. This RFE requests _support_ for const-
restricted constructs.
Submitted On 30-MAY-2001
hlovatt
It is suggested that API arrays don’t support multi-
dimensional arrays. This isn't true, you can take an
IntArray
and put it into an ObjectArray - this is close to what
happens with built in arrays like int[][]. When we get
generics (version 1.5?), you will be able to write:
ObjectArray<IntArray> a;
...
result = a.get(i).get(j);
This is very similar to the current multi-dimensional
arrays.
However the current multi-dimensional arrays and putting
arrays into an ObjectArray are not what you ideally want
from
a performance point of view because both techniques
introduce
an extra indirection, cause unnecessary bound checking, and
split the array into different areas of the heap. There is
already a package that as part of the 3D Graphics API
called
java.vecmath that has two API based arrays GVector (1 D)
and
GMatrix (2 D), these were introduced for performance
reasons.
There is also an approved extension proposal for API based
multi-dimensional arrays JSR-000083, again primarily
proposed
for performance reasons. The existing package and the
proposed package both store multi-dimensional arrays as a
single dimension array to overcome the performance problems
with the current built-in arrays.
Moving onto syntax, it is true that without operator
overloading that [] is substituted for get or set and that
this is not ideal. It should be born in mind that we
already
use set and get like syntax with the Collections API,
StringBuffer, GVector, and GMatrix, to name a few, and it
isn't too bad. Also other features are better syntactically
with an array based API, for example:
Currently: Arrays.sort(a)
API: a.sort()
The whole of the Arrays API could be replaced resulting in
better syntax, same goes for common matrix type operations
like a.mult(b) and sub arrays, a.sub(1,2). You can also
provide iterators for API arrays to syntactically unify
their
use with the Collections API, e.g.:
int sum = 0;
for (IntIterator i = a.iterator(); i.hasNext(); )
sum += i.next();
Thus API syntax is not only better than the in-built syntax
in many circumstances, it is also more like everyone is
used
to with other commonly used classes like StringBuffer and
Collections.
What I suggest is that instead of asking for const we
canvas
for operator overloading and ask the people who are
currently
implementing JSR-000083 API arrays to add read-only. I have
sent an email to jsr-083-comments@sun.com saying great work
what about read-only arrays, if others do like wise then
maybe we will have const arrays sooner rather than latter.
If
the API arrays become successful then the in-built arrays
could be depreciated, which would be a nice simplification
to
Java (less is more!).
Submitted On 03-JUN-2001
eckely
Const methods are of paramount importance for J2EE EJB
programming. Designating a method as const will
allow “smart” persistence. That is, if only const methods
have been called on a bean during a transaction, the
container may decide not to store this bean into database
(as the bean’s state never changed). Because of this major
optimization, vendors of application servers (specifically
WebSphere and WebLogic) already provide proprietary means
for such read-only designation of bean’s remote methods.
The problem with that (besides the lack of standardization)
is the lack of compile-time checking, causing error-prone
hard-to-debug code. This, plus design help provided by the
const correctness is more than enough to consider this
feature seriously.
Jacob Eckel <eckel@dealfusion.com>
Submitted On 03-JUN-2001
mlaiosa
I would like to refute that the complexity of const-ness in
C++ would be carried into Java by this RFE (or anything
else that adds C++’s notion of const to Java)
This is what I understand to be complex about C++’s const.
If there is a complexity to that I am missing here, please
tell me about it.
class A { … };
//ex 1
const A* i; //A pointer to an A that wont let you change
the A object
A* const i; // A pointer to an A that cannot be made to
point to something else (like final)
const A* const i; //A pointer to an A that cannot itself
change, nor can it be used to change the A
//ex 2
const A ** const * i;
//This is confusing. It is a pointer to a pointer to a
pointer to an A; which may not be used to modify the A, nor
may it be used to modify what is produced by the expression
*i.
1: If the final keyword were used as the qualifier proposed
by this RFE, then this confusion would likely still exist.
For this reason, I am in favor of a different keyword.
2: This would not exist in Java, because you cannot have a
reference to a reference, let alone something as bothersome
as this triple pointer. Java avoids this complexity by
avoiding references to references, adding const-ness will
not bring it back.
Submitted On 05-JUN-2001
hlovatt
I think there is a tendency to understate the difficulty of
the problem of adding const to Java and for that matter, to
assume that C++ did everything wrong. I think that C++
probably got as good a concept of const as you are likely
to get (note I am taking const to be different to
immutable, as this RFE does) in a language where it is
added on after basic mutable types are established. This
understatement of the difficulties of adding const,
although not deliberate, trivializes the debate to the
level of ''it's so easy why haven't we done this already''.
I would like to point out why it is much harder.
Vor23 stated a set of rules but neglected arrays (this has
already been pointed out), generics, fields, locals, and
casting away const. The proposal won't fly unless you can
address these points! I will address all these points below.
For example it has been stated that casting away const
isn't necessary (andythomascramer), if you can't cast away
const then you can't use any existing API because they
don't declare their argument const. This would seem to be a
major problem! Also functions that accept const arguments
often return const values and there is then the need to
cast back to a mutable type. EG to increment the maximum of
two Objects (e.g. arrays), the max function would accept
constants (it doesn't change anything) and therefore return
a constant. Thus you need something like:
int[] a, b; // Note - not const
...
result = ( (const_cast) max(a, b) ).inc();
Once you can cast away const, then you can get bugs where a
supposedly const object is changed by mistake.
Another misconception is that Java doesn't have pointers to
pointers (mlaiosa). However you can have a pointer inside
an object that is pointed to! For example multi-dimensional
arrays. You also need arrays, generics, fields, and
locals. So we would require declarations something like:
final Object final o;
final int[] final ia;
final int[] final [] final iaa;
final Array<final Object final> goa; // Generics
final Array< final Array<final Object final> > goaa;
Just as bad as C++! You could make const mean every stage
of the declaration is final, so that the above declarations
become:
const Object o;
const int[] ia;
const int[][] iaa;
const Array<Object> goa;
const Array< Array<Object> > goaa;
This would probably be OK since the finer control of
exactly which reference and which object is final (const)
is rarely needed. I am suggesting that final is not
changed, so the first example would remain illegal, and
that const is introduced in addition to final with the
meaning implied by the second example. However you can
almost get as good a syntax using wrappers, as shown in
previous postings. So it begs the question, ''why bother
changing the language?''
Eckely has said that there are already products out there
that in a proprietary way declare a limited form of const.
I would suggest that what ever technique they use, I am not
familiar with the products, that it isn't very safe because
of the need to cast away const (in some form or other). The
only suggestion I have seen that seems practical, to allow
performance optimisations, is the immutable proposal of
James Gosling (http://java.sun.com/people/jag/FP.html). I
would suggest that if this type of optimisation is what you
want, then this is not the RFE for you!
I think most people are sympathetic to the idea of
declaring something constant both from a class design point
of view and from a performance point of view. The problem
is, how to do it in Java in a way that adds sufficient
benefit for all the trouble it will be to add. Particularly
when wrappers provide much the same functionality already.
Submitted On 07-JUN-2001
hwc
Please no casting away const; it makes the whole thing unsafe. It may seem useful
to be able to use existing class libraries but if you could always rely on other people's
code doing what they say it should, there would would be much less need to introduce
'const' in the first place.
I would expect add( const Object a, const Object b ) to return a new Object. By
analogy, I wouldn't be surprised if max( const Object a, const Object b ) returned a
clone of the larger object.
Another question, though: this RFE asks for const references and const methods;
isn't an immutable object just an extension of the same idea? Constructors could
(implicitly) return const references and all its methods would be const.
It's not something I've tried, but couldn't APIs be retrofitted with 'const'
parameters, much as is being suggested for collections in the generics
proposal? String, Float etc. immediately spring to mind. Later
compilers can then make a much better job of simple statements such as
String s = ….
Float x = (new Float( s ).floatValue();
Submitted On 09-JUN-2001
cowwoc
One thing that needs to be pointed out: 'const' in C++ isn't _really_ constant. You can easily cast a const
object to a non-const equivilent therefore 'const' provides no protection what-so-ever. If you do add 'const' to
the language, then make sure you plan ahead so that there is no need for const-casting an object to
remove/add a const modifier to it.
Submitted On 18-JUN-2001
sci-agn
This whole RFE is a ridiculous idea. If you want constant
primitives and constant Object references, declare them
final. If you want the objects' fields to be constant, use
the existing modifiers and deny direct access to the fields.
I don't see what is so hard about this.
This is a design issue more than it is a syntax issue, as
correctly mentioned in the official evaluation. I
understand that this RFE was lodged with good intentions,
but what it requests is already possible. If Sun never
implement this, it won't hurt the decent programmers out
there - it isn't their fault that people are generating a
"body of const-incorrect legacy code" (andythomascramer).
Regards,
Aaron Nielsen
roesti@f2s.com
Submitted On 19-JUN-2001
hlovatt
Consider the following code which implements the 'real life'
example given by andythomascramer in three different ways,
firstly as given in this forum, then using an array (API)
wrapper, and finally using vecmath like classes. This is an
ironic example to give in this forum, since the supposed
'good' implementation in terms of speed and least code
using the built-in arrays is in fact the slowest and second
longest!
public final class TwoD {
// Common
static final int testTimes = 5, loopTimes = 1000000;
static long start, finish;
static double result;
static final double ptx = 1, pty = 2, ptz = 3;
static void print(String s) { System.out.println(s +
": " + (finish - start) + " ms - result = " + result); }
// Built-in Array
static final double[][] mb = { {1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16} };
static double builtIn() {
double sum = 0;
for (int loop = 0; loop < loopTimes; loop++) {
double rvx = (mb[0][0] * ptx) +
(mb[0][1] * pty) + (mb[0][2] * ptz) + (mb[0][3]);
double rvy = (mb[1][0] * ptx) +
(mb[1][1] * pty) + (mb[1][2] * ptz) + (mb[1][3]);
double rvz = (mb[2][0] * ptx) +
(mb[2][1] * pty) + (mb[2][2] * ptz) + (mb[2][3]);
double w = (mb[3][0] * ptx) +
(mb[3][1] * pty) + (mb[3][2] * ptz) + (mb[3][3]);
sum += rvx + rvy + rvz + w;
}
return sum;
}
// API Array
static final class API {
static final double[] m = {1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16};
double get(final int row, final int col)
{ return m[row * 4 + col]; }
}
static final API ma = new API();
static double api() {
double sum = 0;
for (int loop = 0; loop < loopTimes; loop++) {
double rvx = (ma.get(0,0) * ptx) +
(ma.get(0,1)* pty) + (ma.get(0,2) * ptz) + (ma.get(0,3));
double rvy = (ma.get(1,0) * ptx) +
(ma.get(1,1) * pty) + (ma.get(1,2) * ptz) + (ma.get(1,3));
double rvz = (ma.get(2,0) * ptx) +
(ma.get(2,1) * pty) + (ma.get(2,2) * ptz) + (ma.get(2,3));
double w = (ma.get(3,0) * ptx) +
(ma.get(3,1) * pty) + (ma.get(3,2) * ptz) + (ma.get(3,3));
sum += rvx + rvy + rvz + w;
}
return sum;
}
Submitted On 19-JUN-2001
hlovatt
Continued ...
// vecmath
static final class Vector4d {
double x, y, z, w;
Vector4d() { }
Vector4d(double x, double y, double z, double w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
double sum() { return x + y + z + w; }
}
static final class Matrix4d {
final double m00 = 1, m01 = 2, m02 = 3, m03 = 4;
final double m10 = 5, m11 = 6, m12 = 7, m13 = 8;
final double m20 = 9, m21 = 10, m22 = 11, m23 = 12;
final double m30 = 13, m31 = 14, m32 = 15, m33 = 16;
void transform(Vector4d vec, Vector4d vecOut) {
vecOut.x = (m00 * vec.x) + (m01 * vec.y) +
(m02 * vec.z) + (m03);
vecOut.y = (m10 * vec.x) + (m11 * vec.y) +
(m12 * vec.z) + (m13);
vecOut.z = (m20 * vec.x) + (m21 * vec.y) +
(m22 * vec.z) + (m23);
vecOut.w = (m30 * vec.x) + (m31 * vec.y) +
(m32 * vec.z) + (m33);
}
}
static final Vector4d rv = new Vector4d(),
pt = new Vector4d(ptx, pty, ptz, 0);
static final Matrix4d mf = new Matrix4d();
static double vecmath() {
double sum = 0;
for (int loop = 0; loop < loopTimes; loop++) {
mf.transform(pt, rv);
sum += rv.sum();
}
return sum;
}
// Test
public static void main(String args[]) {
for (int test = 0; test < testTimes; test++) {
start = System.currentTimeMillis();
result = builtIn();
finish = System.currentTimeMillis();
print("Built-in");
start = System.currentTimeMillis();
result = api();
finish = System.currentTimeMillis();
print("API ");
start = System.currentTimeMillis();
result = vecmath();
finish = System.currentTimeMillis();
print("vecmath ");
}
}
}
When run on my PC using the IBM 1.3 JVM it gives:
Built-in: 100 ms - result = 2.4E8
API : 150 ms - result = 2.4E8
vecmath : 110 ms - result = 2.4E8
Built-in: 161 ms - result = 2.4E8
API : 80 ms - result = 2.4E8
vecmath : 100 ms - result = 2.4E8
Built-in: 160 ms - result = 2.4E8
API : 80 ms - result = 2.4E8
vecmath : 100 ms - result = 2.4E8
Built-in: 161 ms - result = 2.4E8
API : 80 ms - result = 2.4E8
vecmath : 100 ms - result = 2.4E8
Built-in: 170 ms - result = 2.4E8
API : 80 ms - result = 2.4E8
vecmath : 100 ms - result = 2.4E8
As you can see wrapping the built-in arrays in a 2D API
speeds things up by about a factor of 2. The vecmath
definitions are taken from the Java3D API v1.3, therefore if
vecmath is used you would not need to write the classes
Vector4d or Matrix4d (making this version the shortest and
easiest to understand). The vecmath version is also
considerably quicker than using built in arrays but not
quite as quick as the array API (but the vecmath method is
the most realistic since it calls methods to do the
multiplication and summing). Note vecmath supports byte,
int, float, and double for small vectors and matrices (but
only double for large ones) and provides many common
operations as methods.
In conclusion, it is a fallacy to suggest that the built-in
arrays should be considered the 'best' method of coding many
problems and therefore do not provide 'good' evidence as to
why 'const' should be added to the language.
Submitted On 19-JUN-2001
andythomascramer
Cowwoc's claim that casting-away const eliminates any protection offered by const-restriction is not
correct. Though the existence of const in C++ does not protect against _mischief_, it still protects against
_accidents_.
Submitted On 19-JUN-2001
andythomascramer
If primitive arrays were deprecated, as hlovatt suggests, how would the API-based arrays be implemented?
Surely not with JNI, if they're intended to be efficient in time. How would arrays of higher-dimensionality
than supported by the API be implemented efficiently by programmers outside of Sun?
Let's move on to the strawman of casting-away-const. Hlovatt claims it's necessary for const-restricted
references, but can lead to bugs, and that therefore const-restricted references are unsafe..
I see nowhere that I've claimed casting-away-const is not necessary, but no matter -- I agree that it's not
necessary. Hlovatt claims it's necessary, but shows only that it would be useful with pre-const libraries.
"Useful" is not "necessary." Commercial Java libraries would likely be updated over time to include
const-correct interfaces; in the meantime, const-restricted references would still be useful for
application-specific code.
Hlovatt claims that casting-away const could lead to bugs, where something is modified unexpectedly.
That's true -- but casting-away const already exists in the current language, implicitly with references
intended to be const-restricted. Even the interface hack suggested by some as an emulation (i.e., doubling
the size of the class hierarchy with the addition of read/write variants of each class) currently allows
casting-away const explicitly. If hlovatt is concerned about casting-away-const, then this proposal would
help, either by not allowing such casts, or by introducing an explicit syntatic salt that can highlight the
danger.
Thus, hlovatt's strawman fails on both assertions. First, casting-away-const is not necessary for this RFE.
Second,.even if it were provided, it doesn't introduce any bugs that can't already exist in current Java -- in
fact, it would reduce the likelihood of such bugs by requiring explicit casts at compile-time.
However, this RFE does not request the ability to cast-away const. Whether it should or should not be
included is left to the language designers. I am not advocating its inclusion or exclusion.
Submitted On 19-JUN-2001
andythomascramer
Sci-agn's dismissal of this RFE relies on the misunderstanding that this RFE requests a qualifier for immutable
objects. It does not. This RFE requests a type qualifier for _references_ which restricts the operations
which may be performed through them to "const" operations.
Submitted On 19-JUN-2001
andythomascramer
Apparently, for hlovatt, more is less.
To avoid a const-restricted qualifier to array references, he suggests the introduction of API-based arrays
consisting of two classes (read and write) per primitive type per number of dimensions. Fortran77 supported
seven dimensions on arrays, but I could get by myself with four (consider a variable across three spatial
dimensions and time, for example). Let's provide Java with less functionality than Fortran 77 - only four
dimensions. Let's also presume only rectangular arrays are provided in the standard API. That's 2 * 8 * 4 =
64 classes. Oh, yeah, let's increase Java's memory footprint even more!
The JSR 000083 hlovatt cites is for the implementation of rectangular multidimensional arrays. The
performance benefit hlovatt cited is derived from the rectangular constraint, not the choice of basing it in
the API rather than the language. The same benefit would be obtained from a language-based approach.
The vecmath classes hlovatt cites are not general arrays, they are mathematical vectors and matrices. In
addition, they support only values of type double. I see no indication that they were preferred for
"performance reasons" over language-based arrays, but rather that they're the natural OO classes to
represent mathematical vectors and 2D rectangular matrices, which might be represented internally partly
by arrays -- language-based arrays. I happen to use Java3D myself, which depends on the vecmath library.
Performance is critical in Java3D, and most of Java3D uses primarily language-based arrays to represent
arrays.
Hlovatt suggests using "get" and "set" are acceptable alternatives to using the natural "[ ]" operator. My
experience as a former CS instructor has been that students would find the latter easier to understand. And
it's more readable as well. Here's part of the code I wrote to multiply a 3D point by a 4x4 transformation
matrix. The language-based version allows a readable, tabular format on 80-character lines. (Each
statement below appears on a single, separate line in the source.)
rv.x = (m[0][0] * pt.x) + (m[0][1] * pt.y) + (m[0][2] * pt.z) + (m[0][3]);
rv.y = (m[1][0] * pt.x) + (m[1][1] * pt.y) + (m[1][2] * pt.z) + (m[1][3]);
rv.z = (m[2][0] * pt.x) + (m[2][1] * pt.y) + (m[2][2] * pt.z) + (m[2][3]);
w = (m[3][0] * pt.x) + (m[3][1] * pt.y) + (m[3][2] * pt.z) + (m[3][3]);
Here's the API-based version, presuming the existence of a 2D array class for the array member type.
rv.x = (m.get(0,0) * pt.x) + (m.get(0,1) * pt.y)
+ (m.get(0,2) * pt.z) + (m.get(0,3));
rv.y = (m.get(1,0) * pt.x) + (m.get(1,1) * pt.y)
+ (m.get(1,2) * pt.z) + (m.get(1,3));
rv.z = (m.get(2,0) * pt.x) + (m.get(2,1) * pt.y)
+ (m.get(2,2) * pt.z) + (m.get(2,3));
w = (m.get(3,0) * pt.x) + (m.get(3,1) * pt.y)
+ (m.get(3,2) * pt.z) + (m.get(3,3));
(continued ...)
Submitted On 28-JUN-2001
andythomascramer
My example was provided only to show the greater
readability provided by the common array access operator []
over .get() methods.
It's obvious that rectangular arrays and hand-coded 4D
matrices will be faster than the current general-purpose
non-rectangular arrays. However, this has no relevance to
the readability issue. Further, I see no relevance to this
RFE. I will reply only to substantive remarks that have
relevance to this RFE.
Submitted On 03-JUL-2001
tbreuel
On the question of "const" methods and caching, you cannot,
in C++, assume that just because only "const" methods have
been called, the object has not been modified, even in the
absence of casts. The object's constructor may have leaked
a non-const reference to the object that is merrily being
used to modify the object behind your back.
The safe way of implementing these kinds of features is via
a "modified" flag. That flag can be implemented more
conveniently using something like AspectJ.
Submitted On 24-JUL-2001
thomas.sievers@gmx.de
Up to now, there's only the possibility to prevent a
parameter given to a method from being assigned to a new
reference by doing the following:
public SomeClass doSomething (final AnotherClass c)
But this is simply insufficient for reference types, as
they can be changed using setter methods.
Submitted On 05-AUG-2001
jdcjdc
Ugh! 'const' artificially creates two types from a given class: a mutable type
and an immutable type. The mutable object can passed as an argument to
any method, but the const (immutable) object cannot be passed as an
argument for mutable args.
Please don't import C++ warts into Java. Use something better like
'design-by-contract' instead of const.
Submitted On 10-AUG-2001
dnoyeB
Help me understand why this is necessary? If you don't
wan't your object modified, pass an interface which your
object implements. That interface should only contain
your 'const' methods.
Or
Make your methods package methods.
package xyz;
void doThis(){}
That method can only be called from within the package. I
take this to be an excellent solution. I cant think of a
reason for more, though there may be one. Please let me
know!
Submitted On 14-AUG-2001
nerd2004
Imho, C++-style const would add unnecessary bloat to the
language. However, I wouldn't mind a "const class"
construct which prevents a class from including any methods
that change its state. (Constructors are an exception, of
course.)
Submitted On 28-AUG-2001
finking
One of my few gripes with java is the lack of support for
constancy. Anybody who has got into using constancy in other
languages will know how much time it can save when the
compiler picks bugs up for you instead of you having to find
them yourself. In Java however compiler support for
constancy only works for primitive types:
final int i = 9;
i can never be changed it will always be 9 - if you try to
change it the compiler will compain.... but
final Thang thang = new Thang(parameters);
thang can be changed (assuming ObjectThang has modifiers).
The only thing the final keyword buys here is that
identifier thang will never be used to refer to a different
object, it does not stop us from changing thang.
The standard solution to this problem is to make "immutable"
classes i.e. classes which have no modifier methods. This in
itself is not enough however. It means that every instance
of the class is either constant or non constant. The
programmer has no way of declaring a constant object if the
class definiing it is not immutable.
What is needed is a scheme which allows objects to be
declared final in the same way that instances of primitive
types are. That is:
an object of a mutable class can be declared as final or not
depending on whether it should be constant or not
respectively.
methods should be able to declare an object parameter as
final or not depending on whether or not the method modifies
that object
methods that have a final object parameter should be able to
take either a final object or a nonfinal object as input
parameters
I addition, because we're dealing with objects we need the
following to be true:
subclasses must have the same properties as the parents and
be able to inherit form parents in the normal way.
The key point here is that we need the compiler to enforce
these rules. The whole point of using constancy is to get
the compiler to do some of the debugging for you.
The Solution
The simple solution to this is as follows: for every class
you write/have written, declare an interface called
YourClass_final. In this interface declare all the class's
non modifier methods. Then have YourClass implement
YourClass_final. That's all there is to it. Now if you (or
anybody else) wants to declare a constant instance of
YourClass they do:
YourClass_final myClass = new YourClass();
If they want to declare a constant parameter to a method,
they do:
public void foo(YourClass_final yc)
It really is that simple! It doesn't get any more
complicated when you add in inheritence either. Lets say you
have a subclass of YourClass called ChildClass. All you do
here is create a new interface ChildClass_final as before -
this class contains all the methods of ChildClass except for
the modifiers. The only extra thing you have to do is make
ChildClass_final extend YourClass_final. Now you can do
things like:
ChildClass_final myChild = new ChildClass();
ChildClass myOtherChild = new ChildClass();
myChild.foo(myOtherChild);
Simple!
Submitted On 28-AUG-2001
Ixchel
Oops. That example should read:
void foo(const Thing x) {
int y = x.getFoo(); // OK
x.setFoo(y); // Compiler error
}
Presumably, it uses a definition of Thing something like:
interface Thing {
int getFoo() const; // Can be called for both
const and non-const 'Thing' references
void setFoo(int x); // Can be called only for
non-const 'Thing' references.
}
Submitted On 28-AUG-2001
Ixchel
I agree that immutable classes are great, and solve many
problems. However, they are not what this RFE is about.
This RFE is about immutable-restricted REFERENCES to
classes. If someone wants to start a new RFE relating to
how to add immutable classes to Java, they are free to do
so, and could even post a link to it here so that others
can find it. I know that James Gosling has written some
papers in support of the idea, and has suggested them as a
possible solution to the "Java has no enumerated types" RFE
that is also active. But this RFE is not about that
subject. The use of the 'const' keyword (in C++) that this
RFE describes has nothing to do with guaranteeing
immutability of objects. It is about restricting the
operations that may be performed via a particular REFERENCE
to an object. That is an ENTIRELY DIFFERENT MATTER.
Sigh. I am quite concerned that the original intent of this
RFE will be lost amidst the noise of the various people in
this discussion who really don't understand it and are
posting irrelevant comments, raising irrelevant objections,
and describing irrelevant solutions based on a
misunderstanding of what is being suggested. I wonder how
many people posting here have actually worked on a project
that consistently USED const in C++. A little experience
often overthrows a lot of theory.
Also, keep in mind that the 'const' keyword in C++ serves
TWO DISTINCT PURPOSES, only one of which is being discussed
by this RFE. One use of 'const' is already handled by
Java's 'final' keyword: Namely, that of ensuring that a
particular object reference (or primitive variable) may not
be changed to point to a new object (or value). This RFE is
about the OTHER use of const, which restricts the
operations that may be performed via a particular object
reference. In other words, we are talking about:
<pre>
void foo(const x) {
int y = x.getFoo(); // OK
x.setFoo(y); // Compiler error
}
</pre>
and we are NOT talking about:
<pre>
const Thing foo = new Thing();
foo = new Thing(); // Compiler error: reference 'foo'
can't be retargeted.
</pre>
since the above is already handled by use of the 'final'
keyword.
Submitted On 28-AUG-2001
finking
Workaround
This problem has come up at our site. I posted a couple of
short articles about it on our site Java BB. The technique I
outline requires no change to the Java language syntax, but
does require the creation of new interfaces for existing
classes. This can be semi-automated. Ultimately to effect a
full solution using this technique, every class would need a
corresponding interface creating (see following posts),
which would require (backwards compatible) changes to all
classes from java.lang.Object downwards.
Finally the second part of the post goes on to describe a
stronger kind of constness (immutability), which is the kind
of const you get in Ada. This is implemented using a similar
technique.
Regards
Robert Finking
Submitted On 28-AUG-2001
finking
One of the main benefits of immutable classes is that you
know an object of an immutable class is guaranteed never to
be changed by anybody. A classic bug is as follows:
class Bar
{
final Object object;
final YourChild_final yourChild;
public Bar(final Object newObject, final YourChild_final
newYourChild)
{
this.object = newObject;
this.yourChild = newYourChild;
}
....
// Methods, which rely on object and yourChild not
changing
}
The class relies on the objects passed in to the constructor
being constant. It would appear from the definitions that
the objects can't change. However there is nothing to stop
the Bar class being used as follows:
Object black = new AnimalColour();
YourChild sheep = new YourChild();
Bar bar = new Bar(black, sheep);
Bar.method();
black.setFlashing(true);
Bar.method();
sheep.addLeg();
Bar.method();
Clearly this is not what the author of the Bar class
intended. What is needed to prevent this kind of bug (which
happens all too easily and can be very difficult to track
down) is a stronger form of constancy - immutability.
Immutability allows a method not just to state that it will
never change the parameters passed to it (which is what the
_final classes achieve), but to require that the object
passed to it is totally immutable. The only way to achieve
this at present is by having objects of an immutable class.
There is currently no way to take an object of a mutable
class and declare an immutable object of that class.
The Solution
The solution to this problem is a simple extension of the
scheme I outlined previously. The essential properties that
are needed are:
A way to declare immutable instances of mutable classes
Compile time checking that a method that accepts an
immutable object has not been passed a mutable one
Validity of either a mutable or immutable object to be
passed to a _final parameter
Again, the solution is very simple, create a new class
YourClass_immutable, which implements YourClass_final. The
YourClass_immutable class implements all the methods in the
YourClass_final interface, no more, no less. The
implementation is trivial: YourClass_immutable contains a
single instance of YourClass and does a simple call through
to that for each method, so we have:
class YourClass_imm implements YourClass_final
{
protected YourClass yourObject;
YourClass_imm(..params..)
{
this.yourObject = new YourClass(..params..);
}
int method1()
{
return yourObject.method1();
}
....
}
We are now able to declare immutable instances of YourClass!
What about inheritence? The observent ones among you will
have noticed that yourObject was declared as having
protected scope rather than private. This is so that when
you have a chlid class, the immutable child can still
inherit from the immutable parent:
class YourChild_imm implements YourChild_final
{
YourChild_imm(..params..)
{
super(new YourChild(..params..));
}
int method1()
{
return ((YourChild) super).yourObject.method1();
}
....
}
Note that there is no need to declare a YourChild member
here, since there is already a member in the parent. In an
ideal world there would be _final and _imm classes
throughout the entire java class tree, from java.lang.Object
downwards, so no _imm classes would need a member, they'd
all refer to the one in Object_imm.
Note also that you need to downcast the member in the parent
to the class you are making an immutable version of.
Sounding more complicated? This is a bit more involved than
the basic "final for objects" described in the previous
post. However the good news is that the generation of the
_imm class can be automated once the corresponding _final
class is in place.
Regards
Submitted On 29-AUG-2001
finking
To clarify my recent posts I am totally behind having
references
to constant values, which is why I've voted for this. The
workaround I presented is just that, a workaround and would
never be as good as the introduction of C++ type constness.
I thought people might be interested in the short articles
I'd written so I posted them. In hind sight it probably
would have been less confusing if I'd not included the
immutability post as that is a separate issue.
However if you read my second post, I think you'll find it
gives you C++ style constness. For the sake of those
unfamiliar with C++ you have
const Class * obj;
to mean obj is a pointer (reference) to a constant instance
of Class and
Class * const obj
to mean obj is a constant pointer (reference) to an instance
of Class
In Java final covers the second option, but not the first,
final Class obj
means obj is a constant reference to an instance of
Class. Now in C++ the meaning of the const keyword is
determined by it's position. In C++ putting it at the front
means "const object" and right before the identifier means
"const reference". In Java it's the other way around putting
final in front means it's a const reference, so to complete
the C++ constness picture all we need is to allow:
Class final Obj
Which would mean Obj is a reference to a constant instance
of Class. That's what I personally want to see and that's
why I voted for this enhancement.
However in the interim you find that the workaround that I
outlined allows you to do:
Class_final Obj
To mean the same thing. The only difference syntactically is
that you use an underscore instead of a space. Either way
though, you get C++ constness
Cheers
Robert Finking
PS To put to rest any fears you may have about my
understanding of C++ constness it's worth saying that I have
roughly the same amount of industrial experience in C++ as I
do with Java. Regards.
Submitted On 30-AUG-2001
dkf
IME, one of the most awkward things about the use of 'const'
in C++ is the way that moving it around causes it to have
different meanings. Sure you can work it out, but it makes
life quite difficult. Worse, you'd still have this
complexity in Java with multi-dimensional arrays, even if
the proportion of people bitten by it would be less.
The sole good feature of 'const' that I miss is being able
to say that a particular array reference can't be used as an
Lvalue. The neatest work-around for this is really using
design-by-contract to specify that the array reference
returned by a method cannot be modified (or perhaps rather
that an array returned this way is only ever modified in a
controlled fashion.) All the other things discussed here
(Robert Finking's suggestions in particular) won't be in the
slightest bit elegant for this case (wrapper classes *and* a
different method of access? Yuck!) though they do indicate
why the need is not pressing for the rest of the language.
On reflection, design-by-contract is probably the way to go
anyway, but more particularly as it allows the capturing of
more of the intent of the code (immutability of reference is
only one of the things you might specify with such a system)
and it need not be too closely linked with Sun anyway (as
long as they don't heave roadblocks in the way. :^)
Submitted On 30-AUG-2001
andythomascramer
The interface hack presented at length by finking has been
discussed in earlier posts. It's discussed in the very
first post, and a list of negatives are in the ninth.
>const Class * obj;
> to mean obj is a pointer (reference) to
> a constant instance of Class and
No, in C++, this means that obj is a pointer restricted to
const operations on an instance of Class. This RFE seeks
the same semantics for Java -- the ability to mark a
_reference_ as restricted to const operations.
Submitted On 16-OCT-2001
adamc
const correctness would be a real boon for java. One thing
to consider is whether more general design-by-contract
support (a la Eiffel) would be better than just
adding "const" and "mutable".
Submitted On 24-OCT-2001
Brill
I'm not a fan of the idea myself, at least not with the
reasons you give. your objects should be designed better in
the first place. I would think very carfully before adding
such a major change to the way you *think* about writing
java code.
Submitted On 24-OCT-2001
ethanleet
Keep const out. Java came from C++, but it is not C++.
C++ allows for sloppy designs and programming. Java forces
the programmer or developer to design better. Java is more Object
Oriented. Lets keep it that way.
Submitted On 09-NOV-2001
finking
We need const to
1. Mark methods as not changing internal state
2. Mark objects as only being allowed to call the methods outlined in 1 and
3. To mark whole classes (as immutable), to allow the compiler to check that an immutable class really is
immutable. At the moment you can write a class, think it's immutable but have some mutable aspect to the
class due to a mistake you've made.
4. To mark arrays as const
Regarding other recent comments, design by contract gives you run time checking. The whole point of
constness is you get the security of compile time checking - no latent bugs. Interestingly the whole theory
that DBC is based on (predicate calculus) was originally employed as a formal method, used to prove (or
disprove) program correctness. The fact that doing the manual proof offline is arduous has led to this whole
idea of runtime checking, which is a great way to keep some of the rigour (baby) whilst throwing away the
impractical proof process (bath water). However, I can't help thinking that parts of a contract might not still
be checkable at compile time. It just needs somebody to write the analysis tools and people to be prepared
to wait for them to run.
On the point about constness being a C++ idea and therefore not OO: the concept of constness is abstract
and nothing to do with C++ per se, any more than having a president is anything to do with Russia.
Constness actually makes more sense in an OO environment than it does outside of it. Why do you think
constness is anti-OO?
Andy, I agree with you. When I talk about a "constant instance of a Class", I do mean an instance from
which you can only call const methods. The class based workaround I outlined is not the same as the
schemes outlined at the start in that it addresses the need for both constness and immutability. The point
that seems to have been missed in other schemes is that you want all of the follwing:
1. You want to be able to declare a class as immutable
2. You want to be able to declare an object as either mutable, const or immutable
3. You want to be able to pass either mutable or immutable objects to a const object parameter (since both
mutable and immutable versions support the const methods)
4. You want to be able to provide a separate implementation for immutable classes since there are often
perfomance benefits to be had from taking advantage of the immutable nature of the class, however you
also need a trivial default implementation for immutable classes to avoid having to write the same class
twice (immutable and mutable versions).
Point 3 above is the one thing that worries me about the const keyword idea. There is currently no effort to
provide a parent interface that covers both mutable and immutable versions of a class. The big culprit here
is String/StringBuffer - instead of having a parent interface that covers both classes, you end up having to
create an intermediate String object whenever you want to pass a StringBuffer object into a method. If we
go down this route than I fear that we'll have to take a leaf out of String/StringBuffer's book and every
immutable/mutable pair of classes we'll have to provide explicit conversion routines. Ah well, small price to
pay eh?
Submitted On 15-NOV-2001
hwc
Finking’s comments may point towards another solution to
the problem – a const interface.
Ideally we should be able to define individual methods
const so that the compiler prevents us
from changing an object’s state accidentally but it would
be equally possible, and giver greater
backwards compatibility, to list the public methods in an
interface marked const. A const
reference to an object would use this const interface. An
immutable object would not have
any other public methods; mutable objects would.
Covariant return types would make this approach
straightforward. In many cases, it may be
possible to retro-fit existing classes with const
interfaces. I don’t know how easy it would be
to apply this approach to String/StringBuffer.
Unfortunately it doesn’t work with arrays.
Submitted On 20-NOV-2001
hlovatt
Continued from above ...
// note - final in immutable form and implements Immutable
public final class Int extends AbstractInt implements
Immutable {
// note - final in immutable form
final int value;
public Int(final int value) { this.value = value; }
// for AbstractInt
public AbstractInt create(final int value) { return new
Int(value); }
public int getValue() { return value; }
// for Immutable - return by copy
public Object toMutable() { return new MutableInt
(value); }
}
// note - not necessarily final in mutable form and
implements Mutable
public final class MutableInt extends AbstractInt
implements Mutable {
// note - not final in immutable form
int value;
public MutableInt(final int value) { this.value =
value; }
// for AbstractInt
public AbstractInt create(final int value) {
return new MutableInt(value);
}
public int getValue() { return value; }
// for Mutable - return by copy
public Object toImmutable() { return new Int(value); }
// 'set' functions - the mutable stuff
public void set(final int value) { this.value =
value; }
public void set(final AbstractInt value) {
this.value = value.getValue();
}
public void setAdd(final int value) { this.value +=
value; }
public void setAdd(final AbstractInt value) {
this.value += value.getValue();
}
}
This technique works for all classes including arrays.
Typical usage is:
public final class Test {
// note - you could program to the abstract type
(AbstractInt) but this
// would require more type conversions. Type casts
shown are not
// necessary with covariant return types, Java v1.5?
public static void main(final String args[]) {
final Int a = new Int(2);
final MutableInt m = (MutableInt) a.toMutable();
final Int b = new Int(3);
final Int c = (Int) a.add(b).add(m); // Int +
Int + MutableInt
System.out.println("c = " + c);
m.setAdd(a); //
MutableInt + Int
m.setAdd(m); //
MutableInt + MutableInt
System.out.println("m = " + m);
final Int d = (Int) m.toImmutable();
m.setAdd(m); // Check d
not aliased
System.out.println("d = " + d);
}
}
Continued below ...
Submitted On 20-NOV-2001
hlovatt
Continued from above ...
Compare this with the same functionality using const below.
The program
below is written in C++ because Java doesn't have const,
but you will get
the idea! Note 1: the Java syntax would be a little
different but roughly
the same amount of typing. Note 2: Don't do this in C++ -
no garbage
collector!
// 'set' and 'non-set' (const) operations all together
class integer {
public:
// construct from primative and integer
integer(const int value) { this->value = value; }
integer(const integer* const value) { this->value =
value->value; }
// 'non-set' (const) methods - the immutable stuff
// add to primative and integer returning copy
integer* add(const int value) const {
return new integer( this->value + value );
}
integer* add(const integer* const value) const {
return new integer( this->value + value->value );
}
// 'set' methods - the mutable stuff
// add and set to primative and integer changing self
void set(const int value) { this->value = value; }
void set(const integer* const value) { this->value =
value->value; }
void setAdd(const int value) { this->value += value; }
void setAdd(const integer* const value) {
this->value += value->value;
}
// For debugging primarily
friend ostream& operator<<(ostream&, const integer*
const);
private:
// Fields mutable because const gives immutability
// Typically there would be a large number of fields
// or a pointer to a structure
int value;
};
// For debugging primarily
ostream& operator<<(ostream& out, const integer* const
value) {
return out << value->value;
}
main() {
const integer* const a = new integer(2);
integer* const m = new integer(a);
const integer* const b = new integer(3);
// const integer + const integer + integer
const integer* const c = a->add(b)->add(m);
cout << "c = " << c << '\n';
m->setAdd(a); // integer
+ const integer
m->setAdd(m); // integer
+ integer
cout << "m = " << m << '\n';
const integer* const d = m; // or: const integer* const
d(m)
m->setAdd(m); // Oops, d
aliased
cout << "d = " << d << '\n';
}
Comparison of techniques:
1. Comparing the two 'mains' we see little difference
between having and
not having const in terms of the required typing.
2. The problem with introducing const is that we introduce
a subtle bug,
you can alias the constant version and it can change! See
last three lines
of the two 'mains'.
3. As noted by Finking the immutable form is likely to be
quicker than the
const form.
4. The immutable form is thread safe, const isn't because
of aliasing to a
non-const version.
Conclusion:
Canvas for immutable keyword, as suggested by Gosling, and
not for const
keyword!
Submitted On 20-NOV-2001
hlovatt
You can get the behaviour requested by Finking using an
abstract base
class and deriving from it an immutable class and a
companion mutable
class. EG
public interface Immutable {
// Convert to mutable by copying!
Object toMutable();
}
public interface Mutable {
// Convert to immutable by copying!
Object toImmutable();
}
// No 'set' Operables in outer class and therefore immutable
public abstract class AbstractInt {
// no fields because immutable inner class needs final
values and
// mutable non-final
// abstract methods that mutable and immutable forms
must implement
public abstract AbstractInt create(final int value);
public abstract int getValue();
// add to primative and AbstractInt that are common
// to both mutable and immutable forms. Not final to
// allow overloading for performance reasons if
necessary
public AbstractInt add(final int value) {
return create( getValue() + value );
}
public AbstractInt add(final AbstractInt value) {
return create( getValue() + value.getValue() );
}
// For debugging primarily, therefore not final
public String toString() { return Integer.toString(
getValue() ); }
}
Continued below ...
Submitted On 23-NOV-2001
finking
hlovatt, you first paragraph and hwc, your second paragraph,
capture exactly what I was intending to convey in my orginal
posts. I wish I could have put it so succinctly in the first
place!
One extra point in favour of getting this added to the
language is speed, in addition to my previous 4 points, we
need a const keyword so that:
5. accessors in immutable objects can avoid making defensive
copies - thus saving (a potentially huge amount of) time.
This means immutable objects can finally shed the only ugly
thing about them.
Submitted On 26-NOV-2001
hlovatt
Point 5 added by Finking is a very good point - I wish I
had included it in my original list!
Submitted On 11-JAN-2002
streissel
Const parameters is really a needed feature.
For example most of the get functions should be able to
return const. Most of the set functions should take const
parameters.
Please add const parameters!
Submitted On 19-JAN-2002
cfmdobbie
I have to vote for this, even though I acknowledge the
added complexity and changes to the current libraries that
would be required. Currently I don't feel happy returning
from a function any object that isn't mutable, due to
possible abuse by the user of said function. Some kind of
const mechanism would put another layer of safety in front
of my business applications, and help to ensure they
function correctly.
Submitted On 22-JAN-2002
hlovatt
I have suggested an alternative, see RFE 4617197, which I
think gets over the problems of a C/C++ style const
specifier. In particular the syntax is cleaner, you can't
accidently cast away const, but you can still convert
between mutable and immutable (const) forms.
Submitted On 08-FEB-2002
shrink_laureate
(continued...)
SOLUTION
Existing code is unaffection; the 'const' keyword should be
left well alone, because it's inherently confusing. Three
keywords should be added:
"readonly" : marks a reference as not being allowed to
modify an object.
"writable" : explicit cast to assign a readonly reference
to a writable reference.
"safe" : when used on a method, indicates that it will
not change the object's state. A safe method may not set
any values, or call an unsafe method. When used on a
member, indicates that it will be considered readonly
inside all safe methods. When used to modify an interface,
forces that all methods on that interface must be safe.
"notnull" : because i feel like it. marks a reference as
having to contain a real value
Code using this would look something like:
class Thingy {
Foo foo = new Foo();
public safe readonly Foo peek()
{ return foo; }
public void poke(readonly Foo newfoo)
{ foo = newfoo; }
public void plonk(Foo newfoo)
{
}
class Doodad {
readonly Thingy thing = new Thingy();
public void doFoos() {
// these lines are fine
readonly Foo myfoo = thing.peek();
thing.poke(myfoo);
// these are ok as well
Foo myfoo2 = (writable) thing.peek();
thing.poke(myfoo);
// these lines generate errors
Foo myfoo3 = thing.peek();
thing.poke(myfoo);
// so does this line
thing.plonk(myfoo);
// but this one is ok
thing.plonk((writable) myfoo);
}
}
As I hope you can see, those changes to the code doesn't
add any great complications to the Java syntax, or
undermine the language's security. A method can have both
safe and readonly modifiers: safe indicating that it
doesn't change the members, and readonly to indicate that
it returns a read-only reference.
As described above, a safe method could still modify the
contents of a non-readonly member. By marking the member as
safe, it inherits the behaviour of the current method -
hence a safe method sees a safe member as if it were
readonly, while an unsafe method sees it as a normal
writable member.
There is a confusion left between a readonly array, and an
array whose members are readonly. Sadly, there only option
I've seen here is the kludge suggested by andythomascramer:
readonly Foo[] x; // you may not write into the array
Foo[ readonly ] x; // you may not write into each member
If anyone can think of a better solution to the last
problem, let me know. If we can agree on a proposal similar
to that, I'll be prepared to vote for this.
Submitted On 08-FEB-2002
shrink_laureate
One final note: this is not Design by Contract, and it
doesn't pretend to be. However, it does inch Java ever so
slightly more in the direction of it, by allowing a small
subset of invariants to be stated in code. In this
respect, the notnull keyword is as important as this RFE.
Submitted On 08-FEB-2002
shrink_laureate
The idea of a read-only reference is a nice one, in that it
makes implicit assumptions explicit, and lets you use the
compiler to prevent mistakes. But to inherit all, or even
any, of the syntax from C++ is a mistake.
Unless i'm stupid and blind (you'll get your chance to
argue this in a minute), the idea being proposed is:
1. A reference may be flagged as "read-only". You cannot
use this reference to write to the object, and you cannot
assign it to an ordinary (writable) reference without an
explicit cast. This does not prevent the object from being
changed from elsewhere.
2. To enforce this, methods are flagged as either non-
modifying and safe to use, or modifying and unsafe. The
compiler will prevent you from using unsafe methods.
3. The body of a non-modifying method believes that 'this'
is a read-only reference, and enforces rules 1 and 2 on it.
4. All of this is checked at compile-time, not at run-time.
This is a good possibility, and as far as i can see a type-
safe way of programming. For the time being i'm leaving
aside immutable classes and objects, because they have
their own RFE (4617197). When deciding on syntax for this,
it should follow these rules:
1. It should not have any harmful effect on existing Java
code. Hence, the meaning of keywords like final, transient
etc should remain unchanged.
2. It should not undermine the existing Java security
model, allowing dangerous code to be written.
3. It should not undermine the current Java syntax. In
particular, C++ uses syntactic tricks involving the
position of the const keyword which do not fit into Java.
A Java method looks like this:
<modifiers> <return type> <name> '(' <arguments> ') {'
<body> '}'
The modifiers may be in any order, even if convention
places them in a certain order, and there are no modifiers
between the return type, name, arguments and body. This
will not and should not change - if you want to compromise
this, give up now. Specifically, you will never get
methods that look like this:
int g(int x) const { }
or this:
int const g(int x) const { }
Because their meaning is not clear. A variable declaration
looks like this:
<modifiers> <type> <name> [ '=' <initial value>];
Again, the modifiers may be in any order but may not appear
between the type, name and initial value. Again, this will
not and should not change. You will never get code like
this:
int[] const x;
or this:
int[] x const;
Submitted On 11-FEB-2002
Ixchel
In general, I think that shrink_laureate proposal (see
previous message) is a good one. Some comments on it:
1) I don't like the keyword 'safe', because I think it is
too vague. ("Safe" in what fashion?) I think naming it
something like "nonmutating" or something with similar
meaning would be better. Or, if you were to apply my
suggestion to use symbols instead of keywords (see below),
you could instead use the keyword "readonly" for this
purpose, and use the "@" symbol for the purpose that
shrink_laureate uses the "readonly" keyword for.
2) I heartily approve of the "notnull" keyword he suggests.
I'm REALLY tired of writing code that says essentially "if
(foo==null) throw new IllegalArgumentException(whatever)".
IMHO, this should be prevented at compile time, not runtime.
3) As for the arrays problem, I suggest that in general, in
Java, declarations are built from left to right (ignoring
for the moment the C++-inherited abomination that allows
declarations like "int i[]"). Normally, declarators are
unary operators that apply to whatever is immediately to
the left of them. For instance "int []" is an array of int,
and "int [] [] " is an array of "array of int". As such,
the logical place for a "readonly" keyword to go would be
to the right of the item it modifies. Therefore, we would
have:
int readonly x; // a read-only int
int readonly [] x; // An array of readonly ints
int [] readonly x; // A readonly array of ints
int readonly [] readonly x; // A readonly array of
readonly ints.
Since this syntax can get a bit verbose, it might be
preferable to use some kind of symbol instead of a keyword.
I'd suggest "&" for "notnull" (this is loosely analogous to
C++ usage of reference types, which are never legally
null), and "@" for "readonly". Thus we would have:
Foo @ x; // a read-only Foo object
Foo @ [] x; // An array of readonly Foo objects
Foo [] @ x; // A readonly array of Foo objects
Foo @ [] @ x; // A readonly array of readonly Foo
objects.
Foo & x; // A non-null Foo object
Foo [] & x; // A non-null array of Foo objects
Foo & [] x; // An array of non-null Foo objects
Foo & @ [] & @ x; // A non-null readonly array of non-
null readonly Foo objects.
Foo @ & [] @ & x; // Same as above.
Submitted On 12-FEB-2002
shrink_laureate
No offense, Ixchel, but using symbols like & and $ and @
doesn't feel at all right. It doesn't feel like Java, it
feels like Perl. Not to mention that it doesn't explain
what the purpose of it is unless you have already learnt
it, leading to lots of newbie mistakes.
I'm not entirely happy with the word "safe" either, but
it's a tough concept to describe. "nonmutating" would be a
good choice, but I'm always open to ideas. In either case,
it should definitely be a keyword modifier, not a symbol
format.
I don't think I've quite sorted out the ordering of arrays
yet, but I do have one rule to apply: any modifiers go
*before* the type, always have done in Java. That means
the standard case must be:
readonly Foo x; // x is a read-only foo
readonly Foo[] x; // x is a read-only array
With the entire array's modifiers on the far left, smaller
modifiers should go somewhere in the middle. The options
are:
Foo readonly[] x;
Foo [readonly] x;
Foo[] readonly x;
Submitted On 13-FEB-2002
shrink_laureate
Hey, I hope you guys at Sun are reading this!
Submitted On 13-FEB-2002
shrink_laureate
> RFE 4617197 covers immutable arrays, not null, and has
> clean syntax ;)
Err... not really. They're different questions entirely.
As the RFE states, it's a difference between making all
instances of a class immutable, and making a single
reference read-only.
I don't like 4617197 because it suggests that inheriting an
interface gives your class different compile-time
behaviour, which is just... wrong. To push that to even
preventing null being assigned to a known immutable type is
utterly twisted. Besides, what if i don't want to make my
class permanently, irreparably immutable just to prevent
one instance from being null? Or say I want to make sure a
reference to somebody else's object isn't null? It really
isn't a solution.
Should I start an RFE for a notnull keyword? Would that
help things, or swallow important votes from other
subjects? Or just be ignored and forgotten?
Submitted On 13-FEB-2002
shrink_laureate
> the kinds of modifiers we are talking about here
> are actually type specifiers, used to construct complex
> types from more simple ones
I think i'm starting to see your point. If i can
paraphrase you, you're saying that the ordinary modifiers
are for external characteristics of a reference, such as
its visibility, while these codes are for its type, which
is a separate element.
The problem is that Java's types aren't that dynamic, so I
didn't instantly see the difference. Arrays in particular
have a syntax that's almost designed to prevent any
flexible modifications of the type.
There are languages that have very dynamic types, but lose
out on the type-safety, such as SmallTalk and ObjectiveC.
If I have one disadvantage on this subject, it's that I
don't know Eiffel, so one of the major points of reference
is missing.
So... how to create a syntax that clearly shows that they
modify the type, without being utterly confusing for
newcomers, and without breaking too many existing Java
rules.
I'm still resisting the use of @ $ & symbols, because I've
seen the effect that they had on C and Perl code.
Especially forbidden are & and *, because Java is still too
close to C to be free of its confusing influence.
The only thing that springs to mind is to use the generic
operators < > to show that this is a dynamic type:
<readonly Thingy> myThingy;
private <notnull readonly Doodad> myDoodad;
final <nonmutating Map<Thingy, readonly Doodad>> myMap;
But most people would get tired of typing the brackets so
often - and i still don't know what to do with the arrays.
*sigh* if anyone has an answer, that doesn't involve the
use of symbols, feel free to chip in!
(ps - to anybody who has more interesting things to do with
their life than learn every programming language under the
Sun, I'm sorry if this post sounded elitist at all. if you
feel you have a solution, but don't have all that
background in other languages and theory and stuff, feel
free to suggest it - you could prove us all to be idiots.)
Submitted On 13-FEB-2002
hlovatt
RFE 4617197 covers immutable arrays, not null, and has
clean syntax ;)
Submitted On 13-FEB-2002
Ixchel
Yes, but RFE 4617197 doesn't allow me to have both a not-
null and a nullable reference to the same type. It also
provides no clean way to pass a mutable object to a
function that promises not to modify it. As such, it's not
an adequate replacement for 'const' (although I think
immutable objects as described in RFE 4617197 are useful
for other things).
As regards shrink_laureate's comment of:
>I don't think I've quite sorted out the ordering
>of arrays yet, but I do have one rule to apply:
>any modifiers go *before* the type, always have
>done in Java.
Hmm. Can't agree with you on that one. Apples and oranges,
really. Modifiers like 'static', 'final', etc. apply to the
VARIABLE, not to the TYPE of the variable. As such, putting
them at the beginning of the declaration is consistent.
However, the kinds of modifiers we are talking about here
are actually type specifiers, used to construct complex
types from more simple ones. They aren't analogous to the
modifiers that specify the duration, location, or
visibility of the variable (static, final, public, etc.)
that is declared of that type.
shrink_laureate, I think that your preference for using
keywords for these is confusing you into thinking that
these keywords are in some sense equivalent to other
keywords because, well, they're keywords. In fact, "const"
and "notnull" used in this fashion are much more similar to
constructs like "[]" than they are to constructs
like "final" or "static" which apply to the variable
itself, rather than to its type. Hence my willingness to
use symbols for them. I don't mind not using symbols, but
if symbols aren't used, we should still keep in mind that
the behavior of these constructs is semantically similar to
places that symbols ARE used in Java.
Placing things at the front of the declaration only makes
sense for things that can only occur once in the
declaration, and "[]", "readonly", and "notnull" don't fall
into this category, all for essentially the same reason:
they must make clear which part of the type they apply to
by their position. Remember, with the generics proposal in
place, types can get quite complicated: "List<Integer
readonly [] readonly> readonly" and such. Having a special
case for the placement of the first keyword, but not for
the rest of them would get rather confusing, IMHO.
After having dealt with this problem in C++ for years, I
can report that it is highly confusing, both to newbies and
to advanced programmers. I have met relatively few C++
programmers who can correctly explain the meaning of "const
int * x;" versus "int const * x;" versus "int * const x;",
and this is largely due to the confusing inconsistency
between the placement of 'const' in simple cases as versus
complex ones.
Note that the frequent usage of the syntax "const int x;"
in C++ is somewhat of a historical accident -- people
started doing it that way, and the habit got formed. The
syntax "int const x;" is actually also legal and means
exactly the same thing, and is furthermore much more
consistent with the use of more elaborate constructs such
as "int const * const * const" (a constant pointer to a
constant pointer to a constant integer). Also note
that 'const' and 'volatile' are the only type constructors
in C++ that are represented by keywords instead of symbols.
[The other type constructors include things
like "()", "[]", "&", and "*"] This inconsistency
frequently confuses people.
Submitted On 13-FEB-2002
kriff
Forgive me if this has been mentioned before. I don't have
time to read all of the comments.
I'm not a C++ programmer, but I've read some articles about
problems with the const keyword in that language. IIRC, the
biggest problem was that most methods need to be overloaded
with const and non-const versions, which leads to an
explosion of duplicate methods. I think C++ introduced a
way to cast a const to a non-const but that somewhat
defeats the purpose of the const keyword.
I've been toying with an idea that involves marking
references as 'const' at runtime, rather than compile time.
If an attempt is made to modify an object via a const
reference then an exception would be thrown.
I haven;t worked out a syntax yet or all the semantics, but
I expect it would work something like this:
Foo f = new Foo();
Foo fc = (const) f;
f.field = 123; // OK
fc.field = 123; // Runtime exception
f.modify(); // OK
fc.modify(); // Throws a runtime exception from the body
of the method
The advantage of this approach is that existing APIs don't
have to change to benefit from the new syntax. Methods
don't have to be marked 'safe' because the 'this' reference
would carry the 'constness' information. No special syntax
is required for arrays. Simply cast each element as you add
them to the array, or cast the array reference itself.
There are some disadvantages, I will admit. This approach
incurs a check for the 'constness' of a reference each time
it is used. It also doesn't prevent an object from being
modified elsewhere. However, this last problem goes away if
you view 'constness' as the permission to modify an object,
rather than a guarantee of immutability.
Submitted On 14-FEB-2002
hwc
Woops; sorry; repeat posting.
Thanks for your clarification, shrink_laureate, re. notnull - the mechanism you propose sounds similar to that
already used to check that variables marked as final are properly initialised. I wonder if it would allow us to
go the whole way and define array elements as final too?
I agree that there's no ideal answer to the problem of legacy code but my fix would be rather different. A
compiler would need to be able to check that methods marked as 'safe' really were and complain if they
weren't. It would also need to record that in the compiled class file. I'd add a switch to the compiler to tell
it to mark all such methods safe, even if the author had forgotten to do so. To aid the transition, I'd add
another compiler switch that allowed you to pass 'readonly' references to unsafe code - you'd get a warning
message but if you chose to ignore it…
I suspect you could make similar transitional arrangements for your 'notnull' proposal.
Submitted On 14-FEB-2002
shrink_laureate
> I wonder if it would allow us to go the whole
> way and define array elements as final too?
Thingy [final] doodads;
Now that's a nice idea! hwc, you are a mine of good
suggestions.
> my fix would be rather different... I'd add a
> switch to the compiler to tell it to mark all
> such methods safe, even if the author had
> forgotten to do so.
Or possibly nitro-glycerine. This is bad, bad, bad.
Just because the version of a class that you have access to
behaves in a notnull-safe or readonly-safe manner doesn't
mean that a future version of it won't. You can't trust
the innards of a class, only its interface - especially
when it was written by somebody else. Unless a method's
argument states that it is nonmutating, it could always
change without notice.
An equally important, but less technical reason, is that
developers *should* state such things in the interface.
Only assigning to a variable once isn't as good as making
it final, because when you look at the variable and *see*
that it's final it stops you from breaking that without
thinking. It also lets the compiler stop you from making
similar mistakes.
Developers make assumptions when they code, about what can
be null, what can be changed where, etc. Putting those
assumptions into the code itself is good for code safety,
and good for developer stress levels. To make it clear
what this really means, imagine debugging in a language
where every pointer was just a pointer to *something* - and
you had no idea what it was.
Submitted On 14-FEB-2002
shrink_laureate
4617197... oh, the immutable types one. our nemesis.
gotcha.
Casting as Writable
-------------------
I don't like the casting back to writable either, hwc, but
it sadly needs to be there. In an ideal, perfect language
that has always had complete support for all forms of
Design by Contract (that's Eiffel, if you believe them),
you shouldn't need it. Unfortunately, there's a lot of java
legacy code, including the entire set of core libraries,
that won't use it.
Consider this case:
readonly Object a = ...;
readonly Object b = ...;
if ( a.equals(b) ) ...;
We all know that Object.equals() does not change its
argument in any way. However, its signature in Object is:
public boolean equals (Object other);
You see, it's argument is writable. So passing a readonly
value like b into the method would bring up an error and be
utterly undoable unless there was some way that we could
cast back. The options are to automatically make it
unsafe, which would utterly destroy the point of the whole
mechanism, or to ask the user to make conscious effort to
cast it. At least it can't happen by accident.
a.equals((writable) b);
If you have a better solution to the legacy problem (or
just as often, the 'somebody else's badly written code'
problem), please share it.
Assigning Not-Null Values
-------------------------
As for the tricky cases of assigning notnulls, my intention
is that the compiler would be intelligent enough to know
when something cannot be null. If there is a known factory
method that the compiler can scan and make sure always
returns a real value (or throws an exception), it will
allow the assignment.
Your array example is a little confusing, because to define
an array you must always give its size. However, i see
your point. Using notnull does restrict your creativity
when creating these things: you need to be sure what you're
doing.
The fact is, much of the time you would not be assigning
from new values; you would be assigning an existing array
to the new reference.
Object[] temp = new Object[number];
// ...build the array...
notnull Object [notnull] array = temp;
The compiler would need to analyze the code for building
the array, to ensure that it leaves absolutely no gaps
whatsoever. But the fact is, that would be a pretty rare
condition. Most of the time, your code would be along the
lines of:
notnull Object [notnull] array = list.toArray();
This would, of course, make a lot more sense with generic
programming. :-) And don't forget that the variable isn't
necessarily created on the same line as its declaration -
as long as it does get created soon.
notnull Object [notnull] array;
array = list.toArray();
Syntax
------
You know, Ixchel, I'm feeling a lot less flexible that I
was. Especially seeing the ease with which hwc described
his question. I think keywords like that are fine, as long
as they're grouped with the type rather than mixed together
<modifiers> <type> <name>;
private static ... notnull Thingy [notnull] ...
myThingies;
protected ... readonly Hashtable <String, notnull
Thingy> ... myHashtable;
Beyond preference, can you really see anything wrong with
that?
Submitted On 14-FEB-2002
hwc
Thank you, shrink_laureate. Your proposal is almost enough to get me to switch back to this RFE from
461797 but then you spoil it by allowing people to cast away const with 'writable'.
I like your 'notnull' idea but I'm not sure how it would work in practice without run-time checks. For
example:
notnull SomeObject var = SomeObject.factoryMethod();
Perhaps factoryMethod() needs to be flagged as notnull, too.
public void someMethod( notnull SomeObject arg1 ) { … }
OK if you pass a nonnull variable but what about a more complex expression. Do all methods that return
objects need to be flagged as notnull?
notnull SomeObject[ notnull ] array = new SomeObject[];
Fails to compile, I assume; how do you initialise the array? It would work in C++ because the default
constructor is called for each element.
Somehow there needs to be a way to pass collections of objects from one method to another safely and
efficiently. These RFEs get us closer but I'm still waiting for the perfect proposal.
Submitted On 14-FEB-2002
hwc
Thank you, shrink_laureate. Your proposal is almost enough to get me to switch back to this RFE from
461797 but then you spoil it by allowing people to cast away const with 'writable'.
I like your 'notnull' idea but I'm not sure how it would work in practice without run-time checks. For
example:
notnull SomeObject var = SomeObject.factoryMethod();
Perhaps factoryMethod() needs to be flagged as notnull, too.
public void someMethod( notnull SomeObject arg1 ) { … }
OK if you pass a nonnull variable but what about a more complex expression. Do all methods that return
objects need to be flagged as notnull?
notnull SomeObject[ notnull ] array = new SomeObject[];
Fails to compile, I assume; how do you initialise the array? It would work in C++ because the default
constructor is called for each element.
Somehow there needs to be a way to pass collections of objects from one method to another safely and
efficiently. These RFEs get us closer but I'm still waiting for the perfect proposal.
Submitted On 15-FEB-2002
hlovatt
Hi, even though I support the immutable RFE 4617197 and
would like to vote against this RFE (if negative votes
were possible ;) ), I can think of a solution to many of
the const_casts (writable casts) that it has been
suggested would be needed.
Const_cast
----------
The situation re. const_casts isn't as bad as you make
out. Using C++ style notation (readonly suggestion
probably better but people are less familiar with it), and
taking the standard class Date as an example, if Date were
re-written (see aside below) to use const it would become:
public class Date {
private long time;
public Date(final long time) { this.time = time; }
public long getTime() const { return time; }
public void setTime(final long time) {
this.time = time;
}
// Rest
}
The compiler could split this into two classes, like it
currently does for inner classes. Generating:
public class Const$Date {
protected long time;
public Const$Date(final long time) {
this.time = time;
}
public long getTime() { return time; }
// Rest of const methods
}
public class Date extends Const$Date {
public Date(final long time) { super(time); }
public void setTime(final long time) {
this.time = time;
}
// Rest of non-const methods
}
Then everywhere you write 'const Date' the compiler
substitutes Const$Date. You can then write:
Object a = new const Date(1);
Object b = new const Date(2);
boolean equals = a.equals(b);
Note there is no const_cast and a and b are const views of
a Date object. A const_cast where needed wouldn't need
special notation, you would simply cast to Date.
This begs the question, why bother with special const
syntax. The people who wrote Date (and anyone else who
wants a const view) can trivially, as it stands at the
moment, split a class into a const part and a non-const
part.
Submitted On 15-FEB-2002
hlovatt
Aside
-----
I think you have to re-write a class to mark methods as
const and arguments as const. I can't convince myself that
the compiler can do this automatically. Presumably
everyone else is of this view and hence all the syntax
suggestions of how to do this.
Unfortunately re-writing classes is unlikely to happen
(there is such a small advantage), so even if you had a
const keyword it wouldn't be much use. EG if Date wasn't
re-written and you were allowed to say:
const Date cd = ...;
you would have to say
l = ( (Date) cd ).getTime(); // (Date) is a const_cast
because getTime isn't marked as const in Date. Also you
would often, even using my proposal, still have to const
cast when passed as an argument to many methods.
Immutable
---------
I used to use the above const view idiom (pattern) in my
code until I discovered that immutable types were much
better (you don't get aliasing). Presumably James Gosling
knew how much better immutable types are all along, that
why he wrote String and StringBuffer and didn't make
String a const view of a StringBuffer. Now that I
appreciate immutable types I write:
public abstract class AbstractDate {
public abstract long getTime();
}
public final class Date extends AbstractDate
implements ToMutable {
private final long time;
public Date(final long time) { this.time = time; }
public long getTime() { return time; }
public Object toMutable() {
return new MutableDate(time);
}
}
public class MutableDate extends AbstractDate
implements ToImmutable {
private long time;
public MutableDate(final long time) {
this.time = time;
}
public long getTime() { return time; }
public void setTime(final long time) {
this.time = time;
}
public Object toImmutable() { return new Date(time); }
}
This begs the question, why did I bother to ask for RFE
4617197, I already essentially use immutable types using
the above idiom (pattern). Because, if immutable types are
compiler and JVM supported then we get many optimizations
that aren't currently possible. This will lead to a
smaller memory footprint and faster running. Also the
compiler can automatically write clone, readresolve, etc.
These are considerable advantages, whereas const simply
saves a couple of lines when you define a class.
Submitted On 18-FEB-2002
shrink_laureate
There you go again, confusing us with immutable classes.
They're very different concepts.
A const reference isn't a different sort of object from a
normal reference. What it represents is a promise: I
promise not to change this object. I promise that I will
not generate any side effects you weren't expecting. I
promise that calling this method is harmless.
You see the difference? It isn't the object that's
different. It's what a section of code is allowed to do to
it. Different concepts.
And I can't think of any more messy solution than
generating 3 or 4 extra classes for each of these I want to
do. It's supposed to by dynamic!
Submitted On 20-FEB-2002
jessh
If not for the fact that I've used all my votes on more
near-term pressing concerns (like 4466510 and 4267080), I'd
vote for this.
After the lack of generics (which, of course is being
addressed), this issue leads the list of "lost
functionality" in moving from C++ to Java. "const" allows
compiler checking of a whole level of intent and usage that
Java compilers cannot check -- because the language
provides no means for the author to convey such intent.
[Of course I want interfaces to allow default method
implementations in terms of other interface methods (i.e.
no extension to field usage beyond the current) too....]
Submitted On 21-FEB-2002
shrink_laureate
public Thing[] getStuff() {
return mStuff;
}
Right now, this is utterly unsafe - the client could change
the array.
Workarounds:
1. copy the array - slow at runtime, especially if it's
big.
2. write a special ImmutableThingArray class - extra
pointless work.
Submitted On 21-FEB-2002
shrink_laureate
Ixchel elightened me with:
> Or, put another way, this
> phrase, "dynamic type", already has a meaning that I
> suspect you don't intend. Dynamic types are ones that can
> change at runtime.
You mean, that the object itself is actually turned from
its own type into another type? Adding, removing and
mangling fields as you go?
Well, you learn something every day. (At least, you try
to.)
> The 'const' implementation in C++, and
> presumably the 'readonly' and 'notnull' ones in Java,
would
> strictly involve static (non-dynamic) typing of
references.
> The actual types of objects that those references
reference
> at runtime would be somewhat dynamic (polymorphic, that
is
> restricted to only types inherited from the type of the
> reference), but this does not change the fact that Java
is,
> absent casting, basically a strongly-typed, and hence non-
> dynamically-typed language.
> ... &c. ...
Yup, that makes sense. I think you and I, Ixchel, agree on
everything except syntax.
hlovatt countered with:
> If you dislike classes so much why do you do OOP?
Huh?
I love classes. I love OOP. What I love most about OOP is
that every single class has a real, conceptual meaning.
You have a class for each conceptual object, no more, no
less. You don't have a dozen extra versions of the same
class laying around just in order to pretend you have
better type-safety than you do.
> Regardless of how a compiler might implement a const view
> and regardless of the syntax used, a const view can be
> thought of as inheritance.
Yes... except that it's an inheritance that is totally
separate from the inheritance of the real classes.
When I design classes, I want to write my code in a way
that fits in with what I think the class is for. That
means that I have my own ideas about the shape of
inheritance. I don't want to have to mangle my entire
class tree to fit in with a specific way of using those
classes.
If the tree has to be mangled, and classes end up different
in bytecode, that's the compiler's job. My job is to
understand the system I'm trying to write, and write
classes to model it. And as far as my personal
understanding goes, constness is not a property of the
object, but of the reference to it. Immutability is what
you get when you apply constness to the object itself, and
that's something different.
The beauty of OOP is how it helps me to understand the
system. I don't want to sacrifice that whenever I require
constness.
> Think of a Java, not C++, example that uses per object
> syntax that cannot be done, syntax aside, with
inheritance
> or using final, i.e. something that cannot currently be
> done.
Think of something that can't be done on a Turing Machine!
Submitted On 21-FEB-2002
hlovatt
In response to shrink_laureate
Trivial response ;)
-------------------
If you dislike classes so much why do you do OOP?
Considered response
-------------------
These statements below describe a const view an object,
referred to as const x, and a non-const view of an object,
referred to simply as x.
1. x ''is a'' const x
2. Anywhere I can write const x I can write x
3. The description of x ''promises'' that I can do
everything with an x that I can do with a const x
4. x ''extends'' const x
5. x ''inherits'' all the properties of const x
They are of course all different ways of saying the same
thing, that const x only allows me to view the state of an
x object and not change it (whereas x allows me to view
the state and change it). But the statements also describe
an object relationship, i.e. x ''inherits/extends'' const
x. Therefore a const view can be considered a type of
inheritance, even if the syntax is different.
Regardless of how a compiler might implement a const view
and regardless of the syntax used, a const view can be
thought of as inheritance. I find grouping operations
together into classes useful. That's why I like OOP. But
grouping objects into classes inevitable means having
classes, more than one. It is not my aim to reduce the
number of classes. Quite the opposite I want more classes,
more tightly focused. This is a divide and conquer
approach. Lots of easily understood little classes. I
think Grady Booch said ''if something is too complicated -
make more classes''.
Challenge
---------
Think of a Java, not C++, example that uses per object
syntax that cannot be done, syntax aside, with inheritance
or using final, i.e. something that cannot currently be
done.
Submitted On 21-FEB-2002
Ixchel
shrink_laureate wrote:
> Ixchel wrote:
>> the kinds of modifiers we are talking about here
>> are actually type specifiers, used to construct complex
>> types from more simple ones
>
>I think i'm starting to see your point. If i can
>paraphrase you, you're saying that the ordinary modifiers
>are for external characteristics of a reference, such as
>its visibility, while these codes are for its type, which
>is a separate element.
Yes, that is a correct statement of my point.
>The problem is that Java's types aren't that dynamic, so I
>didn't instantly see the difference. Arrays in particular
>have a syntax that's almost designed to prevent any
>flexible modifications of the type.
Er.. I think this is an incorrect use of the word "dynamic"
as applies to types. Or, put another way, this
phrase, "dynamic type", already has a meaning that I
suspect you don't intend. Dynamic types are ones that can
change at runtime. The 'const' implementation in C++, and
presumably the 'readonly' and 'notnull' ones in Java, would
strictly involve static (non-dynamic) typing of references.
The actual types of objects that those references reference
at runtime would be somewhat dynamic (polymorphic, that is
restricted to only types inherited from the type of the
reference), but this does not change the fact that Java is,
absent casting, basically a strongly-typed, and hence non-
dynamically-typed language. (There are some exceptions to
this, but they mostly involve casting and/or reflection).
In a strongly statically typed language, most type usage
errors can be detected at compile time, rather than at
runtime. This increases efficiency of the running code,
finds errors earlier, and has a variety of other benefits.
Contrast this with, say, Smalltalk, in which it is possible
to call a method on an object, only to find out at runtime
that "there is no definition for that method when called on
the type of that object". In Java this can't happen,
because all such errors are caught at compile time.
Anyway, to make your above point with slightly different
terminology, the issue is simply that Java's typing system,
while just as statically typed as that of C++, happens to
provide fewer ways to construct types from simpler types
than C++ does. In particular, it really provides only one
such way: the "[]" syntax. (When Generics are added to the
language, a few more options will appear.)
As an unrelated aside, personally, if I were designing the
language, all references would be
implicitly 'final', 'readonly', and 'notnull' unless
declared otherwise. (I'd have 'mutable' and 'nullable'
keywords instead). I think its a weakness in Java that you
currently have to take special steps and invoke more
verbose syntax to ADD safety, instead of having to take
special steps to REMOVE it.
Also, as far as the comments that "it would be a huge
amount of effort to make the libraries const-correct", I
would note that yes, it is, and that nonetheless, exactly
such an effort was taken when 'const' was added to C++. So,
it's a large effort, but not without precedent. As a
temporary workaround, it might be nice to be able to mark
certain packages (e.g. JDK packages) as being not const-
correct (via a compiler command-line option?), so that new
code could call them (unsafely) without using huge numbers
of casts.
Submitted On 22-FEB-2002
davidtribble
I did not specify an explicit syntax for const declarations, but this can be
deduced from my code examples.
One sticky issue remains, though, which is how to declare const arrays
(or to be precise, arrays of references to const objects). A few
possibilities:
const T[] a; // Array of const T
const T a[]; // Array of const T
This is the simple case. Reference variables 'a' and 'a[i]' are modifiable,
but the referrent object of 'a[i]' is not. Thus 'a = b' and 'a[i] = x' are okay,
but 'a[i].poke()' is an error.
const T[][] b; // Array of array of const T
This is trickier. Variable 'b[i][j]' is modifiable, as is 'b[i]', and also 'b', but the
referrent object of 'b[i][j]' is not.
const T[const][] c; // Const array of array of const T
-or-
const T const[][] c; // Const array of array of const T
Variable 'c' is modifiable, but variable 'c[i]' is not. However, variable
'c[i][j]' is modifiable, but its referrent object is not.
const T[][const] d; // Array of const array of const T
-or-
const T[] const[] d; // Array of const array of const T
Variable 'd' is modifiable, as is variable 'd[i]'. However, variable 'd[i][j]' is
not modifiable, nor is its referrent object.
T[const][const] e; // Const array of const array of T
-or-
T const[] const[] e; // Const array of const array of T
Variable 'e' is not modifiable, nor is 'e[i]', nor it 'e[i][j]'. However, the
referrent object of 'e[i][j]' is modifiable.
Confused yet? Keep in mind that this is only a suggested syntax.
I don't particularly like it, but it seems to be the most efficient syntax,
and it is the same syntax as that used for const array function
parameters in C99.
(BTW, for those who have argued against using the keyword 'const', I must
point out that 'const' is already a reserved word in Java; we might as well
use it instead of inventing yet another one.)
It might be prudent to simply mandate that arrays cannot be const, and that
only the objects they refer to (their referrent objects) can be const.
If so, the examples for 'a' and 'b' utilize the only valid syntax, and the other
examples are not legal. The drawback to such a mandate is that while we
could declare methods as returning arrays of const objects, we would not
be able to declare them as returning const arrays (which seems like a
fairly useful thing to be able to do).
Another (better) prudent approach might be to say that only whole arrays
can be const, i.e., the dimensions of an array are either all const or all
non-const. Thus we could have syntax something like:
const T[] a; // Array of const T
T const[] b; // Const array of T
const T const[] b; // Const array of const T
const T[][] d; // Array of array of const T
T const[][] e; // Const array of const array of T
const T const[][] f; // Const array of const array of const T
The leading 'const' applies to the referrent objects of an array declaration,
and the 'const []...[]' modifier applies to the reference elements of the array
variable itself.
Submitted On 23-FEB-2002
hlovatt
In reply to shrink_laureate, you make two points:
1. The class hierarchy is changed, e.g. if 'X extends Y'
this is changed to 'X extends ConstX extends Y extends
ConstY'. You see this change in hierarchy as ''total
devastating'', whereas I see it as a trivial change.
2. You give the example of a const view array, one
approach is to provide a simple wrapper for the
existing in-built arrays, e.g.:
public final class ConstIntArray {
private final int[] array;
public ConstIntArray(final int[] array) {
this.array = array;
}
public int get(final int index) {
return array[index];
}
public int length() { return array.length; }
public int[] constCast() { return array; }
}
You write these const array wrappers once for each of the
primitive types and for Object, you use them again and
again in many different programs. In use you do something
like:
class X {
private final int[] array;
...
ConstIntArray get() {
return new constIntArray(array);
}
}
The wrappers for arrays are simple and the overhead of
writing them once is small, therefore I don't see a
problem with using them. It certainly isn't true to say
that you cannot design interfaces that use a const view of
an array. See previous postings to this forum on more
sophisticated array classes that offer a const view array
and also offer performance improvements over the in-built
array type in Java.
Submitted On 24-FEB-2002
97jaz
Is it possible to vote *against* an RFE? This is a truly awful idea.
Submitted On 25-FEB-2002
shrink_laureate
I don't deny that it's possible to write a relatively
simple wrapper around an array that provides const-ness.
But it isn't an array. All the functionality of this can
be duplicated with extra classes and extra work, but that
isn't really a solution. And no, i don't want operator
overloading as a solution to that, because of all the
messes people make with it.
> Confused yet?
Yes, which is why I don't like that syntax. Particularly
confusing is how you describe the various forms of array.
Tradition is not a good reason for bad design.
Perhaps we're overlooking the obvious:
(I'm going to keep saying readonly, not const, because I
don't want people to assume C-like behaviour for it)
readonly T x;
// x is a read-only T
readonly T[] x;
// x is an array of read-only Ts
readonly array T[] x;
// x is a read-only array of Ts
readonly array readonly T[] x;
// x is a read-only array of read-only Ts
Submitted On 27-FEB-2002
naoursla
Allow transient variables to be changed in const classes.
transient variables are not really part of the class state.
const methods need some way to cache data that is
calculated from data in an object. C++ uses the immutable
keyword. I thin that transient would be sufficient for Java.
Submitted On 27-FEB-2002
naoursla
Here the description of how I would like const to work:
- const is a modifier that can be applied to a reference,
a method, or a class.
- A non-const reference is automatically casted to a const
reference.
- A const reference cannot be casted to a non-const
reference.
- Any variables accessed through a const reference are
also const.
- A transient reference is never limited by const.
- For primitive values, const is identical to final.
- static data always receives const explictly or from the
class. A const refernce can be used to change non-const
static data.
- Only const methods can be called on a const reference.
- In a const method, "this" is const in addition to final.
This implies that const methods:
- can change only transient or non-const static data in
a class.
- can only call other const methods on data members
(including this).
- cannot return a copy of a member reference as a
non-const reference. A copy must be made, or the
return value must be const.
- can call non-const methods on non-const parameter
references.
- A const class has all methods and static data defined as
const. Also known as an immutable class (although
currently this is only specified in documentation).
i.e. java.lang.String should be defined as a const class.
- const array references make the array and its contents
const. This rule is arbitrary. I imagine that one might
want an array of Objects where you cannot change the
array, but can change the object. However, I cannot
imagine a decent syntax to make such a distiction.
- array initializer lists are const and can be used as
const paramters.
- methods derived from const methods must be const.
- methods derived from non-const methods may be changed to
const.
- classes derivied from const classes may be non-const,
but all methods in base class are restricted to const.
Submitted On 01-MAR-2002
shrink_laureate
>
> You are mixing up const and final...
> ...Again you are mixing up final and const...
> ...Again const and final should not mean the same thing,
> that is just very confusing.
This is why I don't want to use the word "const". Hearing
it, you think it must behave like final, when it
doesn't. "readonly" may be an extra keyword for people to
learn, but it says exactly what it's supposed to say.
Just because C called it const, doesn't mean it's right!
The other reason is that we have to have more than one
keyword in this scheme to handle readonly-safe methods and
methods that return readonly references.
> No, const should be illegal for primitive types.
Agreed. We need to separate the idea of read-only
references from that of final values.
> const array references make the array and its contents
> const. This rule is arbitrary. I imagine that one might
> want an array of Objects where you cannot change the
> array, but can change the object. However, I cannot
> imagine a decent syntax to make such a distiction.
I can easily imagine a good syntax for it, but it isn't
Java! Finding a way to slot this into Java will be
difficult.
> A const class... Also known as an immutable class
Then why not call it an immutable class?
Why is it that people would rather have a syntax that's
confusing, buggy and incapable of doing the job it's
designed for, than just add another two or three keywords
to the language?
Submitted On 01-MAR-2002
megagurka
> - Any variables accessed through a const reference are
also const.
What do you mean with variables? Reference fields? Why
should they be
const just because they are accessed through a const
reference? They
should be final in the sense that you cannot change their
value, but
you can still change the value of the object they are
referencing. You
are mixing up final and const.
> - For primitive values, const is identical to final.
No, const should be illegal for primitive types. Again const and
final should not mean the same thing, that is just very
confusing.
> - static data always receives const explictly or from the
> class. A const refernce can be used to change non-const
> static data.
What do you mean with "static data always receives const
explictly"?
Static data should always be mutable through a const reference
(otherwise you can still change it through the class name),
unless
it's declared final. Exactly like today. Again you are
mixing up final
and const.
> - In a const method, "this" is const in addition to final.
> This implies that const methods:
> - can change only transient or non-const static data in
> a class.
What is "non-const static data"?
> - can call non-const methods on non-const parameter
> references.
This applies to all methods, not just const methods.
> - A const class has all methods and static data defined as
> const. Also known as an immutable class (although
> currently this is only specified in documentation).
> i.e. java.lang.String should be defined as a const class.
Const classes are a bad idea, they are not needed.
> - const array references make the array and its contents
> const.
No, this wouldnt be good, it's two separate things.
Sometimes you want
const array references where you can change the objects in
the array.
> - array initializer lists are const and can be used as
> const paramters.
??? An array initializer list just creates a new array. It
should
return a normal reference, not a const reference.
Submitted On 06-MAR-2002
hlovatt
Couldn't agree more with hwc, this proposal is a lot of
trouble for no gain. It does not increase type safety. RFE
4617197, Immutable types, gives reduced memory footprint
and speed.
Submitted On 06-MAR-2002
hwc
Rather than ask why we need two or three keywords, I would
ask why would people use them. safe, readonly and notnull
are easier to understand than the many proposed meanings of
the single keyword const but most of our methods will then
become something like
safe public readonly notnull MyObject method( final
readonly SomeObject x )
Would most programmers bother if there weren't clear
performance and safety benefits? Some would, but compiler
support for immutable objects offers many of the same
benefits with less effort.
C++ gets away with a single keyword because references are
implicitly final and not null. Java references are more
like C's pointers in this respect with the same problems.
Submitted On 13-MAR-2002
megagurka
I dont agree with hwc and hlovatt. What we are discussing
here are references that cannot change the object they refer
to. That's it. We are not discussing immutable objects or
classes (like RFE 4617197).
C++ solved this with two keywords: const and mutable. I
think it's a reasonable solution.
>> Would most programmers bother if there weren't clear
>> performance and safety benefits?
I know I would cause the alternative is to design a special
const interface for each class which is ugly and tedious. If
you have programmed C++ you know that const is used very
often and is a great feature.
Submitted On 17-MAR-2002
ChristianHujer
Although this is not a bad idea, I am against adding this
"feature". The basic problem is that programmers do not know
the difference between identity attributes and peripheral
attributes and because of set write setters for attributes
that must not be changed.
Programmer's should learn good OO style.
Example:
public class Point {
private double x;
private double y;
public Point(double x, double y) {
setX(x);
setY(y);
}
public double getX() {
return x;
}
public double getY() {
return y;
}
// they will cause big trouble:
// they instead should be private or protected
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
}
class Rect {
private Point lowerLeftCorner;
private Point upperRightCorner;
public Rect(Point lowerLeftCorner, Point upperRightCorner) {
this.lowerLeftCorner = lowerLeftCorner;
this.upperRightCorner = upperRightCorner;
}
}
class TroubleMaker {
public static void main(String[] args) {
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
p2.setX(p2.getX() + 2); // ouch
p2.setY(p2.getY() + 3); // ouch
Rect r2 = new Rect(p1, p2);
}
}
Movement of Points should instead result in construction of
a new Point, like this:
public class Point {
// ...
public Point move(double dx, double dy) {
return new Point(this.x + dx, this.y + dy);
}
}
Otherwise programmers will start cloning to be safe that
their objects keep unmodified by called methods.
And const won't solve this when used for method parameter
declarations.
My two cents.
Submitted On 19-MAR-2002
hlovatt
In reply to megagurka, contrasting this proposal with the
immutable proposal 4617197, would you really rather write:
public final const int const[] const[] maximum(final const
int const[] const[] other) const {...}
rather than
public final Integer[][] maximum(Integer[][] other) {...}
Note the 4617197 version will also run faster and take up
less space.
For a proposal that only adds syntax, not functionallity,
it is a pity that the syntax isn't better ;)
Submitted On 19-MAR-2002
hlovatt
Following on from ChristianHujer point, I have seen this
sort of thing happen in C++. It doesn't happen in simple
examples it happens in really conveluted ways that are hard
to find :( . Using ChristianHujer example and assuming that
const is allowed in Java and that Rect is declared as
accepting const arguments. The senario I have seen is that
the initial version of the code is:
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
Rect r2 = new Rect(p1, p2);
This compiles and runs fine, but infact contains a subtle
mistake. p1 and p2 should have been declared const. The
compiler doesn't pick this up because it is OK to pass a
non-const to Rect that is expecting a const.
Now the trouble begins, during maintenance the above is
changed to:
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
p2.setX(p2.getX() + 2); // ouch
p2.setY(p2.getY() + 3); // ouch
Rect r2 = new Rect(p1, p2);
This again goes through the compiler without mistake.
Constrast this with the immutable C proposal, the initial
mistake of forgetting the const keyword is picked up by the
compiler because you can't pass a mutable to an immutable
(unlike const were a non-const can be passed to a const).
Note the syntax is also helpfull, whereas it is easy to
forget const you are far less likely to ADD Mutable and you
would have needed to add Mutable to the declaration of p1
and p2 and to the declarion of the constructor Rect, all by
mistake, highly uinlikely!
Therefore assuming that Point is an immutable type (see RFE
4617197), the original code is unchanged:
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
Rect r2 = new Rect(p1, p2);
Now during the code maintenance the code becomes
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
MutablePoint p3 = p2.toMutable();
p3.setAddX(2); // now OK
p3.setAddY(3); // now OK
Rect r2 = new Rect( p1, p3.toImmutable() );
Or since Point is so quick to create, you wouldn't bother
with a mutable form, therefore the example becomes:
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
Point p3 = new Point(p2.getX() + 2, p2.getY() + 3);
Rect r2 = new Rect(p1, p3);
Both of which are bug free :)
Submitted On 21-MAR-2002
megagurka
hlovatt, I dont understand what you mean. There is no bug in
the following code, it does exactly what the programmer wants:
Point p1 = new Point(3, 4);
Point p2 = new Point(7, 9);
Rect r1 = new Rect(p1, p2);
p2.setX(p2.getX() + 2);
p2.setY(p2.getY() + 3);
Rect r2 = new Rect(p1, p2);
If the programmer didnt want the r1 to change when p2 is
changed, he/she would pass a copy of p2 to the Rect constructor.
Again you are talking about immutable objects. This RFE is
NOT about immutable objects. Declaring a method parameter as
const only mean that the object cannot be changed through
that parameter. It can still be changed through other
non-const references.
I'm not saying immutable objects are not useful, but it's a
different subject.
Submitted On 29-MAR-2002
andythomascramer
Hlovatt's comparison of
public final const int const[] const[] maximum(final
const int const[] const[] other) const {...}
to
public final Integer[][] maximum(Integer[][] other)
{...}
relies on his proposal that all arrays containing immutable
objects must themselves be immutable. The latter's
simplicity thus derives from absence of choice.
Also, the latter form omits the "final" before the
argument, necessary for equivalence with the former. But
it's generally accepted that declaring formal
arguments "final" is allowing the implementation to intrude
upon the interface.
Also, the syntax for declaring array references const is
not yet determined. It might be simply that a single const
specifies that a reference to a multi-dimensional array
cannot modify any member of the array, in any dimension.
Thus, a reference of type const int[][] would point to a 2D
array of integers, and be unable to modify the 2D array at
all. Or more flexibility could be provided, at a cost to
simplicity -- e.g., int [const][const].
Regardless, in Hlovatt's former statement, the
first "const" before the return type and argument has no
purpose.
Also, the trailing const on the former provides a compile-
time check not provided by the latter. Again, the
simplicity results from less functionality.
Also, either 'Integer' in the latter does not refer to
java.lang.Integer, or Hlovatt's proposal breaks existing
code (because of his proposal that arrays of immutable
objects _must_ themselves be immutable). If the former, it
requires either an import or qualification. If the latter,
it’s a futile proposal.
An accurate comparison, then, would be between the
following:
public final const int [][] maximum(const int[][]
other) {...}
to
public final HLovatt.Integer[][] maximum(HLovatt.Integer
[][] other) {...}
The former offers greater flexibility and requires
significantly less memory.
However, an either-or battle between const-restricted
references and immutable types is illogical. Both const-
restricted references and immutable types would be useful.
Submitted On 29-MAR-2002
andythomascramer
David Tribble's "Comprehensive Theory" placed recently in
the description of this RFE has a common flaw: in a few
places, it confuses const-restricted references with
immutable objects.
Consider, for example:
"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."
Contrast that with:
"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."
The former presumes that all const-restricted references
point to immutable objects. The latter does not. (And the
former requires run-time checks; the latter only compile-
time.)
Consider this class:
public class MyClass {
private const AnotherClass m_reference;
public MyClass( const AnotherClass reference ) {
m_reference = reference;
}
…
}
Other code can create MyClass, passing it a reference to a
mutable object, following Tribble's latter rule:
AnotherClass ac = new AnotherClass(); // Mutable
MyClass o = new MyClass( ac );
ac.nonConstOperation(); // Legal
But this breaks Tribble's former rule: the member variable
is declared const, but the object to which it points is not
immutable.
I'd like to suggest this alternative wording:
"Any reference variable declared 'const' is
restricted to 'const' operations on the object
to which it refers."
Read as a whole, Tribble's specification (and later remarks
on arrays) is appropriate for this RFE, and almost perfect.
He clearly understands the concept.
The specification’s occasional confusion with immutable
objects, however, is unfortunate, and likely to confuse
other readers. I encourage Mr. Tribble to amend the
specification, and Sun to update the description.
Submitted On 29-MAR-2002
andythomascramer
David Tribble's remarks on const-restricted references in
arrays are wonderfully comprehensive. However, they don't
address the similar issue of const-restriction for
references to arrays of primitives.
For example, a method might want to expose an internal
array for read-only access. Without const-restricted
references to arrays of primitives, I've found it necessary
either to copy the array or make a fervent plea to clients
in the method documentation. The former can harm
performance, the latter allows error.
Using a syntax parallel to Tribble's for array references
supporting dimension-specific const-restriction:
public double[const] getArray() const { return
m_myArray; }
Using a syntax parallel to Tribble's for array references
NOT supporting dimension-specific const-restriction:
public double const[] getArray() const { return
m_myArray; }
(I find the former more readable for 1-dimensional arrays,
but realize this comes with greater complexity for multi-
dimensional arrays. I would find the latter functionality
usually sufficient.)
Both of the return types are references restricted to const
operations on the array to which they point. They are _not_
references to immutable arrays.
The C++ syntax "const double[]" is not parallel to
Tribble's suggested syntax for arrays of references to
objects. In Tribble's "const T[]", the const specifies that
the members themselves are const-restricted references.
Therefore, "const double[]" should not be supported.
Submitted On 01-APR-2002
hlovatt
I think const fails this "less is more" test, but I am
willing to be convinced otherwise. I am most definitely in
favor of improved compile time checking (static checking).
So give me an example of how type safety is improved with
const, in a way that is safer than the current alternative
of using objects, inheritance, and interfaces and is
better/safer than using immutable types.
I have asked for examples of why const is worth while twice
before in this forum, on both occasions people replied with
const arrays. On both occasions I pointed out that you can
do them with wrappers (plus other techniques). The reply to
the wrapper suggestion, on both occasions, was along the
lines of instead of writing 'i = ia[0]' you now had to
write 'i = ia.get(0)' (like you would for ArrayList) and
that this was unacceptable to them. My own personal bias is
that I don't point much weight on shorter syntax, I prefer
easier to understand syntax and/or more functionality. So I
don't think that the "'get' is too long" argument is a good
enough argument for a language extension. Also the
immutable proposal gives even better (both shorter and
clearer) syntax for unchanging arrays, so this is a poor
argument on two counts.
So please, give me a good example of were const might be
used.
Submitted On 01-APR-2002
hlovatt
In reply to andythomascramer:
I think my original comparison is valid (but see A to D
below),
namely:
public final int const[] const[] maximum(
final int const[] const[] other) const {...}
compared to using immutables as defined in RFE 4617197
(incl.
subsequent discussions), i.e.:
public final Integer[][] maximum(Integer[][] other)
{...}
My reasoning is:
1. You suggest that the immutable form will take up more
memory
(presumable because you think extra pointers will be
needed).
This isn't true, immutables don't require extra
pointers,
unlike const. Also, immutable execute quicker than const.
2. I was replying to megagurka who was advocating C++ like
syntax, hence all the const's (I will come back to this).
3. The immutable RFE 4617197 makes immutable types final as
well
as making arrays of immutables themselves immutable,
hence
final argument in const version.
4. All the const's aren't necessary, point B below, but the
const after the method declaration is necessary. In an
immutable class all the methods can't change the fields
(they are immutable). Note this is compiler checked,
this is
opposite to what you said.
The areas I did cheat in are:
A. As you point out some of the syntax problems with const
are
because you specify const for each dimension of an
array;
but you suggest that you can't have some changeable and
some
unchanging dimensions with immutables, this isn't true:
MutableArray<Integer[]> or a custom array class for
example.
B. I did put an extra const in for an int, I have removed it
from the above. The extra const isn't required for
primitive
types but would be needed for classes or interfaces.
C. The file in which maximum is defined in requires the
import
java.lang.immutable. I didn't show this because all I
was
showing was the method definition.
As I have already said; I was replying to another post that
advocated C++ style syntax, but I do agree with you that
better
syntax has been suggested for const references. However I
still
don't think const is worth adding, even with better syntax.
When
would you use it in preference to immutable? Hardly ever!
Submitted On 01-APR-2002
hlovatt
In reply to megagurka:
> hlovatt, I don't understand what you mean. There is no
> bug in the following code, it does exactly what the
> programmer wants:
The code was posted as an example of a type of bug seen in
real programs, originally given as an example by
ChristianHujer, and therefore must be a bug (it is an
example of one!). The mythical programmer didn't want r1 to
change, he/she made a mistake.
The point of my posting was to say that this type of bug
happens in real code and that const doesn't help to prevent
this. As I said in my posting it is an example, no one is
suggesting that in such simple code a mistake would be
made, but in a large project when r1 and r2 are in separate
packages let alone separate classes and files, this type of
thing can inadvertently happen. In fact this type of bug is
so common it is given a name, const aliasing.
ChristianHujer expressed similar opinions in his posting,
as have many other to this forum.
At present people are unlikely to write Rect without
copying the point arguments in the constructor, because
most people are aware that point might change. However if
const exists there is the temptation to write Rect
accepting const arguments to save the copying. This is when
the trouble starts, because the user of Rect now has to be
very careful to avoid const aliasing problems. There is
nothing the writer of Rect can do to help the user of Rect
from accidentally having a const aliasing problem. Thus far
from decreasing bugs, I think const will increase them
because it will encourage bad practice in the name of
optimization. With immutable you don't get the alias
problem and you get an even larger speed up.
What I am saying is that const isn't very useful (in fact
it is positively harmful). Not that the compiler is
implementing const incorrectly or that const and immutable
are the same. I am also saying that immutable is better
than const and that we shouldn't add const to Java
because "less is more". (I interpret Sun's "less is more"
phrase to mean: something has to pull its weight, it has to
be useful in many circumstances, you don't want lots of
things that might be used in similar circumstances, and
there isn't a better alternative. I don't interpret "less
is more" to mean less typing.)
Submitted On 11-APR-2002
bbringert
This proposal doesn't seem to cover the const-ness of method
parameters and return values when methods are overridden.
For example:
<pre>
public class Foo {
public void peek(const Foothing thing) {
...
}
}
public class Bar extends Foo {
public void peek(Foothing thing) {
// do something nasty to thing
}
}
const Foothing thing = ...
Foo foo = new Bar();
foo.peek(thing);
</pre>
It seems like overriding methods must not only be as
restrictive as the overridden method when it comes to method
constness, but also regarding the constness of method
parameters (return value constness would work the other way
around I guess).
Submitted On 18-APR-2002
MatteS
We have developed a formal theory of how to construct a
const for a Java-like language. In the language it is
possible to declare a member variable as read-only and then
that variable will not be able be used to change the
transitive state of the object to which the variable
referes. furthermore, we have also included the possibility
to declare a variable as context which means that the
variable will be treated as a read-only variable within
methods invoked via read-only objects and treated as an
ordinary references otherwise.
The proposal has been presented both at the Formal
Techniques for Java Programs Workshop at ECOOP 2001 in
Budapest and at the Sixth International Conference on
Computer Science and Informatics 2002. You may download the
proposal from http://www.dsv.su.se/~matte/.
The proposal considers method parameters, method returns,
local variables and member variables. It has been proved to
keep the read-onlyness of a reference in reference
transfers, i.e. returns, assignements and parameter
passing. The read-only properties can be statically checked
and thus does not impose any run-time or memory overhead,
and, if adapted to Java, it would not require any change to
the virtual machine.
Any comments could be useful to further improve the
proposal.
Thanks
Mats Skoglund, matte@dsv.su.se
Submitted On 19-APR-2002
Ixchel
I just read through the above-mentioned paper. I have a few
comments:
1) Overall, I like the approach. The ability to
transitively protect data is a nice touch.
2) I think keywords "read", "write", "context", and "any"
will not be acceptable as they are too widely used as
method and variable names. New keywords will be needed.
2) I think that some provision needs to be made for caching
of data within "read" methods. C++ uses 'mutable' for this.
Simply allowing class members to be declared 'write' would
be sufficient, I think.
3) Inheritance and overriding need to be considered. For
instance, can I declare the methods "Thing flagellate(read
Thing x)" and "Thing flagellate(write Thing x)" in the same
class? One in a superclass and the other in a subclass? Can
the second override the first?
4) The presence of the value 'null' needs to be considered.
When can it be assigned, and to what. (Note: I'd still like
to see a 'notnull' keyword or the equivalent in Java at
some point).
5) I'm not sure that I understand the desirability of
the 'any' qualifier. Wouldn't it be sufficient to use
a 'read' qualifier, and allow an implicit cast from
a 'write' reference to a 'read' reference?
6) Regarding backwards compatibility, what is the default
qualifier for a variable which is not declared with one?
How do these variables interact with the other modes?
Submitted On 19-APR-2002
Ixchel
Another question:
7) How does your proposed syntax handle more complex types,
such as multidimensional arrays and generic types? What
about array initializers? Presumably, one wants to be able
to declare such entities as, for instance, a 'read' array
which contains 'write' elements. Also, in this case,
does 'context' in an array element refer to the mode of the
array that contains it, or the object that contains that
array?
Submitted On 22-APR-2002
MatteS
I shall try to answer your questions as good as I can.
2) The proposal was originally focused on class-based
object-oriented programming languages in general and not
just for Java. The keywords are just syntax and were chosen
mostly for convinience. I don't have any problem with
changing the syntax to something more acceptable. Any
suggestion is welcome!
2, second) You are perfectly right, adding the possibility
to declare member variables as 'write' would not be to
hard. The reason why we didn't do it originally is also for
convinience. A 'write' member variable could end up
referring to the same object as a 'read' or 'context'
member variable and thus, in order to account for that in
the proofs, we would have to add more constraints for the
proof system and we just didn't want to do that.
3) Inheritance is considered to some degree in our
proposal. We simply say that the modes of a overriding
method must be the same as the modes of the overridden. We
have experimented with some covariance/contravariance on
parameters and method returns but I cannot recall the exact
outcome of those experiments so I leave that issue open for
the moment.
For now, this means in our proposal that the example "Thing
flagellate(read Thing x)" and "Thing flagellate(write Thing
x)" would not be allowed. The problem is to determine which
method will be bound to in runtime. We do not want to bind
a read reference to a method that takes a write formal
parameter. This could perhaps be determined in some cases
for a specific program. However, in the general case this
is much harder to determine due to the dynamic binding of
methods so we have to be conservative. Also, we do not want
to reject older programs just because we have added a
subclass to the inheritance hiearchy which by
conservativness *might* by bound to.
4) We have not considered 'notnull' in our proposal.
5) The 'any' qualifier is just dynamic sugar added to our
proposal. In our proposal a 'read' variable can contain
only a read reference, a 'write' variable only a write
reference and a 'context' variable contains a reference
with the same mode as the mode of the reference used to
invoke the method where the context variable is used.
An 'any' variable can contain either a read reference or a
write reference with no respect to the mode of the
reference used to invoke the method where it is used. This,
however, requires a dynamic check to be performed on the
variable before it is used in order to 'cast' it to the
right runtime mode. Other solutions are of course possible,
e.g. throwing an exception if the variable is used
wrongfully. The problem is that we need dynamics to
determine this so the development of the 'any' part of the
proposal has been postponed for the moment.
6) For backwards compatibility the default qualifier for a
local variable, formal parameter, method return and methods
would be 'write' and for member variables the default would
be 'context'. With those default settings you can write
ordinary programs without using any read-only features
unless you need them.
7) We have not yet considered arrays and other complex
types at all so any suggestion is welcome.
Mats Skoglund, matte@dsv.su.se
Submitted On 01-MAY-2002
shrink_laureate
I like the proposal MatteS. I could even live with the
syntax, once it's been sugared up with a few defaults (ie,
to not break or alter existing code).
However, it isn't complete without a way of marking the
insides and outsides of arrays. (Generics are easier to
handle). And as you can read on this page, that is a hard
area to agree on.
Submitted On 13-MAY-2002
kinsalis
I think that this feature would be best left out of the
language as it isn't really necessary, and I think if you're
worried about things getting changed then you clone them.
Hell: I'm sure some people think it'd be nice to have inline
assembly and no checking of memory access etc, but that sort
of stuff is what things like c\c++ are good for, this is one
bug I wish I could vote DOWN (suggestion for improvement in
the bug voting scheme?), no need to hack into the java spec
to keep the c++ programmers happy: they already did that
with .net and c# :)
Submitted On 13-MAY-2002
megagurka
To say that you can achieve the same effect as this RFE by
cloning objects, you really haven't understood what this RFE
is about. Cloning is a totally different concept.
Submitted On 14-MAY-2002
shrink_laureate
This RFE really has very little to do with C++, and .NET is
no closer to it than Java. It's an advanced component-
oriented feature, on the road to design by contract, not a
throwback to the bad old procedural days.
Submitted On 26-MAY-2002
manish_jethani
Yes, I've been asking for this since long. The const
qualifier should be added to the Java language - for all
the reasons that everyone else has mentioned (go and search
comp.lane.java.*).
Submitted On 11-JUL-2002
SteveCrook
It seems plain that this isn't going to happen, and for all
the wrong reasons (though I do have some sympathy). It
would be a huge upheaval to the current codebase and I'm
sure that a lot of code would be broken. I remember my
problems in C++ trying to introduce the use of const into
an app that had ignored it. Still, for a modern language to
not have this feature is bonkers and it does rather betray
the languages origins. Sooner or later I suspect that Sun
will have to bite the bullet and do this. The longer they
leave it the more painful it will be for all of us. Just
think of all the classes that wouldn't have been written
yet if this had been done in the release after the RFE was
submitted. If they can't do const and generics take
forever, what hope is there for full DBC?
Submitted On 26-JUL-2002
shrink_laureate
There is no hope for DbC. Sun clearly isn't prepared to make
the changed needed to keep Java at the top of the pile, so
sooner or later somebody else is going to take their place.
So far, the alternatives I see are:
- C# on .NET is a nice language, but doesn't distinguish
itself from the Java it copied, and also comes with too much
political baggage.
- Perl 6 is coming along nicely, but isn't intended to have
the type-safety and strict correctness that makes Java what
it is - and which read-only references and DbC will help to
bring up to spec.
Once again, i feel in a language-writing mood. Who's with
me?
Submitted On 28-AUG-2002
fuchssa
OOOh yea this is a glaring omission from a superb OO
language like Java. I'm aghast that such a useful feature
with no side effects isn't supported.
In my favorite C++ books they always mention "const-ness",
and how valuable it is to laying a good code structure.
I will go out of my way to vote for this one!
Submitted On 29-OCT-2002
davidtribble
I'd just like to point out that classes already exist in the standard
library that act like they are 'const' classes. Perhaps the most
notable are classes 'String', 'Integer', 'Character', et al, in
package 'java.lang'.
This fact should not cause any major problems, though, if 'const' were
eventually adopted by Java. For example, the following pairs of
methods below would be *functionally* identical, even if the compiler
treats them as *semantically* different:
String getName() { ... } // A1
const String getName() { ... } // A2
void setName(String n) { ... } // B1
void setName(const String n) { ... } // B2
Submitted On 22-NOV-2002
susomc
it would be useful add a new keyword inmutable, with the
following functionality
You have to forbid casting an inmutable parent as a mutable
child
but only in the case you have declared the parent as
inmutable
I mean
inmutable class I {
protected int a;
}
class M extends I {
void modify() {
a = 5;
}
}
M m;
I i;
m = (M)i; (FORBIDEN!!!) (only in this case because i is
declared inmutable)
i = (I)m; {ALLOWED}
The programer should be responsible of returning only
inmutable object references from an inmutable class, even if
this objects are mutable. You can also return copies of the
objects.
Submitted On 02-DEC-2002
jordansamuels
The pros of this outweight the cons. Unlike other possible
language additions to Java borrowed from C++ or other
languages, this feature does not seriously impact developer
who don't wish to use the feature. Its value to the
developers who do wish to use it is almost immeasurable;
others have already commented on Design by Contract. For
Java to be a serious, mature language it must adopt
something of this nature.
Submitted On 11-DEC-2002
eboukobza
One should also consider 'const' feature may be trouble and
misleading.
Take for example:
const HashMap myData = new HashMap();
Can I use myData.iterator() ?
Can I use myData.entrySet() ?
Either the response is yes and 'const' is broken since:
Iterator iter = myData.iterator();
iter.remove()
will actually modify myData... OR... myData is just about
unusable !!!
Make it by design !!!
Eric
Submitted On 11-DEC-2002
Ixchel
CONST REFERENCES AND IMMUTABLE CLASSES ARE TWO
COMPLETELY DIFFERENT THINGS!
I put this in all caps because there still seem to be people
posting comments that claim that immutable classes are in
some way replacements for being able to declare particular
references (variables, parameters, etc.) as 'const'. If what
you want is immutability, go look at bug #4617197, which
deals with that subject, rather than this one.
Please don't reply to this feature request telling us how to
create immutable objects. We know. There are lost of
immutable objects already in Java. Java.lang.string,
java.lang.Integer, etc. That's not what this feature request is
for. A const reference allows A PARTICULAR USER of an
object to guarantee that THAT USER won't change it. An
immutable class guarantees that NO USERS of an object will
change it once it is constructed. These are entirely different
concepts with completely different purposes.
Submitted On 11-DEC-2002
Ixchel
In response to the recent article by eboukobza:
The way this is handled in C++ is by having 'iterator()' when
called on a const object return a const iterator, and by
having iterator() when called on a non-const object return a
non-const iterator. An iterator declared 'const' iterator
doesn't allow access to the remove() operation, while the a
non-const iterator does. In C++, this might be declared as a
pair of methods in the same class:
const Iterator iterator() const { ... }
Iterator iterator() { ... }
At compile time, the compiler will choose the correct method
depending on whether the object the method being invoked
on is const or not.
There are some proposals (above) for collapsing these two
declarations into a single one by using a keyword that means,
basically, "const-if-the-object-being-called-on-is-const, else
non-const".
Submitted On 12-DEC-2002
eboukobza
The purpose of this RFE is to provide read-only access to an
Object just like Collections.unmodifiableCollection() does.
Compile time decision is not always possible, especially when
you work with interface !
Take the following example:
package a;
public class A {
public int peek() const { ...}
public void poke(int v) {...}
}
package a;
public interface Data {
public A getData();
}
package b;
public class B implements Data {
const A someData = new A();
A getData() const { return someData; }
}
package c;
public class C {
Data myData;
public C(Data d) {
myData = d;
}
void doSomething() {
A data = foo.getData();
data.poke(1);
}
}
package c;
public class Main {
public static void main(String[] args) {
try {
Data data = Class.forName(args[0]).newInstance();
C c = new C(data);
c.doSomething();
} catch (Exception e) {}
}
}
Package a is an API and is compiled alone (i.e. packages b &
c not in classpath).
Package b is an implementation of that API (compiled with
package a in classpath).
Package C is an application using B implementation (compiled
with package a ONLY in classpath).
Now... What did the implementor of class B meant ?... What
will happen when compiling/running C ?...
My point is that const alone can NOT give guaranty of
readonly access. This IS misleading !!!
A 'const' keyword may be useful (especially for small
applications) and will not cause much trouble as long as it is
designed as a compiler HINT to make best effort to enforce
readonly access. BUT... what will be the next step ?...
Programmers will want readonly guaranry and this is only
possible by either breaking the dynamic binding of the runtime
or creating immutable object.
Now... Tell me want users REALLY want ?... If they want a
compiler hint... no problem (as long as they don't ask for more
tomorrow)... But if they want read-only access guaranty
(which, by the way, would be a great feature)... THIS IS NOT
THE WAY TO DO IT since you can't escape creating a stub to
control the access (unless you want to loose dynamic
binding).
My bottom line is that I'm tired of RFE's that go to the
direction of loosing dynamic binding (they are way too many
of them and a few in the top 25 RFE's). The fact that a
feature exist in C/C++ doesn't meant it have to be in Java or,
at least, it doesn't mean it has to be implemented the same
way in Java. Dynamic binding is the stongest feature of Java;
they are not too many languages out there providing it, and
none of them can provide Java performance.
Hope I made myself clear now,
Eric
Submitted On 19-DEC-2002
M.R.Atkinson
An alternative way to get similar functionality is:
Add the following keywords to Java[1] immutable, function,
update, read and notnull; with the following semantics:
immutable
---------
This is discussed more fully in bug id=4617197.
function
--------
This is used to indicate that a method has no side effects.
All its parameters must be "immutable" classes or marked
"read", it is not allowed to modify "this", nor is it allowed
to access static variables (neither read or write to them).
All methods it calls are also to be "function".
When used in interfaces this means that classes
implementing the interface must have a "function"
method of the same signature.
Subclasses of a class with a "function" method may override
it but in that case it must be also a "function".
read
----
As a method marker this is used to indicate that a method
does not alter any of its parameters (or "this"), or any
object reachable from its parameters or "this". It is only
able to call methods that are "function" or "read". It may
only read or write static variables that are declared
"read"[2].
When used in interfaces this means that classes
implementing the interface must have a "function" or "read"
method of the same signature.
Subclasses of a class with a "read" method may override it
but in that case it must be a "function" or "read" method.
As a parameter marker it indicates that the parameter (or
any object reachable from the parameter) is not modified
during the method[3]. It is redundant on parameters that
have primitive or "immutable" types. It is also redundant on
"function", "read" and "update" method parameters as they
are "read" by default, and furthermore cannot be "update".
[4]
Methods in subclasses that override (or implements a
interface containing) a method that has "read" parameters
must have the same parameters as "read".
class, instance and local variables may be marked as "read",
do not allowed to be update methods to be called on them.
Although if they are not declared final they may be changed
to another instance.
Continued...
Submitted On 19-DEC-2002
M.R.Atkinson
update
------
As a method marker this is used to indicate that a method
does not alter any of its parameters, but may change "this"
(or objects reachable from "this"). The only methods it is
able to call are marked "update", "read" or "function". It
may read or write static variables.
When used in interfaces this means that classes
implementing the interface must have a "function", "read"
or "update" method of the same signature.
Subclasses of a class with a "read" method may override it
but in that case it must be a "function", "read" or "update"
method.
As a parameter marker it indicates that the parameter may
be changed by the parameter. It is not allowed (will result
in a compile time error) on parameters that have primitive
or "immutable" types.
Methods in subclasses that override (or implements a
interface containing) a method that has "update"
parameters may alter these parameters to be unmarked or
"read".
notnull
-------
This indicates that a parameter may not take a null value.
Parameters marked as "notnull" will throw an
IllegalArgumentException if they are passed a null value. In
many cases the compiler can detect assigning a null value
to a "notnull" parameter and will issue a compile time error.
notes
-----
[1] It would probably be necessary to add a new class of
keywords "keyword_or_ident" to the language, and then
distinguish whether these new keywords are keyword or
identifier in Java source by their context.
[2] static read variables may be written to as they cannot
be used to modify the instance. This allows output and
logging to be used.
[3] for "function" methods this will always be true. For
"read" and "update" methods this is only true on the
same thread. Once a "read" parameter is written to a
static variable it is available to be modified by a
different thread.
[4] "Read" parameters only guarantees the contract from
the client code point-of-view, the method cannot assume
that a "read" parameter will remain constant over the
lifetime of the method, the client code could modify it (or
an object reachable from it) in annother thread. If it
important that the parameter remain constant over the
lifetime of the method, then the method must
synchronize on the parameter.
Submitted On 19-DEC-2002
megagurka
> The purpose of this RFE is to provide read-only access to an
> Object just like Collections.unmodifiableCollection() does.
> Compile time decision is not always possible, especially when
> you work with interface !
You're wrong, it's possible (Java is no different from C++
at compile time). Your example is incorrect, in class B you
have the line:
A getData() const { return someData; }
which would generate a compiler error since you cant convert
a const reference (someData) to a non-const reference.
Submitted On 19-DEC-2002
M.R.Atkinson
Perhaps I should point out that use of function, read and
update to mark methods does almost everything a const
keyword would do, but makes it easier to indicate the
programmers intent and reason about programs. They also
potentially allow a JVM to perform extra optimisations
(especially for function methods).
function methods are ideal for implementing interfaces like
comparable. Almost all methods for Immutable classes are
also functions, although some may have to be read methods if
they access static fields. update methods are used for mutators.
All three make the jonathanfinn noted problem with
static void add(Matrix a, const Matrix b) {...}
impossible.
They also solve the nasty syntax required for arrays, they
also work for interfaces, generics, primitives, immutables.
The one problem they don't resolve is one that has not been
brought up on this list. Reference type parameters that are
reachable by annother thread are liable to change during the
execution of a method (even if it is marked function, read
or update). Defensive programming could synchronise on each
such parameter, but this is error prone an may lead to
deadlocks. Lightweight immutable types, like primitives
cannot be synchronized on (as they may be pass-by-value).
Submitted On 23-DEC-2002
eboukobza
> > The purpose of this RFE is to provide read-only access to
an
> > Object just like Collections.unmodifiableCollection() does.
> > Compile time decision is not always possible, especially
when
> > you work with interface !
>
> You're wrong, it's possible (Java is no different from C++
> at compile time). Your example is incorrect, in class B you
> have the line:
>
> A getData() const { return someData; }
>
> which would generate a compiler error since you cant
convert
> a const reference (someData) to a non-const reference.
>
The example did NOT convert to a non-const reference. You
can read the line above as:
const A getData() { return someData; }
I was just using the syntax used by the writer of the RFE.
Anyway... By trying to argue on a stupid example, you are
just showing how much my main point is right ;)
People... If you want read only guarantee just ASK FOR IT...
not for some kind of implementation like this... The people
responsible for Java in Sun already proved they are able to
provide features in the best possible way (and no... I'm not a
Sun employee).
By asking for loosy implementation of features you're just
killing the language !
I wish I could VOTE AGAINST this RFE and alikes.
Eric
Submitted On 09-JAN-2003
andylarder
Creeping featurism???? The lack of const has got to be the
most brain-dead part of Java apart from the lack of operator
overloading. Get them sorted!
Oh well, I'm sure MS .NET will support const soon anyway ;-)
Submitted On 13-JAN-2003
MartinHilpert
why not making it more easy and interpret the final keyword
so that not (only) the reference variable is final but also the
referenced object, i.e. the object's state can't be changed.
same effect as "const" but doesn't introduce a new keyword
that is effectivaly the same as the already well known "final"
keyword.
Submitted On 13-JAN-2003
pervel
MarintHilpert, that would be a very bad idea as it would break
a lot of existing code relying on the current semantics of final.
Submitted On 17-JAN-2003
megagurka
>> You're wrong, it's possible (Java is no different from C++
>> at compile time). Your example is incorrect, in class B you
>> have the line:
>>
>> A getData() const { return someData; }
>>
>> which would generate a compiler error since you cant convert
>> a const reference (someData) to a non-const reference.
>>
> The example did NOT convert to a non-const reference. You
> can read the line above as:
>
> const A getData() { return someData; }
>
> I was just using the syntax used by the writer of the RFE.
No, it's not the same thing.
A getData() const ...
means that the method can't change the object pointed to
by 'this',
'this' is a read only reference.
const A getData() ...
means that you return a read-only reference to an object
of type A.
> People... If you want read only guarantee just ASK FOR IT...
What do you mean with read only guarantee? This RFE is about
read only references, not read only objects. I think it
would be a valuable addition to Java.
Submitted On 28-JAN-2003
keithkml
personally I don't want this. I never liked that
functionality in C++, as it just cluttered method signatures
and I never really cared about it anyway. let's all use
immutable view objects!
Submitted On 09-FEB-2003
dnoyeB
Reiterating my negative feelings toward this unnecessary
idea. This would take work away from interfaces. Currently
what the poster is requesting is exactly what interfaces are
for. What he really wants appears to be automatic inferred
creation of an interface that only allows access to
non-modifying methods.
By the time you get finished marking all your methods with
the const moniker, you could have created the necessary
interface. exact_same_result.
Again someone please explain why this is not achieveable
with interfaces or why its better with the const moniker??
Submitted On 24-FEB-2003
dkf
If there was just a way to say "this array does not permit
assignment" that'd be good enough. Well, good enough for
me. Others might prefer massive const poisoning of the API,
but it scares me the more I think about it...
Submitted On 25-FEB-2003
Anjum
How about using these keywords (idempotent and immutable):
public class A
{
// This method can change the state of this object
public void doSomething()
{
}
// This method is guarenteed NOT to change the state of
this object
public idempotent int doSomethingElse()
{
}
}
public class B
{
// Using the immutable keyword guarantess to the caller
that "stuff" will not be changed
public void doStuff(immutable C stuff)
{
stuff.doSomething(...); // <---- Compiler error!!!!
stuff = new C(); // <---- OK
stuff.doSomethingElse(); // <---- OK
}
public doStuff2(final immutable C stuff)
{
stuff.doSomething(...); // <---- Compiler error!!!!
stuff = new C(); // <---- Compiler error!!!!
stuff.doSomethingElse(); // <---- OK
}
}
Submitted On 11-MAR-2003
megagurka
> Again someone please explain why this is not achieveable
> with interfaces or why its better with the const moniker??
Two reasons:
- It's more work to do it with interfaces.
- Having an interface with "read only" methods doesn't
guarantee that the implementation doesn't change it's
internal state when these methods are called. With a const
equivalent, the compiler can detect this and produce an error.
Submitted On 11-MAR-2003
megagurka
> If there was just a way to say "this array does not permit
> assignment" that'd be good enough. Well, good enough for
> me.
Why don't you just wrap the array in a class? You shouldn't
pass arrays around in a program, use ArrayList's or
something better.
> How about using these keywords (idempotent and immutable):
You also need a 'mutable' keyword for fields that can be
changed in an idempotent method.
Submitted On 12-MAR-2003
hlovatt
In reply to Megagurka.
I think you are mistaken in a number of areas with your
arguments.
1. Const is not necessarily less work than a const interface,
for example:
1a. A const interface to a multidimensional array may be very
much simpler than a const keyword (e.g. C++).
1b. New syntax is something everyone has to learn whether
they use it or not (because other people will use it).
Therefore the total work for everyone may well be higher.
1c. You end up with double methods, a const and non-const
version (see 2 below).
2. The compiler cannot give the protection you ask for (it can
give no more protection than a const interface), e.g.:
void method1() const {
SomeOtherClass.method2( this );
}
Is method1 const or not, it depends on method2.
EG:
void method2( Object o ) {
NonConstType nco = (NonConstType) o;
nco.changeConst();
}
Clearly you wouldn't do this deliberately but it may happen by
mistake and the compiler can't help. This is the same as
assigning to a void* in C++, the C++ compiler can't stop this.
Another example, should this be banned:
constObject.toString();
You can't call toString because it isn't const! If toString is
declared const in Object all current code is broken that
declares its own toString and legitemete uses of say counting
the numer of calls to toString aren't allowed. What happens in
C++ is that almost all methods end up occuring twice, once
with a const signature and once without and you have to
overload both!
3. Const and const interfaces introduce a false sense of
security and make programs difficult to debug. Experience
from C++ tells us that const will be used as an optimization
instead of making a clone and then there will be problems
when the value changes (the well documented const aliasing
problem in C++).
A better alternative is immutable types, see:
http://developer.java.sun.com/developer/bugParade/bugs/461
7197.html
Submitted On 17-MAR-2003
megagurka
hlovatt, I'll respond to your arguments although you seem to
be repeating them over and over. Also, a const keyword is
not a replacement for immutable types, and vice versa.
> 1a. A const interface to a multidimensional array may be very
> much simpler than a const keyword (e.g. C++).
Can you give an example?
> 1b. New syntax is something everyone has to learn whether
> they use it or not (because other people will use it).
> Therefore the total work for everyone may well be higher.
It would require some learning, yes. But the alternative
today is that almost noone uses const interfaces. Just look
at the collections library for example. Immutable containers
use the same interface as mutable. That stinks!
> 1c. You end up with double methods, a const and non-const
> version (see 2 below).
No. In that case your design is bad.
> 2. The compiler cannot give the protection you ask for (it
can
> give no more protection than a const interface), e.g.:
The compiler cannot protect against stupid casts (unless you
remove the possibility to cast to non-const), but it can
protect against code like this:
class Test {
private int x;
public int getX() const {
x = 4; // <-- Compiler error
return x;
}
}
This is something that wouldn't be detected using const
interfaces.
> You can't call toString because it isn't const! If
toString is
> declared const in Object all current code is broken that
> declares its own toString
toString() should clearly be a const method from the
beginning of Java. Changing it to a const method today
would, as you say, break existing code. I don't know any
solution to this problem.
> and legitemete uses of say counting
> the numer of calls to toString aren't allowed.
Sure it would. I don't know if you are familiar with C++ (it
doesn't seem so), but there is a keyword called mutable that
takes care of this case.
> What happens in
> C++ is that almost all methods end up occuring twice, once
> with a const signature and once without and you have to
> overload both!
??? I've almost never implemented the same method twice in
C++ (with the exception of some reference counting classes),
and I always use const where I see fit.
> 3. Const and const interfaces introduce a false sense of
> security and make programs difficult to debug.
So, you are saying we shouldn't have any protection
mechanisms because they "introduce a false sense of security
and make programs difficult to debug"? What a stupid
argument. Introducing const in Java does not protect against
stupid programmers, it protects against good programmers
making small mistakes that will be detected by the compiler.
> Experience from C++ tells us that const will be used as an
> optimization instead of making a clone and then there will be
> problems when the value changes
> (the well documented const aliasing problem in C++).
Const is not about protected the object from changes, it's
about protecting from changes through a specific reference.
You should always be prepared that the object can change,
unless it's an immutable object. As I said before, immutable
objects and const references are not the same thing. They
are both useful.
Submitted On 17-MAR-2003
hlovatt
Megagurka, here is an example that shows using interfaces to
be simpler and clearer than a const keyword. 1st const
version assuming C++ like const.
public class Matrix {
private int[][] values = new int[ 3 ][ 3 ];
public Matrix( ... ) { ... }
public Matrix add( final const Matrix left,
final const Matrix right ) const { ... }
public void set( final int r, final int c,
final int value ) const {
values[ r ][ c ] = value;
}
public void get( final int r,
final int c ) const {
return values[ r ][ c ];
}
public void copy(
final const Matrix out ) const {
for ( int r = 0; ... )
for ( int c = 0; ... )
out.values[ r ][ c ] =
values[ r ][ c ];
}
public const Matrix max(
final const Matrix that ) const {
if ( ... ) return this;
else return that;
}
public Matrix max( final Matrix that ) {
if ( ... ) return this;
else return that;
}
}
Notes:
0. Only add and get are cleanly expressed using const, for
the other methods const is just baggage. I would say
misleading baggage since you don't instantly think that a
const method changes the this reference. It isn't that const
isn't doing what it should do, it is, the point is that const isn't
very useful!
1. Values isn't really constant inside a const method since the
content can change in a const array, i.e. no syntax for
methods to specify that values is of type 'const int const[]
const[]' where 'const int const[] const[]' means that
elements of values as well as values are const. See set.
2. Same goes for arguments to methods, they aren't really
const. See copy, from its signature which way does it copy,
to this or from this? The compiler is of no help!
3. The example shows mutations of an array object, but any
object will behave the same. Const is useful in procedural
languages but looses its usefulness in OO because of this
feature. Final has the same unfortunate consequences in
Java, most people find final objects that change state
confusing.
Submitted On 17-MAR-2003
hlovatt
4. The max method is a common example of needing a double
function, const and non-const. Joshua Block has stated that
experience with the C++ STL and similar led him to eliminate
const and non-const forms in the interfaces for Collections
because of this bloat.
Now lets look at the interface version.
public class ConstMatrix {
protected int[][] values = new int[3][3];
public ConstMatrix( ... ) { ... }
public Matrix add( final ConstMatrix left,
final ConstMatrix right ) { ... }
public void get(final int r, final int c) {
return values[ r ][ c ];
}
public void copy( final ConstMatrix out ) {
for ( int r = 0; ... )
for ( int c = 0; ... )
out.values[ r ][ c ] =
values[ r ][ c ];
}
public ConstMatrix max(
final ConstMatrix that ) {
if ( ... ) return this;
else return that;
}
}
public class Matrix extends ConstMatrix {
public Matrix( ... ) { super( ... ); }
public void set( final int r, final int c,
final int value ) {
values[ r ][ c ] = value;
}
public Matrix max( final Matrix that ) {
if ( ... ) return this;
else return that;
}
}
This interface version is clearer because it groups together
methods that don't change the matrix, whereas the const
marker is positively misleading! They have about the same
type safety and yet the interface version doesn't break old
code, doesn't require any extensions, and can be done today!
You mention that the above pattern for const isn't common.
It is fairly common in one form, when the non-const class is
kept package private, e.g. BigDecimal. The reason for this is
that const isn't that useful in OO, except as an optimisation
for an immutable. One of the big drawbacks of the const
keyword proposal is that it doesn't support this common
usage of keeping the mutable form private!
Plus the previously mentioned problems with class Object and
any other base class.
So I have given an example that clearly shown there are
down sides to const and almost no advantages, can you think
of an example that really must use const and couldn't use the
above pattern and/or an immutable?
Submitted On 20-MAR-2003
jordansamuels
This is not creeping featurism. It's a crucial element in
industrial-strength software design.
Submitted On 23-MAR-2003
hlovatt
jordansamuels; but we can already do const references, see
post immediately above yours :). Do you have a counter
example?
Submitted On 25-MAR-2003
brettw1
You people are all on crack. If you want to be protected
from yourselves, pick another language. I have worked on
several large scale java projects over the past few years,
and inadvertantly modifying object states in methods is not
a that occurs often enough for a language feature. In fact,
of the thousands of bugs I have probably fixed over these
projects, that particular one might have happened twice. Go
bloat somebody else's language, or go back to C++. Or
should we throw in templates, operator overloading, and
multiple-inheritance, as well?
Submitted On 28-MAR-2003
tzervos
I do agree with brettw1's remarks: "Go
bloat somebody else's language, or go back to C++. Or
should we throw in templates, operator overloading, and
multiple-inheritance, as well?".
Simple things make life easier. If your developers write bad code try to enforce good-code-practices or show them how to write better code!
I also agree with guill's remarks: "It`s a lot simpler to understand someone else code in Java language that in C++, thanks to the confusing
features that don't exist in Java.".
Submitted On 31-MAR-2003
megagurka
to hlovatt:
I still think a const keyword is better and simpler than
const interfaces, but I agree with you that it will be a
hell of a lot of work to add it to the Java language today
(and it will break a lot of existing code). It should have
been there from day one. Adding it today is probably not
worth it.
brettw1 writes:
> You people are all on crack
No, I prefer coke :-)
> Or should we throw in templates,
No, but generic types are desperately needed (and coming soon).
> operator overloading, and
No. Operator overloading makes the code harder to read, and
the benefit is small.
> multiple-inheritance, as well?
Multiple inheritance is not needed when you have interfaces.
Submitted On 31-MAR-2003
hlovatt
Megagurka, most of the proposals put forward in the forum
have been minor variations on the C++ theme; perhaps
different keywords, for example. They don't tend to address
issues of practicality or really even address where const
might be used.
I am *** against *** the following proposal, but a method I
did think of for const before proposing immutable types
(4617197) is given below. I am posting the proposal now so
that it might spark some discussion other than simply re-
hashing C++'s concept of const.
Proposal
========
0. Use const where you would currently use final for
variables, fields, and arguments. const would behave like final
currently does except it could not be applied to methods or
classes to mean cannot be overridden.
1. If final is used for anything other than cannot override then
issue a depreciated warning.
2. Allow const as a qualifier to a class to mean that all its
methods are to treat all fields (even those declared higher up
the class heirarchy) as though they were declared const
(final). Note this does not mean that methods cannot be
overridden and it does not mean that its fields are really
const (final). It means that when in one of its methods the
fields are treated as though they were declared const (final).
Like other class qualifiers the const class qualifier is not
inherited by sub classes. For an example, see "For" point 3
below.
3. Make all fields etc. which are of a type that has the const
qualifier themselves automatically const (final). EG the
keyword const in "const ConstMatrix cm = ...;" is redundant,
but not an error, because ConstMatrix is a class that is
already qualified with const. Also see point 6 below.
Note "const Matrix x" and "ConstMatrix x" are different (they
are of different types), however they both share the
characteristic that "x" cannot be assigned to.
4. The return type of a method may not be qualified with
const. The programmer probably means to return a const
class, e.g. ConstMatrix, therefore flag this as an error. Also it
is an error in Java to have the returned object from a method
on the left hand side of = and therefore a const qualified
return type has no meaning.
5. Modify RTTI for new const qualifier. In particular, class
Modifier to have field CONST and method isConst. These are
simply aliases for existing field FINAL and existing method
isFinal. Also class Class needs a new method isConst that
returns true when a class is declared const.
6. A minor modification to the JVM is necessary, namely an
extra tag bit is needed to mark the class as const. The const
qualifier on variables etc. behaves like final currently does.
The const qualifier to a class is only enforced by the compiler
not by the JVM. The compiler is responsible for marking
variables of a type that is a const class as const (final).
7. You can't mark an interface as const. It doesn't make
sense, const is an implementation detail and anyway it isn't
inherited by derived types. All fields in an interface are
automatically static and const (final), i.e. no change from
status quo.
Submitted On 31-MAR-2003
hlovatt
For
===
Plus points for this proposal are that:
0. It elevates confusion over final having two meanings
1. Doesn't break existing code
2. Provides C++ like level of protection; better is some ways,
worse in others
3. Similar amount of typing to C++, e.g.:
public abstract const class ConstMatrix {
protected int[][] values = new int[ 3 ][ 3 ];
public ConstMatrix add( ConstMatrix left,
ConstMatrix right ) { ... }
public void get(const int r, const int c) {
return values[ r ][ c ];
}
public void copy( ConstMatrix out ) {
for ( int r = 0; ... )
for ( int c = 0; ... )
out.values[ r ][ c ] =
values[ r ][ c ];
}
public ConstMatrix max( ConstMatrix that ) {
if ( ... ) return this;
else return that;
}
}
public class Matrix extends ConstMatrix {
public Matrix( ... ) { ... }
public void set( const int r, const int c,
const int value ) {
values[ r ][ c ] = value;
}
public Matrix max( const Matrix that ) {
if ( ... ) return this;
else return that;
}
}
4. Splits a class into 2 classes so that access control and
own constructors can be given to both const and non-const
forms. Alternatively, as shown, a C++ like version were const
form is just a reduced interface of non-const form is possible.
Note const form that behave like C++ are "abstract const", as
in above example.
Against
=======
The argument against is that "less is more", i.e.:
0. The uses for const references are limited in OO, see point
1 below.
1. It is generally better to use immutable types instead. On
the rare occasions that a const reference is really needed
just use a hand coded const interface.
2. The distinction between "const Matrix" and "ConstMatrix" is
too subtle to be useful, it is just confusing.
Summary
=======
Don't do it. Instead do:
http://developer.java.sun.com/developer/bugParade/bugs/461
7197.html
Submitted On 30-APR-2003
pmurray
You need a another constraint: a const parameter may not
be passed as a non-const parameter to another method. Or
thrown as an exception. Or assigned to a non-const member
variable.
Otherwise I can give my const parameter to myself by
passing it to a method. Or by wrapping the const in an
exception class and throwing it to myself.
Submitted On 30-APR-2003
hlovatt
Reply to pmurray.
When you pass a field to a method it passes a copy, so within
the limitations of the protection provided by const (final) this
hasn't broken the type checking. But I agree that the
behaviour isn't very useful, hence I favour immutables. The
passing to methods and passing to exceptions are yet more
examples of the const aliasing problem that is well known in
C++. People who are strong advocates of const don't see this
as a problem, see discussions in this forum, but for me this
limitation makes const marginally useful at best.
Submitted On 17-MAY-2003
tektoon
I vote against! The whole 'const' concept is a pain. When you really start thinking about it, you need several concepts of 'read-only-ness', for several clients/users of 'your' class, for which 'const' doesn't help you at all.
That's why C++ needs a 'feature' to actually cast const away! Adding 'const' is a bad idea!
Submitted On 21-MAY-2003
michaelkopp
I actually lost track about what is discussed here.
C++ does not have the best solution for const correctness
but java has none. I do not consider the proposal to actually
have to code an imutable object or an read-only interface a
solution for that.
So stop to bully around how bad C++ const is.
The main problem is how do you make sure that an object
given to a method is not modified in that method. there is no
compiler check what so ever.
What if the object is thrid-party? i do not want to write
wrappers for all of my third party objects.
Now here comes the real interessting part. what if the
method is third party? How do I make sure that the third
party method does not modify my object.
None of the 2 is possible in java without copying the object
(what a performance nag) or hand coding it.
I aggree that the 2nd example is not possible in C++ either
(methods can be const, but const_cast and mutable are
breaking that) and that therefor the C++ solution is not good
enough.
Never the less I'd like to see a solution for this problems.
- Compiler Check to make sure that a method marked
as 'readonly' does not modify any members (which does
include methods called in that method)
- Compiler Check that parameters/fields/variables marked
as 'readonly / imutable' are not modified.
These two points also need runtime checking.
We all know that this would be a major effort, but frankly
speaking it should have been there from the start.
Submitted On 28-MAY-2003
bhaskarn
Yes. Please implement this. The collection classes in
java.util are particularly in need of this. Generally they
must throw runtime exceptions when an "immutable" collection
is modified. This makes for very fragile implementations
where runtime tests must be used in place of compile time
checks.
Submitted On 28-MAY-2003
jesusla
Please, implement this much needed feature in Java. Hacks
such as Collections.unmodifiable<Container> should have
never existed in the first place but instead implemented
using const and non-const methods.
Granted, the effort to upgrade all the existing JRE classes
to const-awareness is huge, and not until it is complete
will this const feature yield its fruits, but it's definitely worth
it.
Submitted On 30-MAY-2003
dakokes
I would like very much for this to be done. One thing I'd
like to mention, and I apologize if it had already been said
in one of the comments, is that if you are going to have
you will need a 'mutable' keyword, similar to C++, to mark
class members which const methods can change without
violating constness. They are members which are not
considered part of the object's 'externally visible' state,
or more precisely members that the object's abstract state
does not depend on. It is necessary, if const methods and
references are to be useful, to have this ability. One
common use case is for caching, where in an accessor you use
an instance variable to cache the result of a complex
computation. Calling the accessor may necessitate an
assignment to this variable, but it doesn't really change
the object so the accessor should still be declared const.
Allowing this instance variable to be declared as "mutable"
will allow this, whereas without it you would get a compile
error.
Submitted On 29-JUN-2003
hlovatt
People may not have picked up on this, but the variance
proposal adds read-only arrays to Java. Read-only arrays
seem from the discussions in this forum to be the most
common requirement of people who like const references.
See:
http://developer.java.sun.com/developer/bugParade/bugs/485
6545.html
With this proposal you would write:
T[+] readOnlyArrayOfTsOrSubTypesOfT;
T[-] writeOnlyArrayOfTsOrSuperTypesOfT;
T[=] readWriteArrayOfOnlyTsNotSuperOrSubTypes;
T[] existingArrayThatMayThrowAnArrayStoreException;
Submitted On 07-JUL-2003
barbyware
It is possible add Conditional compilation (like C)
Submitted On 14-JUL-2003
cpell
I'm with brettw1 and tzervos on this. If you feel like Java
needs const, it's because you haven't yet learned how to
program Java in such a way that you don't need const.
Many programmers seem to fall under the impression that once
the method signature and body are written, they are done.
This is not the case in OO design. Every public class and
public method requires a contract. If you don't provide a
contract you haven't finished programming the method or class.
If I want to write a method that is guaranteed to never
modify its argument, I say so in its contract (that is, its
javadoc). If you want to be sure my method won't modify
your object, read the javadoc.
I can only guess that this concept was overlooked because,
traditionally, programmers have hated adding documentation.
I'm guilty of it too. But in an OO world, documentation is
much more important than it ever was in C or C++. It
doesn't just explain things, it defines things.
What I see in the comments here is that many people want
"const" so the compiler can do the work of a contract. It
would be nice to have strong checking for immutable objects,
but the comments make it clear (to me, at least) that the
complexity of adding "const" far outweighs the benefit.
Contracts in the form of javadoc are much clearer to me,
while the amount of additional work needed to fully support
"const" seems daunting.
I think most of the proponents of "const" are looking for a
programming shortcut. I think we can do it with the tools
already provided, and I think we should. I'm sorry that
writing wrapper classes and full javadoc is work, but OO
often is that way: a lot of early work saves a huge amount
of work later.
Submitted On 13-AUG-2003
dkf
I agree with cpell on the point of "contracts" for classes,
objects and methods. Taking the time to develop them and
making sure you stick to them saves your bacon, time and
time again. (Mind you, this isn't a feature of OO design. It's
a feature of all high-quality programming. OO doesn't make it
suddenly become a requirement; you should have been doing
it all along.)
Submitted On 27-AUG-2003
cyberguide
The const feature is the hottest one i was always wondering
about, why it has not made it into the language in the first
place.
Another cool feature in Java would be to allow for operator
overloading and for this one, there is already a working
implementation to be found with the JUMP compiler (don't
know the address anymore).
Hope const will be a feature for the next version after Java
Tiger (1.5). I really do!
Submitted On 14-SEP-2003
gbishop
I see no value in this. I vote against it.
Submitted On 17-SEP-2003
jessh
cpell and dkf are full of it here.
Textually described contracts are all well and good -- and
downright necessary in most cases, but unless/until the
compiler knows about them and enforces them for you they
don't replace 'const' at all.
The entire point of 'const' is to express more intent in a form
that the compiler can understand and enforce -- thereby
forcing at least a portion of the contract (beyond arg, return,
and throws types) to be obeyed at compile time vs. runtime.
C++ may have screwy syntax due to pointers and references
here, but at least one can express this aspect of contracts
and have it statically enforced at compile time.
[On the flip side, someone argued for operator overloading.
This is a straightforward recipe to code that can only be
maintained by its author as there is no realistic way to
prevent someone in a sizable team from using this feature in
such a way that no one else can follow the code -- the
opportunities for accidental obfuscation are endless!
Operator overloading is really cool IF (and only if) you're the
one writing *all* of the code.]
Submitted On 12-DEC-2003
carstenklein1
No need for that one, really.
Please do consider implementing well defined interfaces,
perhaps even incorporating dynamic proxies.
I presume that it would be too much of a problem of
implementing this into the VM or even the Java APIs.
Immutable and Mutable interfaces are good.
Consider that in C++ you are always like forced to use the
const cast operator to cast away constness on many occasions.
Therefore I don't believe that this proposal would do any
good to the language, as it did to C++.
Submitted On 25-FEB-2004
Niklas_Bergh
> Immutable and Mutable interfaces are good.
Indeed, but how can the compiler enforce that they so are?
First after that is possible then I think this request could
be closed.
Submitted On 08-MAR-2004
hlovatt
I have written a compiler available for download that
includes immutables and mutables that are compiler enforced
(in addition to other features). It uses the concept of a
marker interface to identify an immutable (see RFE 4617197).
It is a free download from:
pec.dev.java.net
Under the Lesser GNU Public Licence.
Let me know what you think.
Submitted On 09-MAR-2004
JoeSB
I vote for it.
I think it improve Design By Contract for java.
Just becasue it's not in java the first day, doesn't mean
it should be in java after all.
If you vote against this one, then would you vote that
putting 'final' keyword on method parameter and on
member variable be removed?
Because using 'final' in those two way really give you
not much benefit. You can check by yourself that you
didn't reassign the value to a variable.
The point is that, the check is done by compiler. And it
does what you expected.
I have seen places in javadoc that say "This return the
internal data, without copy, for perfromance. So Don't
modify the returned value" Why do we need this
comment at all? are we asking for const here?
Now that java 1.5 is here and there is annotation. I
think we should have @const as some compiler &
runtime attribute.
Submitted On 16-MAY-2004
mdernst
The paper "A practical type system and language for reference
immutability" makes a concrete proposal regarding "const" in the
context of Java, and provides experience with a prototype
implementation. The paper will appear in OOPSLA 2004, and
comments on
the proposal or the paper are welcome. The abstract appears
below,
and you can find the paper itself at:
http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004-abstract.html
A practical type system and language for reference immutability
Adrian Birka and Michael D. Ernst
To appear in OOPSLA 2004
This paper describes a type system that is capable of
expressing and
enforcing immutability constraints. The specific constraint
expressed is that the abstract state of the object to which an
immutable reference refers cannot be modified using that
reference.
The abstract state is (part of) the transitively reachable
state:
that is, the state of the object and all state reachable
from it by
following references. The type system permits explicitly
excluding
fields or objects from the abstract state of an object. For a
statically type-safe language, the type system guarantees
reference
immutability. If the language is extended with downcasts, then
run-time checks enforce the reference immutability constraints.
In order to better understand the usability and efficacy of
the type
system, we have implemented an extension to Java, called Javari,
that includes all the features of our type system. Javari is
interoperable with Java and existing JVMs. It can be viewed
as a
proposal for the semantics of the Java "const" keyword, though
Javari's syntax uses "readonly" instead. This paper
describes the
design and implementation of Javari, including the type-checking
rules for the language. This paper also discusses
experience with
160,000 lines of Javari code. Javari was easy to use and
provided a
number of benefits, including detecting errors in
well-tested code.
Submitted On 08-JUL-2004
JessHolle
Actually JoeSB's idea of using 1.5's annotations via an @const or some such seems quite interesting.
In general providing additional design-by-contract features via annotations and compiler warnings and/or errors based on these annotations seems promising. The annotation processor could default to these being warnings, but these could be boosted to errors for clean, new code areas in large projects. Moreover, static analyzers could look at the annotations in the resulting class files and allow one to audit violations, mark known violations (or violations against certain packages) as "ignore", and alert one to new violations.
Overall, this would allow a "strict as you need it" approach -- assuming core libraries like rt.jar were well annotated for design-by-constract concerns like constness.
Submitted On 08-JUL-2004
David Silver
I consider this a misguided attempt to turn Java into C++.
After six years of programming in C++, coming to Java
(back in 1998) was a relief. Finally , a language where the
other programmers on my team didn't have a loaded gun
pointed at *my* foot (let alone the bloody stumps they were
hobbling around on). It wasn't just the safety afforded by
Java's memory model. It was also the fact that my code
was now immune to shoddy, non-const correct code.
class Shoddy
{
private int x;
public int getX() // NOT const-correct
{ return x; }
}
class UsesShoddy
{
private Shoddy shoddy;
public int getY() const // Now I'm in const-correctness hell.
{ return shoddy.getX(); } // ERROR: getX() is not const.
}
The solution in C++ is an ugly const_cast<> of this.
According to supporters of this RFE, however, we should
never need to cast away const or declare fields mutable.
In that case, the only solution is to not use the
non-const-correct class, or rewrite it. Got some old code
that isn't const correct? Re-write it. Only got the class
files? Tough luck.
The point I want to make is that const correctness is an
all-or-nothing affair. (Particularly if you want to be autocratic
about disallowing const casts.) If you want to be
const-correct, you'd better hope that everybody else is too.
Honestly, this RFE has the hallmarks of a deliberate attempt
to sabotage the language. It won't be getting my vote.
I really wish that votes could be cast against RFEs, as well
as for them, because despite the number of votes for this, I
wonder if they are a true indication of how the community
feels about this. Sun: take note.
Submitted On 08-JUL-2004
JessHolle
Despite previous comments on my part in favor of this RFE, I do have to agree with David Silver on one point: in C++ const-awareness/safety *is* an all or nothing affair -- at least from the point of core, etc, libraries on up. In general, a given body of code effectively cannot use const unless all the libraries it directly depends on make proper use thereof.
This means that this RFE would require at least the level of backwards and cross-library compatibility design work that went into 1.5's generics. Without such finely finessed solutions as we now see in 1.5 generics, this RFE *would* be harmful.
In essense, if this can't be done right then the cure is worse than the disease....
Submitted On 22-AUG-2004
hlovatt
musheno, see the Immutable pattern here:
https://pec.dev.java.net/nonav/compile/index.html
For how you might enforce immutability with a compiler. You can also vote for Immutable types in Java here:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4617197
Submitted On 22-AUG-2004
musheno
If I am not mistaken, that would be impossable, as a subclass would be free to override that piece of functionality, plus, to allow non mutability you could only send cloned objects, but there is no way to ensure this, as the compiler would have to process the entire call chain, and what happens when the framework I rely upon changes, My code will not compile, or wolnt run? Plus how will the compiler "Ensure" the method is non mutable (including any delagated mutations)?
Submitted On 07-SEP-2004
171110
The last official evaluation is from 1999 - 5 years ago. It's #2 RFE, couldn't Sun provide an updated evaluation with more detail?
Submitted On 15-SEP-2004
NiclasH
I totally agree with David Silver's post on 2004-July-08.
Although it 'seems' like a good idea at first, it is a very nasty feature that really screws up for others when misused.
Submitted On 17-SEP-2004
Quartz
I agree that this would be one more featurism for the language. I'm already cautious about the static imports AND autoboxing (however, I like the idea of generics and full-fledged enums). There are quite a few compilers that can help you with that, if you so desire (google JML). Anotations might help some time in the future. As soon as people figure out how to make them work with the new instrumentation layer...
Submitted On 30-SEP-2004
aldo_g
I agree partially resolve this using 1.5 annotations, for parameters and methods, and let the compliler check
posible violations
Submitted On 03-OCT-2004
herohero3
i'm agree that it is a great enhancement but plx think about these :
1) For these C, C++ developer PLX study the the usage of "final" key word clearly b4 air ur opinion here. cuz "final" can do most of the stuff that "const" can.
2) Const parameters: no pass by reference in java. do we need const parameters?
3)Also we can do something like this:
void function(final Object Foo){}
4) u can use the immutable design pattern
Submitted On 03-OCT-2004
herohero3
i read some of ur opinion is just want to eliminiated the cloning of array so why not just adding a "readonly" key word for array of all diminension just like that of c#
Submitted On 12-OCT-2004
muminc
One vote from me. This is one feature that I really miss from c++
Submitted On 15-OCT-2004
jaubourg
(my apologies for the possible english mistakes to come: english is not my mother tongue... thanks)
I find the reactions against a const modifier quite stunning.
But, surely, it
Submitted On 15-OCT-2004
jaubourg
(too big a post? I'll split)
I find the reactions against a const modifier quite stunning.
But, surely, it's Sun's answer that puzzles me the most:
"One can design around this (using interfaces, wrappers etc.)"
Really? And to what extend?
Let's take a simple example (and with generics, why not?):
public interface Setter<T> {
public void set(T value);
}
public interface Getter<T> {
public T get();
}
public interface Container<T> extends Setter<T>, Getter<T> {
}
All right, so we have our interfaces. Let's get to the implementation:
public class DefaultContainer<T> implements Container<T> {
private T object = null;
public void set(T value) { object = value; }
public T get() { return object; }
}
Since we wanna be able to enforce immutability, we need a wrapper:
public final class ImmutabilityWrapper<T> implements Getter<T> {
private final Container<T> container;
public ImmutabilityWrapper(Container<T> c) { container=c; }
public T get() { return container.get(); }
}
Submitted On 15-OCT-2004
jaubourg
Here, so everytime I wanna ensure immutability, I wrap my Container in an
ImmutabilityWrapper and my problems are handled, right?
NO WAY!
For instance, let me code a completely stupid subclass of DefaultContainer:
public class StupidContainer<T> extends DefaultContainer<T> {
public T get() { set(null); return null; }
}
Hmmm... What's going on?
Now an ImmutabilityWrapper that wraps a Container is not guaranteed to prevent changes
made to the internals of the Container because we have created a new subclass that breaks
the tacit contract.
TACIT: That's the problem. Take a look at the JDK javadoc and count the number of methods
for which the doc specifically states which methods will be called on every single parameter
and on the object itself (because you realize that's the only way you can know what behavior
to expect out of the call): of course, none.
Beside, the documentation has no value when it comes to compile-time checks, so what would
be the point?
Believe me, breaking a tacit contract happens more often than one would desire, especially
in big projects with lots of people involved, and it is definitly not always as obvious
as the StupidContainer example.
So back to our problem. How can we prevent this?
1) "Let's make DefaultContainer final!"
cool, what prevents me from directly implementing Container?
2) "Screw this interface, let's make an abstract class"
I can still subclass it and redefine its methods
3) "All right, so let's make the method final... or even the class: done!"
Sure, now that you don't have interfaces, how will you provide an immutability wrapper?
4) "Bah! through another class, of course!"
What if I want to have another kind of immutable getter? I can't subclass since
get is final now.
You can toy around all you want, there are only two ways to GUARANTEE immutability:
1) scraping inheritance altogether: you provide only final classes (or classes with
critical methods being final) and you forget about interfaces. Good bye Mr.OO Design.
Let's be honest, you CAN do without interfaces... just use reflexivity. Hello Mr.
Cumbersome Code.
2) you clone every single object you pass as a parameter and don't want changed, before
every single call. Hello Mr.Garbage Collector.
Sure, nice workarounds.
And please note I didn't take a complicated example. There are much more intricated situations
where there are strictly NO workaround.
Submitted On 15-OCT-2004
jaubourg
I generally stay away from this kind of "philosophical" discussions. You know: people want
something that looks like a feature from another language. Other people say they're fanboys
of the given language, that java is better that way, that the earth is flat and so on and so
on.
I've been programming in Java for a good ammount of time now and I had been programming with
C, C++ and Ada before. I won't list Java's strengths in regard to other languages: suffise
to say it has quite a lot, at least enough for it to be my programming language of choice
(and I'm not alone, am I?).
However, this very RFE raises some interesting questions concerning Sun's policy regarding
Java's future. Since Day 1 is the lack of expressiveness in method contracts the obviously
weakest point in all of the language specification. This is really no news... and I am
NOT saying the situation is better in such or such language, I'm just saying we have a
LACK here.
Where are we at now? We have annotations (which require quite intricated reflection API
calls for runtime management) and we have generics (which current implementation, as far
as I'm concerned, given the warning noise level and lack of RTTI, is nothing more than a
proof of concept).
I will make the best use I can out of all these new constructs because I believe they enhance
the language. However, it saddens me that adding const correctness in Java is officially
regarded by Sun as "creaping featurism". Contract specification is unavoidable if and when
one works on a huge code base. If we can load classes at runtime unknown at compile time,
in a flexible OO world where subclassing (and more specifically, implementing) is the design
of choice, then we DO NEED const correctness ensured or else the state of the program can
go havoc with no way for the developper to work against it preemptively.
The workarounds currently used do not avoid the issue, they just give coders the illusion the
problem is solved, leading to more difficulties when the program's behavior becomes erratic for
no apparent reason.
So, please, tell us this is not a priority from your point of view but don't pretend this is
not a problem.
Submitted On 25-OCT-2004
hlovatt
jaubourg,
See the Immutable pattern here:
https://pec.dev.java.net/nonav/compile/index.html
For how you might enforce immutability with a compiler.
This compiler is a free download under LGPL.
You can also vote for Immutable types in Java here:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4617197
Both the above links show how immutability can be
enforced and solve the problem you posted.
Submitted On 24-NOV-2004
hwc
I support hlovatt's proposal but there's still the question of how to make better use of existing code.
Perhaps we can start with const methods. There could be a @pure annotation, checked by the compiler, to indicate that a method does not modify the object. Such a method could only be overridden by another @pure method.
Then we have const references, marked @const. No methods can be called through a @const variable unless they are marked @pure. Similarly, elements of a @const array cannot be modified.
Then we have const classes. This suggests another annotation, @immutable, indicating that public member variables are not only final but also @const, and that all public methods are (implicitly or explicitly) @pure. This attribute could (and should?) be applied to classes such as java.lang.String.
Finally we have immutable values which behave like primitives: never null, no ==, not synchronised etc. This seems a stronger guarantee than annotations can provide, hence the need for a new compiler like hlovatt's PEC, but perhaps const annotations are a useful step from current Java.
Submitted On 30-NOV-2004
hlovatt
You can do everything needed for const and more already
(no language extension is necessary or desirable), e.g.
abstract class ConstInteger {
abstract int getValue();
abstract ConstInteger instanceOfSelf( int value );
ConstInteger add( final ConstInteger rhs ) {
return instanceOfSelf( getValue() + rhs.getValue() );
}
}
final class ImmutableInteger extends ConstInteger {
final int value;
ImmutableInteger( final int value ) {
this.value = value;
}
int getValue() { return value; }
ConstInteger instanceOfSelf( final int value ) {
return new ImmutableInteger( value );
}
}
class ValueInteger extends ConstInteger {
int value;
ValueInteger( final int value ) {
this.value = value;
}
int getValue() { return value; }
ConstInteger instanceOfSelf( final int value ) {
return new ValueInteger( value );
}
void set( final int value ) {
this.value = value;
}
}
The above pattern is better than const in many ways,
including catching casting away of const on
ImmutableInteger and allowing individual visability control
(e.g. package access for ValueInteger).
The advantage of the PEC is that it checks that the
immutable integer really is immutable, see
https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/immutable/Immutable.html
for details of writting this example using the PEC.
If a JVM understood immutable, RFE 4617197, then it
would be able to do some optirmizations, as described by
hwc above, that are not possible with const.
So in conclusion I don't think that const is either necessary
or desirable, instead of refactoring old code by adding
const or writing new code with const, refactor/write using
the above pattern instead. If you want to ensure that you
have used the pattern correctly, use the PEC.
Submitted On 13-DEC-2004
gbishop
This is not a featureism, it
Submitted On 13-DEC-2004
gbishop
This is not a featureism, it's a way to strengthen a contract when programming. No reason not to do it.
Submitted On 20-DEC-2004
hlovatt
gbishop,
Except that existing mechanisms are already superior :) See post immediately above yours!
Submitted On 03-JAN-2005
Laie_Techie
gbishop, that would break the class hierchy! We would either need two separate trees (one for mutable, one for readonly) or multiple inheritance.
Besides, I believe the mutable class should inherit from the read-only one:
public class Integer
{
public int getValue();
}
public class MutableInteger extends Integer
{
public void setValue( in newValue );
}
Submitted On 03-JAN-2005
Laie_Techie
Here
Submitted On 04-JAN-2005
wwk_killer
Heh, looks like time to close this RFE -- at least until all 779 people will not evaluate third-party solution:
Submitted On 08-MAR-2004
hlovatt
I have written a compiler available for download that
includes immutables and mutables that are compiler enforced (in addition to other features).
http://pec.dev.java.net
Let me know what you think.
I will NEVER support this RFE. Or even regard as lawful.
Submitted On 04-JAN-2005
ray
And on and on it goes, making the case for Sun to free Java or developers to look elsewhere (if they haven't already). I was, as an employee of a major licensee, asking for const before Java was at version 1.0. This particular request was filed 6 years ago. And Sun has never seriously considered it or some better way to solve the problem.
Submitted On 21-JAN-2005
nevgeniev
I can't understand any objection regarding const. The immutable interfaces are completely different story.
Just imagine how fast and slim swing could be if it does not clone tons of objects on every getter...
Submitted On 27-JAN-2005
hlovatt
Are but you would have to clone. Just because your view of an object is constant doesn't mean that someone elses view is constant and the object can't change. This is the source of the const aliasing bugs in C++. The only way to avoid copying is to have immutability a const reference is not sufficient.
Submitted On 30-JAN-2005
Ixchel
I don't know how many times this has been said in this forum, but it seems that it has been ignored by certain people every time that it has been said, so I'll say it again in capitals in the hopes that, maybe, just perhaps it will finally sink in:
IMMUTABILITY AND CONST CORRECTNESS ARE TWO COMPLETELY DIFFERENT FEATURES WITH DIFFERENT INTENDED USES, WHICH SOLVE DIFFERENT PROBLEMS.
I am a big fan of immutable objects. I use them a lot in my coding. I would be thrilled if the Java language included explicit support for them. However, even if it did, I would still want enforced const-correctness AS WELL.
Immutability is not a substitute for const-correctness. In the cases where true const-correctness is desired, the only way to make immutability do the job is to make an immutable copy of every object that you want to protect from modification from even a single client.
Basically, the difference is as follows:
An Immutable object cannot be modified BY ANYBODY once it is constructed.
A const-correct object cannot be modified BY CERTAIN CLIENTS, namely those which have been handed only a 'const' reference to the object. However, other clients (those with non-const references to the object) can still modify it. This is not a bug -- it's a feature. It allows the programmer to restrict modifications to the object to only a few, carefully controlled locations, while allowing many locations to get 'read-only' access to those modifications.
These two features are NOT the same. Having support for immutable objects would not fulfill most of the needs that are making people ask for the 'const' keyword, as it is defined in C++. There are some limited forms of the 'const' keyword that can be simulated via Java interfaces, but other forms (such as arrays containing const elements) simply cannot be done in Java without wrapping the entire object in a holder class. Even the interface tricks will only work if you have the ability to modify the code of the object in question to add interfaces to it, which you certainly can't do for classes such as the JDK libraries.
The name 'const' is a bit deceptive, because it implies 'constant', and that's not what this keyword actually means. What it really means is "readonly". Immutability does not provide for readonly objects -- it only provides for truly constant ones. Thus, it is not the subject of this particular Request For Enhancement. If immutability is what you want, then RFE 4617197 will probably meet your needs. However, as should be clear from the examples given in the description, THIS RFE (which is currently at the #2 position in the most-requested language features) is for C++-style 'const', not immutability.
I would be quite happy to see both the immutability RFE and the const RFE make it into the Java language. However, they are not even close to being the same thing, and neither one can fully substitute for the other.
Submitted On 01-FEB-2005
hlovatt
Ixchel,
Yes const references and immutability are different, however if you have immutability then you don't need const references. In particular:
1. const references are often abused and used as though they are immutables leading to bugs
2. Your example of having an section of code that can change a value and a section of code that can only view the value is better accomplished using an immutable with a companion mutable (value semantics class). Change the mutable and then make an immutable version of it. See:
https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/immutable/ImmutableValueConversions.html
The advantage of using an immutable instead of a const view is that it is thread safe, e.g. in GUIs and database applications.
3. The const reference functionality you want is provided by an interface, see:
https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/immutable/Immutable.html
Particularly the section beginning "A typical development cycle". However I would recommend using it, see points 1 and 2 above.
4. Immutables can be used for arrays, see:
https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/immutable/ImmutableArrayList.html
Submitted On 14-FEB-2005
maxgilead
"Yes const references and immutability are different, however if you have immutability then you don't need const references."
If you don't care about memory overhead of creating possibly thousands of object all the time, yes, they can be used instead. But then, we can write special wrappers, so immutables are also not needed as well? This is not about what is possible or what is not, it's about making programmer more effective and your applications more bug-free and efficient.
"1. const references are often abused and used as though they are immutables leading to bugs"
Are you proposing to remove all language features which can be misunderstood by some groups of people?
"2. Your example of having an section of code that can change a value and a section of code that can only view the value is better accomplished using an immutable with a companion mutable"
See above. Programmer efficiency, application efficiency.
"3. The const reference functionality you want is provided by an interface, see: https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/immutable/Immutable.html"
With all due respect, that code is terrible, bloated and presents a method which can solve only limited range of problems.
"4. Immutables can be used for arrays"
That's irrelevant.
Submitted On 14-FEB-2005
hlovatt
In reply to maxgilead ,
I think you are missing the point, the case when the overhead of object creation is too high is a rare case and can be covered with a const interface. The common cases are best covered using immutables and therefore it is better to add immutables instead of const references.
For example immutables have far fewer bad uses than const references, so why add something (const references) that are going to get abused when we can add something that is superior instead.
Submitted On 27-FEB-2005
musheno
This is a bad idea!
Reason: if you were to impose "constantness" on a method, or variable it would cease to be mutable.
if it is not mutable, whats wrong with a final method, and have done with it.
If you are looking for a way to encapsulate a procedure, there are better ways of doing that to.
So, it cant be:
1: dont modify. (if it is use final)
2: dont modify, but do another procedure (use a procedure object, this may need work in jdk).
3: Dont modify, but allow instances to do a differant procedure (if this is the case see 2, note: base class should be non mutable).
So what do we have left? To implement this the thing must be either modifyable (ignores the whole point), or without any design scemantics (which is bad form anyway).
as there are plenty of workarounds, I say we drop this.
Todd_Musheno@yahoo.com
PS: feel free to publish, or send me mail reguarding this topic.
Submitted On 02-MAR-2005
martinr2
Doesn't a "const" keyword scheme obstruct any "lazy evaluation" pattern?
I mean:
Imagine you have a method that does _not_ change the _observable_state_ of an object, but actually _does_ change the internal state, e.g. by performing some costly computations and storing the result in some internal variable(s). Next time it's called, it doesn't perform the computation any more, but just returns the result.
It seems you can't declare the method "const" then, although it would be desirable, because the observable state is unchanged.
Am I getting something wrong?
Submitted On 03-MAR-2005
AlexLamSL
IMHO, the proposed "const" keyword would:
-bring about more inefficiencies if implemented for run-time
-leads to "Const pollution" as mentioned even if it is only implemented for compile-time
-is not a general enough "security" policy anyway so it is not worth all the trouble mentioned above
I hope others would agree with me - I can put up some examples as well if any of you like~
Submitted On 14-MAR-2005
sjasja
> Doesn't a "const" keyword scheme obstruct
> any "lazy evaluation" pattern?
Yes. String.hashCode() is a simple example. Making it
"const" (which it presumably would need to be) would
be a nasty slap in the face of the principle that interface
and implementation should be separate.
If a method is best implemented by modifying object state,
it should not be visible in the interface.
Submitted On 19-MAR-2005
Agile.Logic
The arguments presented against this feature in the evaluation are extremely weak.
Re: Creeping featurism - some would call this the evolution and enhancement of the language. This is subjective opinion only. Which features are allowed to creep and which aren't?
Re: Too late now - this is just a subjective opinion, and not backed by any fact. Why is it
Submitted On 20-MAR-2005
landrain
> The arguments presented against this feature in the evaluation are extremely weak.
I agree. Within a few months/years, they will wonder why people move to the Nice programming language.
Submitted On 21-MAR-2005
megagurka
> Doesn't a
Submitted On 21-MAR-2005
megagurka
> Doesn't a "const" keyword scheme obstruct any "lazy evaluation" pattern?
No. You add a new keyword (in C++ it's called 'mutable') which you use to indicate that a class field can be modified from a 'const' method, and that this field is not really part of the object state but only a performance enhancement. Of course you only use this keyword for caching etc.
Submitted On 21-MAR-2005
megagurka
> Yes. String.hashCode() is a simple example. Making it
> "const" (which it presumably would need to be) would
> be a nasty slap in the face of the principle that interface
> and implementation should be separate.
Wrong. Object.hashCode() is typical example of a method that would be declared as 'const'. Calling this method shall NOT modify object state. If String.hashCode() caches the result, it should do so in fields marked with 'mutable'.
Submitted On 21-MAR-2005
AlmogJava
I think its great that this RFE is canceled! Good for you Sun for showing some backbone and not giving in to idiocy and pressure from the clueless masses!
The whole
Submitted On 21-MAR-2005
fbottin
It's too late now? That's great to hear that Sun, but this RFE is SIX YEARS OLD!
Who is late then?
Submitted On 21-MAR-2005
dmbdmb
Wow, closing this issue is a really bad decision. It makes validating program correctness so much more difficult and error prone. Boo on you.
Submitted On 21-MAR-2005
cdandoy
With 787 votes, this RFE was second in the Top 25 list and it has been in the top 3 for years.
Submitted On 24-MAR-2005
sjasja
> You add a new keyword (in C++ it's called 'mutable')
Talk about a slippery slope. Kludge on top of kludge, all for the fear that somewhere there are hordes of programmers that keep accidentally modifying objects.
(Are there? I've been coding most of my life, and I can't recall ever accidentally modifying an object, or seeing someone else have an accidental modification bug. Is there a particular programming style that leads to that being such a common bug?)
If you want C++, you know where to find it. Not every language has to be C++ by another name.
Submitted On 27-MAY-2005
gkbuck
I'm glad Sun rejected this. It might have been workable had it been part of Java since day-one, but it's too late to shoehorn a solution into the language at this point. Besides, as others have pointed out, there are several ways to design around the need for it.
Submitted On 31-JUL-2005
benegiamo
Is incredible that Sun close this RFE. It's, actually, the 2nd of RFEs (also if closed...).
Reading the thread seems that instead to enhancing the language to allow better development, someone don't want break the toy and others don't want resemble too much to other existing languages.
A language is useful if developers can use it efficiently to solve problems, when a language don't help developers it must be corrected. And this issue don't help developers!
Loosing more than 6 years in a so important topic is a big error (also if the RFE was still open). And alternatives are worst: immutable classes are much more complicated that a simple keyword.
The "community contribution" don't seems to be listened too much by Sun this time.
P.S. Of course this is an extra "post-mortem" vote for this RFE.
Submitted On 15-OCT-2005
gbishop
I object.
sjasja is incorrect. It is quite common for novice developers (in my case IBM Global Services to the tune of $4M) to develop code that passes in, say a String[], whose 1st member is null if there are no errors upon return (a-la C). The String[] gets populated as a side effect of calling a method instead of throwing a normal exception.
Once this has been done there is no way to fix it. Even marking the parameter as final does not help, because it is a member of the array that is being changed, not the array itself.
Yes, of course it is poor coding style. Unfortunately it is now 12,000,000 lines and 400 files of ENTERPRISE CODE portions of which will be used for DECADES with no way to find the problems or fix them short of examining every single method.
I for one don't like reading hundreds of 2000 line methods written by novices who have very strange ideas about what "normal" coding style is.
What we need is a keyword like const or and enhanced final that marks this method and all methods descending from it for a compile-time check so that objects within it cannot be modified.
xxxxx@xxxxx 2005-03-01 22:19:57 GMT is wrong. Const (I prefer enhanced final) need not result in code "pollution". I want to mark the parameters, not the methods. Also with regard to compatibility with no code-pollution, thisalso is not a problem. Ditto for hashCode and the Collection classes. I think this shows remarkable lack of vision.
Submitted On 13-JUN-2007
Sjasja, it would seem you've never programmed in an environment with lots of programmers. If you do not like this addition, you do not have to use it, if it is, hopefully, someday added to Java. The fact that Java should be simpler and more intuitive than C++ does not bury the fact that it should include some of it's advantages.
Furthermore, it is at the very least illogical not to expand the language with new capabilities.
Submitted On 30-JUL-2007
Mark_McKay
const correctness is an excellent safety feature. Java should support it either via a const keywork or something equivilent
Submitted On 29-MAR-2008
AndrewMedico
Add my vote for const references. Letting the compiler verify contracts by checking const-correctness is a good thing.
Submitted On 18-SEP-2008
stianr
This is also a post-mortem vote for this feature. I don't think closing this shows any "backbone" as stated previously, but instead shows a total lack of understanding of the amount of control you need when you have lots of programmers (novices) and millions of lines of code that has to work properly. Having readonly parameters and methods is very powerful, and designing around the problem is _not_ a solution (you can't have core objects of the java api inherit your const interfaces can you).
Saying "I've never changed an object by mistake" is showing that the problem is not understood clearly. The problem is not that YOU change your object by mistake, but that those who wrote the class you use do so (and they intended to, but forgot to tell you).
Having a const/readonly or whatever in the parameter decleration (in C++) tells the user that the object is not supposed to be changed (which is not a big information). On the other hand, the lack of "const" states very clearly that "watch out, I WILL change your object here, so if you don't want to make a copy". The latter in my opinion is a very important piece of information when you're using ancient code written by someone not accessible, and with a sourcecode which is not inheritly understandable (sounds familiar?)...
Here's to hoping this issue will be re-opened someday and this feature added to Java (I mean there ARE a couple of good things in C++, and const is one of them).
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|