Wrapper classes are Immutable but you use them to make a function parameter a reference?

M

marcwentink

Wrapper classes are Immutable but you use them to make a primitive
function parameter a reference?

I am studying some java. My main language I am used to program in is
C++. Doing some test questions I am confused. It seems Wrapper classes
for primitives are Immutable classes, so their value cannot be changed.
But I understood that you need Wrapper classes to change the value of
say an integer when you use an integer as a function parameter and you
want that integer to change accordingly to the changes in that
function.

Is this not a paradox?

Marc Wentink
 
C

Chris Uppal

Wrapper classes are Immutable but you use them to make a primitive
function parameter a reference?

Not in the sense that a C++ programmer would mean. The C++ world gives the
word "reference" a very special meaning which is not shared by Java (or,
indeed, by much of the rest of the programming world).

The wrapper classes wrap a primitive value in an immutable object. So instead
of a variable which holds a primitive value, a 32-bit int say, you have a
variable which holds a reference to an object. The word "reference" here means
essentially the same as "pointer" (the variable holds a pointer to an object),
and has /absolutely nothing/ to do with C++'s weird "reference variables"
(where the "reference" is to another variable).

I am studying some java. My main language I am used to program in is
C++. Doing some test questions I am confused. It seems Wrapper classes
for primitives are Immutable classes, so their value cannot be changed.
Correct.


But I understood that you need Wrapper classes to change the value of
say an integer when you use an integer as a function parameter and you
want that integer to change accordingly to the changes in that
function.

Is this not a paradox?

Nope, just a misunderstanding ;-)

That isn't the purpose of the wrapper classes. If you want "value holder"
objects (as the concept is often called) then you can program them yourself.
But before you do so, give some thought to the design which makes you want
them.Usually such designs are flawed. There /are/ exceptions to that rule,
typically when the ValueHolders are used as part of some fairly sophisticated
architecture (such as using the Observer pattern to track changes to their
values). Using them to simulate C++ parameter passing semantics is not one of
the valid uses.

-- chris
 
M

marcwentink

Mijn goede vriend Chris Uppal schreef deze boodschap als constructief
advies:

(And the above is Dutch for: 'My dear friend Chris Uppal wrote this
message as constructive advice.')


Uhm, that mean the value of the integer cannot be changed, right? It
does not mean the reference to Wrapper class cannot be changed. I am
like 90% sure about this, but just to check it.
That isn't the purpose of the wrapper classes.

Then what is, since I think making a integer immutable could be done by
using a final variable?
Using them to simulate C++ parameter passing semantics is not one of
the valid uses.

Do I understand that you think passing parameters by reference is a bad
concept in itself?

Thanks a lot for the information, and I need to read a lot more about
Java still.

Marc Wentink
 
K

Karl Uppiano

Mijn goede vriend Chris Uppal schreef deze boodschap als constructief
advies:

(And the above is Dutch for: 'My dear friend Chris Uppal wrote this
message as constructive advice.')

Pardon my jumping in here... The title caught my eye...
Uhm, that mean the value of the integer cannot be changed, right? It
does not mean the reference to Wrapper class cannot be changed. I am
like 90% sure about this, but just to check it.


Then what is, since I think making a integer immutable could be done by
using a final variable?

The wrappers are for situations that require a full featured
java.lang.Object instead of a primitive, such as hash maps, or having a
monitor to synchronize on, or has several standard object methods, such as
equals(Object other) or toString(), or in the case of numbers, extends
Number, with all of the Number base methods.
Do I understand that you think passing parameters by reference is a bad
concept in itself?

Not in C++, but it is not an idiom in Java, so experienced Java programmers
would want to know what you were smoking -- unless there was an
intrinsically good design reason to use it. Most of the time, I see this
kind of "language abuse" in programs (stupidly) ported from C++ instead of
re-written to take advantage of Java features and idioms.
 
C

Chris Uppal

[The following is pretty-much a duplicate of Karl's reply -- but maybe two
views from slightly different angles will help you perceive the issue in depth
;-) ]


Uhm, that mean the value of the integer cannot be changed, right? It
does not mean the reference to Wrapper class cannot be changed. I am
like 90% sure about this, but just to check it.

You are right. You can do what you like with variables holding a reference to
a wrapper object (unless they've been declared final); but you can't change the
wrapper object itself in any way.

Then what is, since I think making a integer immutable could be done by
using a final variable?

The point of the wrapper classes is to provide a workaround for a design
error[*] in the Java language. In Java the primitive values are not objects,
and so cannot participate in many fun games that any object can play. For
instance you can't add them to a java.util.List (and Karl has given other
examples). So the wrapper classes provide a way to "disguise" a primitive
value as an object, and so let it play with the others. The workaround has (in
Java 1.5) been strengthened by adding auto-boxing to the language (for which
see Google, or ask again); auto-boxing is /another/ design error in my
opinion, but I don't doubt the designers' good intentions -- they wanted to
make it as easy as possible to use primitives as if they were objects.

([*] Some may think that "error" is too strong a word, but not me, and in any
case the stronger term gets the idea across better.)

Do I understand that you think passing parameters by reference is a bad
concept in itself?

Not really, although it's not something that /I/ would add to an OO language
design (IMO it's only there in C++ to support assignment-like operator
overloading).

In Java, and in other OO languages, I suppose, an apparent need for "out"
parameters (pass-by-reference) is usually seen as symptomatic of a design with
fewer objects than it "wants" to have.

-- and
 
K

Karl Uppiano

([*] Some may think that "error" is too strong a word, but not me, and in
any
case the stronger term gets the idea across better.)

I would be one of those. Believing as I do, that all engineering is a
compromise (trade-offs between conflicting requirements), I think the Java
language designers had to make a hard choice between lightweight fundamental
data types such as booleans and numerics.

They simply could not justify the performance overhead of allocating objects
for every data type, even automatic variables on the stack. Obviously, not
everyone agrees with that compromise, but like politics, nothing is perfect.
;-)
 
