Java type-casting -- Q3

M

markspace

grz01 said:
I pasted your code into Eclipse to look at it,
and I *do* get a warning on both return-statements:

Type safety: Unchecked cast from Object to T

That's odd, I'll have to look into that. I didn't notice one.

Try this:


import java.util.HashMap;
import java.util.Map;


/** A type safe heterogeneous container.
*
* @author Brenden
*/
public class HeterogeneousContainer {

Map<String,Class<?>> namesAndTypes;
Map<String,Object> values;

public HeterogeneousContainer( Map<String, Class<?>> namesAndTypes )
{
this.namesAndTypes = new HashMap<String,Class<?>>( namesAndTypes );
values = new HashMap<String,Object>( namesAndTypes.size() );
}

public <T> T get( String name, Class<T> type ) {
if( type == namesAndTypes.get( name ) ) {
return type.cast( values.get( name ) );
}
else {
throw new IllegalArgumentException( "Pair (" + name + ", "+
type+") do not exist." );
}
}

public <T> T put( String name, Class<T> type, T value ) {
if( type == namesAndTypes.get( name ) ) {
return type.cast( values.put( name, value ) );
}
else {
throw new IllegalArgumentException( "Pair (" + name + ", "+
type+") do not exist." );
}
}

public static void main( String[] args )
{
HashMap<String,Class<?>> namesAndTypes = new
HashMap<String,Class<?>>();
namesAndTypes.put( "first", String.class );
namesAndTypes.put( "second", Integer.class );
HeterogeneousContainer test = new HeterogeneousContainer(
namesAndTypes );
test.put( "first", String.class, "A String");
test.put( "second", Integer.class, 4 );
String s = test.get( "first", String.class );
Integer i = test.get( "second", Integer.class );
System.out.println( "Values: " + s + i );
}
}
 
L

Lew

grz01 said:
I pasted your code into Eclipse to look at it,
and I *do* get a warning on both return-statements:

Type safety: Unchecked cast from Object to T

There is a style of programming that permits generic casts deep enough in an
API, with suitable warning suppression. It's avoidable when you have a
'Class' instance handy.

public <T> T put( String name, Class<T> type, T value )
{
if( type == namesAndTypes.get( name ) )
{
return type.cast( values.put( name, value ));
}
else
{
throw new IllegalArgumentException(
"Pair ("+ name +", "+ type +") do not exist." );
}
}
 
M

Mayeul

grz01 said:
Im sure you did...

But, in trivial cases like this, why exactly is that Interval
class a better solution than using Pair<Date, Date> or something?
Which is, at least, just a simple and easy.

- Because reading the type Interval is fairly more describing than
reading the type Pair<Date, Date>.

- Because interval.start is fairly more describing in client code than
p.member1 is.

- Because the same goes for interval.end and p.member2.

Here is not a reason why Pair<Date, Date> would be better:

- There is very little potential for usefulness in having a type that
can both represent a time interval and the birthdays of a married couple.
Plus saves you from bloating your code with yet another
<flame-warning>silly</flame-warning> JavaBean class :)

Not really. You often need to do it this way in Java anyway, the Java
base library itself does just that all the time. Hide every classes you
can in some package not exposed by your API if this bloat bothers you so
much. To be honest, I've met a lot of situations where bloat complicates
the task of doing something, and we don't have an example of it here.
If the Interval type is part of an API - yes - Interval
is probably the better choice.

I'm nitpicking here, but I actually wonder - Why? Even better, is it not
part of your API the moment you define it and return it from one of your
methods?
But for all the internal logic of a class or library, etc,
where these "one-off" things keep popping up daily...?

I say, Dont Repeat Yourself.

I think the point is: making Interval and CoupleBirthdays is not a
repetition.
 
G

grz01

Ah, well...maybe we can simplify your life quite a bit then.

Here, check this out:

     Pair<Integer, String> getData();

Now, tell me everything there is to know about the data being returned by  
the method.  What, exactly, will I find there?  How are the Integer and  
String related?  What do the Integer and String represent?  Why do they  
belong together?

The fact is, you can't answer those questions.  The name of the type isn't  
informative at all.

Enjoy your retirement!

Pete


Well, I see what you mean :)

I would rather offer a method, for example.

Pair<Integer, String> getAgeAndName() {...};

The caller might then say:

Pair<Integer,String> ageAndName = getAgeAndName();
Integer age = ageAndName.getFirst();
String name = ageAndName.getSecond();


