writeObject signature

L

Liz

An addition:

For example there's nothing that prevents the Java developers from
creating a new root of the class hierarchy,

But there's all that documentation SUN would have to change.
 
L

Lee Fesperman

Michael said:
Yes. It works with current versions of the *Java* language because every
object is an instance of Object. Therefore you can cast any object to
type Object and only therefore you can call getClass. Don't think in
Java, draw e.g. an UML static structure diagramm and you'll see, what I
mean.

I don't see any casting in the code above.

Yes, every object in Java must be an instance of Object. That can't change, so there's
no need to say current versions.

I have no idea what "UML static structure diagram" means in this context. I don't know
what you mean.
 
T

Tony Morris

Instances of X aren't instances of Object anymore. Now if writeObject
would rely on the serializable interface, the cast to Object would e.g.
result in a ClassCastException.

I want some of that stuff you're smoking.

--
Tony Morris
(BInfTech, Cert 3 I.T.)
Software Engineer
(2003 VTR1000F)
Sun Certified Programmer for the Java 2 Platform (1.4)
Sun Certified Developer for the Java 2 Platform
 
L

lyallex

The most experienced java developer/architect I know is my dog.

Fascinating, and such a useful contribution to the discussion.


"Process- How will the work and the team be organized?
The team needs to fit the culture in which it will operate,
but you should write software well rather than preserve the
irrationality of an enclosing culture" - Kent Beck
 
L

lyallex