M

marcwentink

Chris Uppal schreef:
auto-boxing

I think there is a simular concept in .NET and C#, can I compare it to
that?

By the way if you want a language that is 100% about objects, there is
Smalltalk I think?
 
C

Chris Uppal

Karl said:
They simply could not justify the performance overhead of allocating
objects for every data type, even automatic variables on the stack.

There are fairly well-known techniques for avoiding that overhead. The most
widely used is to encode "some" values directly in what would otherwise be
pointers (pointers to objects in almost any sane implementation will have some
spare low-bits since the objects won't be aligned on arbitrary
byte-boundaries). That doesn't work at all for, say, 64-bit longs on a 32-bit
machine, but where it is applicable it works well -- nearly all serious
Smalltalk implementations use it, for instance, and I assume it is also widely
used in the Lisp world (they invented it, after all ;-).

Alternatively, I suspect that the state of the art in dynamic optimisation has
advanced far enough that nearly all (performance critical) use of boxed
integers could be optimised away.

-- chris
 
C

Chris Uppal

Chris Uppal schreef:


I think there is a simular concept in .NET and C#, can I compare it to
that?

There is certainly a similar concept (in fact I suspect that auto-boxing got
added to Java in part as a "me too" response to .NET). I don't know enough
about .NET (in in particular its notion of value objects) to be sure that the
two concepts are actually the same.

By the way if you want a language that is 100% about objects, there is
Smalltalk I think?

Indeed, and very nice it is too ;-)

-- chris
 
C

Chris Smith

Chris Uppal wrote (in two different posts):
There is certainly a similar concept (in fact I suspect that auto-boxing got
added to Java in part as a "me too" response to .NET). I don't know enough
about .NET (in in particular its notion of value objects) to be sure that the
two concepts are actually the same.

Just to fill in a little, they are a little different, in that with
..NET, there are value types which can be user-defined much like
reference types can. Each value type has a corresponding object type
to/from which is is boxed or unboxed. The behavior is not specific to
any specific list of primitive types.
There are fairly well-known techniques for avoiding that overhead. The most
widely used is to encode "some" values directly in what would otherwise be
pointers (pointers to objects in almost any sane implementation will have some
spare low-bits since the objects won't be aligned on arbitrary
byte-boundaries).

This is certainly not a horrible idea, but it is certainly possible to
do better. Runtime tagging does carry some performance cost, and some
cost in ranges of data types (admittedly less important).
Alternatively, I suspect that the state of the art in dynamic optimisation has
advanced far enough that nearly all (performance critical) use of boxed
integers could be optimised away.

Yes, with qualifications. In the general case, this is a global
analysis, which makes it expensive even if possible. With a few simple
language changes, it's actually trivial. If I got to wave my magic wand
and change Java, here's what I'd do.

1. Everything is an object.

2. Variables (which are now always references) are not nullable by
default, and a special syntax exists to make them nullable.

3. Reference comparison is exposed ONLY through the default
implementation of Object.equals. a==b is shorthand for saying
(a is null ? b is null : a.equals(b)). If a class overrides equals (and
doesn't expose the original in some way) then reference comparison is
not possible.

The result is a language in which it's easily type-verifiable that what
is logically a reference to some object can always be replaced by
storing a value directly in a variable under a set of conditions that
are trivially definable (namely: the class is immutable, final, and
completely hides reference comparison). Furthermore, the JIT compiler
can make judgement calls about when to do one versus the other,
depending on the size of the data in the object, how often the variable
is used in a context that requires a true object, etc. Those judgements
are potentially statistically optimizable.

But, of course, the shop has sailed for fundamental changes to language
design. Gotta save those changes for the next big language, then.
 
K

Karl Uppiano

Chris Uppal said:
There are fairly well-known techniques for avoiding that overhead. The
most
widely used is to encode "some" values directly in what would otherwise be
pointers (pointers to objects in almost any sane implementation will have
some
spare low-bits since the objects won't be aligned on arbitrary
byte-boundaries). That doesn't work at all for, say, 64-bit longs on a
32-bit
machine, but where it is applicable it works well -- nearly all serious
Smalltalk implementations use it, for instance, and I assume it is also
widely
used in the Lisp world (they invented it, after all ;-).

Alternatively, I suspect that the state of the art in dynamic optimisation
has
advanced far enough that nearly all (performance critical) use of boxed
integers could be optimised away.

Ok. But overhead was the argument given when I first heard the question
answered ten years ago. I certainly do not have the inside story on every
design decision that went into the Java language.
 
C

Chris Uppal

Chris said:
3. Reference comparison is exposed ONLY through the default
implementation of Object.equals. a==b is shorthand for saying
(a is null ? b is null : a.equals(b)). If a class overrides equals (and
doesn't expose the original in some way) then reference comparison is
not possible.

You'd probably have to strengthen that a little; as it stands there is nothing
to prevent b "exposing" its identity even though a hides its own. Adding an
extra condition that a and b are of the same class would fix the definition of
==, but that might be a bit too strong.

There are a few other places where identity is exposed too. They are trivial to
fix up, I think, but by the time you /have/ fixed them up, I suspect it'd have
been easier to go with an explicit "Does not support identity" tag on the class
(an annotation or whatever). That would determine the meaning of ==,
synchronised, identityHash() and so on, rather than each object's stance w.r.t
identity being derived from them.

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top