No less, no more informative, that I can see, than first defining
this:

class AgeAndName(){
// ... here repeat yourself til you die by defining
// getAge(), setAge, getName(), and setName()
}

and then defining method:

AgeAndName getAgeAndName(){...};

where the caller might then say:

AgeAndName ageAndName = getAgeAndName();
Integer age = ageAndName.getAge();
String name = ageAndName.getName();

I just dont see the obvious advantage in bloating your code with silly
JavaBeans like this.

I do see the several advantages in not repeating yourself
unnecessarily.
 
G

grz01

I think the point is: making Interval and CoupleBirthdays is not a
repetition.

I think the crucial point rather is:
Would you ever consider changing your implementation, or something...

Per your reasoning, I conclude,
one should also never use "naked" Integers like:

Integer pointInTime = ...;
Integer birthday = ...;

but rather first define two JavaBeans classes Birthday and
PointInTime,
with only one getter and one setter each, and then say

PointInTime pointInTime = ...;
Birthday birthday = ...;

because PointInTime and Birthday are different things, right?

Working with Integers without putting them in JavaBean classes
would then be restricted to pure number-theory applications
or something, where the Integers are used only for the sake
of studying them as Integers, and never represent anything
particular in the physical world.
 
G

grz01

Really?  You don't see the advantage of having methods named "getAge()"  
and "getName()"?

Uh, okay.  Good luck with that.

Pete



Did you also see the line just before that?

Pair<Integer,String> ageAndName = getAgeAndName();

It's just like when you write a code-line:

String companyName = getCompanyName();

You use sensible *variable names* and *method names*, to make it clear
what we are dealing with.
 
M

Mayeul

grz01 said:
I think the crucial point rather is:
Would you ever consider changing your implementation, or something...

Not really a point, because you don't have a choice here. Pair<A, B> and
its members are not self-describing and offer little to no type
checking, case closed. Java offers no way to return and meaningfully
type and name two objects at once, case closed too.

There is no convincing solution without creating a holder class here,
and it really 'looks like' the Java way, the way it is meant.

Besides, the moment I need a holder class is often the moment I delegate
some trivial logic to it. For instance I can make it a SomethingResponse
class and shove some context and status in it if useful later. An
Interval will quickly have a duration() method, a CoupleBirthdays a
youngest() method (admittedly, only if I need the birthdays ordered
sooner or later, which is not a given.)
Per your reasoning, I conclude,
one should also never use "naked" Integers like:

Integer pointInTime = ...;
Integer birthday = ...;

but rather first define two JavaBeans classes Birthday and
PointInTime,
with only one getter and one setter each, and then say

PointInTime pointInTime = ...;
Birthday birthday = ...;

because PointInTime and Birthday are different things, right?

Working with Integers without putting them in JavaBean classes
would then be restricted to pure number-theory applications
or something, where the Integers are used only for the sake
of studying them as Integers, and never represent anything
particular in the physical world.

I actually see this as a tradeoff between, on one side:

- Actual speed in development - including direct usability of base types
in all existing APIs.
- Guaranteed knowledge the client has on the types
- Not really insane explosion of different classes

And on the other side:

- Finely-tuned type checking
- Flexibility in data representation and extensibility

Sometimes the later side offers enough to outweigh the former. Certainly
not most of times, at least not for me, but it does happen. The trick
is, when I need to return two objects, there isn't a choice anyway.
 
S

stefan hemma

Not really a point, because you don't have a choice here. Pair<A, B> and
its members are not self-describing and offer little to no type
checking, case closed. Java offers no way to return and meaningfully
type and name two objects at once, case closed too.

There is no convincing solution without creating a holder class here,
and it really 'looks like' the Java way, the way it is meant.

Besides, the moment I need a holder class is often the moment I delegate
some trivial logic to it. For instance I can make it a SomethingResponse
class and shove some context and status in it if useful later. An
Interval will quickly have a duration() method, a CoupleBirthdays a
youngest() method (admittedly, only if I need the birthdays ordered
sooner or later, which is not a given.)









I actually see this as a tradeoff between, on one side:

- Actual speed in development - including direct usability of base types
in all existing APIs.
- Guaranteed knowledge the client has on the types
- Not really insane explosion of different classes

And on the other side:

- Finely-tuned type checking
- Flexibility in data representation and extensibility

Sometimes the later side offers enough to outweigh the former. Certainly
not most of times, at least not for me, but it does happen. The trick
is, when I need to return two objects, there isn't a choice anyway.