In fact :-(


Ok, then let's assume that overriding isn't the argument. Even so, I
don't think that writeObject should take a Serializable. I think that
this has something to do with design.

If writeObject would take an argument of type Serializable, this would
only work because AFAIK all objects in (current) Java are instances of
Object.

Serializable doesn't declare any methods. If we would rely only on the
Serializable interface we wouldn't be able to use any method. E.g. there
would be no way to call getClass (because Serializable doesn't define it).

If you implement an interface in Java the the implementing class has
an 'is a' relationship with that interface. It's java's way of
providing (pseudo) multiple inheritence without many of the unpleasent
side effects of full multiple inheritence.
When you implement an interface the resulting type exists 'above' the
implementing class in the hierarchy but 'below' object

So

public class MyClass implements Serializable{

public void makeStupidComment(){
System.out.println("My dog knows Java");
}
...
}

Serializable s = new MyClass();

s.getClass() //OK, comes from Object
s.makeStupidComment(); //Can't do this because serializable is higer
up the inheritence hierarchy.

hmm, this is getting interesting.

Rgds
Lyall


"Process- How will the work and the team be organized?
The team needs to fit the culture in which it will operate,
but you should write software well rather than preserve the
irrationality of an enclosing culture" - Kent Beck
 
M

Michael Rauscher

Lee said:
I don't see any casting in the code above.

Serializable doesn't declare any methods. Therefore either the developer
or the compiler must do a cast to Object.
Yes, every object in Java must be an instance of Object. That can't change, so there's
no need to say current versions.

I don't believe that you can impress the developers of java by telling
them, that they can not do this or this.
I have no idea what "UML static structure diagram" means in this context. I don't know
what you mean.

Sloppy said: a class diagram.

+--------------------+ +--------------------+
| | <<uses>> | <<interface>> |
| ObjectOutputStream |- - - - - - - | Serializable |
+--------------------+ +--------------------+
|+writeObject( |
| a:Serializable) |
+--------------------+

vs.

+--------------------+ +--------------------+
| | <<uses>> | |
| ObjectOutputStream |- - - - - - - | Object |
+--------------------+ +--------------------+
+--------------------+
|+getClass() : Class |
|... |
+--------------------+

Between the interface Serializable and the class Object there's no
relation. In the first example, it would be wrong (or bad design) to
send a getClass message to "a" at design time, because "a" is
Serializable and Serializable doesn't declare such a method.

The fact, the in the current version of the model anything is an
instance of Object wouldn't make the design better.

That would be the same as if one method takes a Collection and
internally assumes that this Collection is a Vector:

public Enumeration getEnumeration( Collection c ) {
return ((Vector)c).elements();
}

The fact, that you've probably declared a precondition saying that c
must be an instance of Vector doesn't make the design better.

Bye
Michael
 
M

Michael Rauscher

lyallex said:
On Wed, 09 Jun 2004 20:04:47 +0200, Michael Rauscher

So

public class MyClass implements Serializable{

public void makeStupidComment(){
System.out.println("My dog knows Java");
}
...
}

Serializable s = new MyClass();

s.getClass() //OK, comes from Object
s.makeStupidComment(); //Can't do this because serializable is higer
up the inheritence hierarchy.

You can't do this because MyClass and Serializable don't build a class
hierarchy.

Your example shows exactly the design issue: if a method uses a
Serializable but want to use methods from another type, there must be in
general a (implicit or explicit) cast to the desired type.

In your example the first call leads into a cast which is done implicit
by the compiler:

((Object)s).getClass();

So, IMO it would have been bad design to take a Serializable as argument
and using methods that aren't declared by Serializable.

Bye
Michael
 
F

Filip Larsen

Roedy Green wrote
I just noticed that it is writeObject ( Object o )
rather than writeObject ( Serializable o )

how come?

From all the possible reasons already mentioned I think that the best
candidate is that some designer(s) thought that the Serializable marker
interface was an implementation detail that had no place in the API
signatures. One could indeed argue that since supporting the
Serializable marker interface do not imply serializability alone, the
compile-time benefit of using Serializable in signatures will be small;
callers of a writeObject(Serializable) would still have to prepare for
getting a NotSerializableException (or equivalent).

My personal second guess will be that the API is like that because of
practical considerations at design time, like for instance a requirement
that the serialization mechanism should able to serialize instances of
classes that was designed before or independent of the mechanism itself.
Perhaps someone with very early Java API documentation can check whether
or not the
standard classes expected to be serializable implements
Serializable. They seem to do so in Java 1.1 which is the earliest
documentation I have. From my testing on the matter with Java 1.4.2 I
haven't been able to find a class that is supposed to be serializable
but which do not implement Serializable (in fact, I even learned that
arrays
actually are instances of Serializable).

Finally, I would like to remark that if the signature was
writeObject(Serializable), then for symmetry one could argue that the
signature for readObject should be Serializable readObject() and that
would mean you couldn't deserialize into non-serializable objects like
you can today.


Regards,
 
C

Chris Smith

Michael said:
Serializable doesn't declare any methods. Therefore either the developer
or the compiler must do a cast to Object.

That's a fairly confusing way to put things, though. The word "cast" in
Java refers to a syntax for type conversion -- namely, placing the
target type name in parentheses prior to an expression. The compiler
doesn't generate source code, so it can't "do a cast".

If you would prefer to talk bytecode compiler implementation, then
neither does it insert a 'checkcast' bytecode instruction. If you
insist on talking JIT compiler implementation, there's *still* no extra
step in generated code to express an implicit type conversion. The
compiler simply indexes into the function pointer table for the object,
*knowing* that it's a valid instance of Object.

There are implicit widening conversions in Java, which are sometimes
confusingly referred to as "upcasts". Nevertheless, unless you choose
to do so unnecessarily, these conversions don't require a cast.
Besides, this isn't a widening conversion anyway. There's never a wider
type involved in this expression.
Between the interface Serializable and the class Object there's no
relation. In the first example, it would be wrong (or bad design) to
send a getClass message to "a" at design time, because "a" is
Serializable and Serializable doesn't declare such a method.

And this pretty much sums up why you shouldn't become obsessed with UML
for making design decisions for you. Here you're confusing a quirk of
the UML modelling format with justification for API design. Let me put
this simply: there's absolutely no good reason to avoid calling methods
of java.lang.Object via an interface type. When you start considering
that, it's a good sign that you're letting your desire to do "clean"
design interfere with your ability to use the language you're working
in.
The fact, the in the current version of the model anything is an
instance of Object wouldn't make the design better.

"The current version of the model"?

You seem to be missing the point. You are apparently picking one out of
a potential seven billion changes that could be made to Java -- and a
*very* unlikely one at that -- and advocating designing around the
possibility that the language might change in that way. If the language
changes that dramatically, or (far more likely) if you decide on a
different implementation language or write bindings for a different
language, you're going to have a *lot* of porting and adaptation to make
your code work, and whether your API is declared to take an interface
parameter or not in Java is just plain insignificant in that scenario.

So why not design around the possibility that Sun might eliminate
interface types entirely, or that you might switch to a language that
doesn't have those? Or ever better, what about automatic memory
management? Should I be designing my Java APIs to manage who has
responsibility for reclaiming memory, even though it really doesn't need
to be done at all? After all, Sun might change Java to eliminate the
garbage collector, or I might decide to provide a C++ interface to the
library. What then?
That would be the same as if one method takes a Collection and
internally assumes that this Collection is a Vector:

public Enumeration getEnumeration( Collection c ) {
return ((Vector)c).elements();
}

Well, no it's not. One situation involves a type conversion that's not
guaranteed to succeed. The other involves no conversion at all, but
rather simply using the reference according to its declared interface.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
T

Tony Morris

If you implement an interface in Java the the implementing class has
an 'is a' relationship with that interface. It's java's way of
providing (pseudo) multiple inheritence without many of the unpleasent
side effects of full multiple inheritence.
When you implement an interface the resulting type exists 'above' the
implementing class in the hierarchy but 'below' object

Not quite true.
What you are describing is the Decorator Design Pattern.
This does not assist you in "working around" lack of multiple inheritance.

Single-inheritance, together with the Adapter Design Pattern, is what helps
you with that.

I'd draw a little UML diagram for you, but...

--
Tony Morris
(BInfTech, Cert 3 I.T.)
Software Engineer
(2003 VTR1000F)
Sun Certified Programmer for the Java 2 Platform (1.4)
Sun Certified Developer for the Java 2 Platform
 
M

Michael Rauscher

[Essay on why I had better not used the word "cast"]
There are implicit widening conversions in Java, which are sometimes
confusingly referred to as "upcasts". Nevertheless, unless you choose
to do so unnecessarily, these conversions don't require a cast.
Besides, this isn't a widening conversion anyway. There's never a wider
type involved in this expression.

Excuse my sloppy usage of the word "cast". But if you want to be that
precise: it *is* a widening conversion as stated in 5.1.4 of the JLS:

- From any interface type to type Object.
And this pretty much sums up why you shouldn't become obsessed with UML
for making design decisions for you. Here you're confusing a quirk of
the UML modelling format with justification for API design. Let me put
this simply: there's absolutely no good reason to avoid calling methods
of java.lang.Object via an interface type. When you start considering
that, it's a good sign that you're letting your desire to do "clean"
design interfere with your ability to use the language you're working
in.

So I assume, that you'd find it better to have the writeObject method
taking a Serializable as an argument, because of your ability to use the
language.
"The current version of the model"?

You seem to be missing the point. You are apparently picking one out of
a potential seven billion changes that could be made to Java -- and a
*very* unlikely one at that -- and advocating designing around the
possibility that the language might change in that way. If the language
changes that dramatically, or (far more likely) if you decide on a
different implementation language or write bindings for a different
language, you're going to have a *lot* of porting and adaptation to make
your code work, and whether your API is declared to take an interface
parameter or not in Java is just plain insignificant in that scenario.

As you like to be precise: the language doesn't change just because the
class library changes.

And as I seem to be missing the point:
- let the Java developers change the writeObject method
- let the Java developers introduce another Serializable-like interface
- let the Java developers deprecate the Serializable interface

And now?

But perhaps I'm wrong and I should not desire to have a clean design to
not interfere with the ability to use the language I'm working in...
So why not design around the possibility that Sun might eliminate
interface types entirely, or that you might switch to a language that
doesn't have those? Or ever better, what about automatic memory
management? Should I be designing my Java APIs to manage who has
responsibility for reclaiming memory, even though it really doesn't need
to be done at all? After all, Sun might change Java to eliminate the
garbage collector, or I might decide to provide a C++ interface to the
library. What then?

Extending the class library isn't changing the language.
Well, no it's not. One situation involves a type conversion that's not
guaranteed to succeed. The other involves no conversion at all, but
rather simply using the reference according to its declared interface.

The other involves an implicit widening reference conversion.

Chris, as you obviously disagree with my opinion: I didn't see your
answer/opinion to the question, how it comes that it is
writeObject(Object o) and not writeObject(Serializable s).

Bye
Michael
 
M

Michael Rauscher

An addition:

Michael said:
lyallex said:
]


So
public class MyClass implements Serializable{

public void makeStupidComment(){
System.out.println("My dog knows Java");
}
...
}

Serializable s = new MyClass();

s.getClass() //OK, comes from Object
s.makeStupidComment(); //Can't do this because serializable is higer
up the inheritence hierarchy.


You can't do this because MyClass and Serializable don't build a class
hierarchy.

Your example shows exactly the design issue: if a method uses a
Serializable but want to use methods from another type, there must be in
general a (implicit or explicit) cast to the desired type.

In your example the first call leads into a cast which is done implicit
by the compiler:

((Object)s).getClass();

The above is wrong: to be precise s.getClass() is a widening reference
conversion.
 
L

lyallex

Not quite true.
What you are describing is the Decorator Design Pattern.
This does not assist you in "working around" lack of multiple inheritance.

Single-inheritance, together with the Adapter Design Pattern, is what helps
you with that.

I'd draw a little UML diagram for you, but...

well a picture of the Object graph for the
Object <- MyClass -> Serializable hierarchy would be better
I can do the UML but I can't yet visualise what the graph would look
like

Rgds
lyallex


"Process- How will the work and the team be organized?
The team needs to fit the culture in which it will operate,
but you should write software well rather than preserve the
irrationality of an enclosing culture" - Kent Beck
 
L

lyallex

Roedy Green wrote


From all the possible reasons already mentioned I think that the best
candidate is that some designer(s) thought that the Serializable marker
interface was an implementation detail that had no place in the API
signatures. One could indeed argue that since supporting the
Serializable marker interface do not imply serializability alone, the
compile-time benefit of using Serializable in signatures will be small;
callers of a writeObject(Serializable) would still have to prepare for
getting a NotSerializableException (or equivalent).

My personal second guess will be that the API is like that because of
practical considerations at design time, like for instance a requirement
that the serialization mechanism should able to serialize instances of
classes that was designed before or independent of the mechanism itself.
Perhaps someone with very early Java API documentation can check whether
or not the
standard classes expected to be serializable implements
Serializable. They seem to do so in Java 1.1 which is the earliest
documentation I have. From my testing on the matter with Java 1.4.2 I
haven't been able to find a class that is supposed to be serializable
but which do not implement Serializable (in fact, I even learned that
arrays
actually are instances of Serializable).

Ah, I was wondering about arrays, that's another piece of the puzzle
in place.

ObjectOutputStream implements java.io_ObjectOutput and provides an
implementation of writeObject as defined in that interface. It would
obviously not be a good idea to require that all arguments be
Serializable in the declaration of this method in the ObjectOutput
interface as that would reduce the flexibility of this interface.

If you look at the code for ObjectOutputStream there is the following
if statement

// remaining cases
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else {
throw new NotSerializableException(cl.getName());
}

I can see no explicit casting going on here (or anywhare in this class
for that matter) but there is an explicit check for 'Serializableness'
It seems therefore that the requirement that a class implement
Serializable is an internal requirement of the implementation of this
method in this class therefore it doesn't make sense to force the
argument to be Serializable as you would still need to provide an
implementation of writeObject that took an Object as argument.

So I would agree with the first statement of this reply

"From all the possible reasons already mentioned I think that the best
candidate is that some designer(s) thought that the Serializable
markerinterface was an implementation detail that had no place in the
APIsignatures"

I'm sure somone will put me straight if I've missed something.

Finally, I would like to remark that if the signature was
writeObject(Serializable), then for symmetry one could argue that the
signature for readObject should be Serializable readObject() and that
would mean you couldn't deserialize into non-serializable objects like
you can today.

Another good point

Rgds
lyallex



"Process- How will the work and the team be organized?
The team needs to fit the culture in which it will operate,
but you should write software well rather than preserve the
irrationality of an enclosing culture" - Kent Beck
 
D

Dale King

Hello, Roedy Green !
You said:
I just noticed that it is writeObject ( Object o )
rather than writeObject ( Serializable o )

how come?

writeObject in ObjectOutputStream is an implementation of the
writeObject method specified in the more general ObjectOutput
inteface which it implements. The interface has no restrictions
on what type of object you can write. You can write your own
implementation of ObjectOutput that is not restricted to
Serializable. And you can also do the same thing with your own
subclass of ObjectOutputStream as well. It provides hooks to
override the default behavior suchthat you could write objects
that do not implement Serializable.
 

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

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top