OK, looks like we found some common level of agreement then ... :)
Only your tolerance for repetitive coding is a trifle higher than
mine...

Cheers,
 
M

markspace

grz01 said:
But, in trivial cases like this, why exactly is that Interval
class a better solution than using Pair<Date, Date> or something?
Which is, at least, just a simple and easy.

Plus saves you from bloating your code with yet another
<flame-warning>silly</flame-warning> JavaBean class :)


You seem to have a real thing about Java Beans. I don't use them much,
so I can't speak about their architecture, but Internval was only a Java
Bean on accident. It had three methods starting with the word "get",
and that was it.

If the Interval type is part of an API - yes - Interval
is probably the better choice.

But for all the internal logic of a class or library, etc,
where these "one-off" things keep popping up daily...?


These one-off things are specific to the problem domain. There's no way
the Java API could anticipate them or provide them for you.

I say, Dont Repeat Yourself.


I looked at the article on Wikipedia. While that hardly makes me an
expert, I noticed this:

"When the DRY principle is applied successfully, a modification of any
single element of a system does not change other logically-unrelated
elements."

Interval had three methods: getStart, getEnd and getInterval. The
latter just computed end - start, but if that was left out, I'd have to
put that logic (end-start) everywhere through-out the code.

If I needed to change the values stored with Interval, to a start time
and a delta, for example, then I'd have to find every place in the code
that I used (end-start) and replace it with a new calculation.

And if I used "Pair" without the ability to change getter names, I'd
have to find all those uses manually. Not nice.

So Interval implemented basic encapsulation for me. Whether that
constitutes DRY or not, I'm unsure. However, if it did violate DRY,
then I believe DRY is the wrong paradigm to use for this problem.

And, after all those years, Im afraid,
I'll probably keep saying that until the end of days :)


"Moderation in all things," -- paraphrased, Aristotle
 
G

grz01

Interval had three methods: getStart, getEnd and getInterval.  The
latter just computed end - start, but if that was left out, I'd have to
put that logic (end-start) everywhere through-out the code.

Hi Mark!

I looked again at your previous msgs in this thread and my replies,
and can only confirm I agree with everything you said.

I believe this whole thread have been unnecessarily "polarized", which
is unfortunately not uncommon in these kinds of forums. When
*slightly* or *partly* opposing viewpoints meet (not yours and mine,
though) they tend to become or seem *very* opposing, because (in my
experience) us humans tend to focus on things we *dont* agree with,
rather than things we *agree* with.

Looking back, I see I missed a sentence in one of your msgs, thats why
my reply there wasnt quite appropriate.

Youre totally right, of course, if a JavaBean has *other* significant
methods, than just plain setters and getters, its not a "silly" bean
at all -- but a *good* bean. Thats what they *should* be used for...
When you want to offer different "views" of the same common data, put
validations in the setter, return *computed* values, etc, etc....
many, many valid uses.

What originally spurred the lengthy discussion in this thread was the
situation when you just want to bunch two or more things together
quite temporarily, like my example of returning two different things
of different types from a class-method, and similar stuff... thats
where I truly wish the Java language or the std lib had some more
sensible mechanism for us developers than creating a custom JavaBean.

And that's mainly what I had in mind during this whole thread.

OK, hope that cleared up any possible "ponderings" you might've had :)

Cheers,
 
L

Lew

Nearly every POJO class written in Java should be a Bean if it has attributes.

At its bare minimum, the requirement for beanhood is to use getters and
setters for attributes. One doesn't have to add bean listeners and event
handlers.

Using getters and setters for attributes in Java is a universal idiom and a
best practice.

The OP's obsession with labeling every class in a program "bloat" or "silly"
seems predicated on a valid design principle: avoid bloat.

But he begs the question by labeling everything "bloat" indiscriminately.

Please, grz01, remember that the winning chess player sees the merit of his
opponent's strategy.

Rules of thumb are neither universal nor tyrannical. That code bloat is bad
does not imply that all code is bloat.

I suspect the problem is not of philosophy or practice but of description.
You espouse good practices; I feel you must understand the compromises and
balances in practice and are simply expressing your viewpoint didactically.
(Here I exemplify "Pot calling the kettle black.") This hypothesis gains
strength in light of your response.
Hi Mark!

I looked again at your previous msgs in this thread and my replies,
and can only confirm I agree with everything you said.
....
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,233
Latest member
AlyssaCrai

Latest Threads

Top