Generics annoyance

M

markspace

Here's a little issue from my code that bugging me right now. I have a
generic class that implements Callable<Void>

private class SortTask<T extends Comparable<? super T>>
implements Callable<Void>
{
...
@Override
public Void call()
throws Exception
{
...
}
}

When I use this class, the compiler doesn't seem to recognize that
SortTask implements Callable. It insists on issuing an unchecked warning.

SortTask task = new SortTask<T>( a, l, i - 1, counter );
executor.submit( task ); // Unchecked

To alleviate this warning I made a new variable and assigned "task" to
that. However this makes me suspicious that there's a hidden cast in
there now, and I'd prefer not to do that because the algorithm is very
time critical.

SortTask task = new SortTask<T>( a, l, i - 1, counter );
Callable<?> call = task; // Hidden cast?
executor.submit( call );

So I'm wondering if there's a better way to do this. If I make SortTask
non-generic, then the compiler spots the "implements Callable<Void>"
just fine, and doesn't complain. This strikes me as a bug in the
compiler. But it also leads to other problems with generics, so I think
I need to use the generic version of SortTask for now.

If anyone could point out a better way of doing this, I'd appreciate it.
 
M

markspace

Your 'task' variable is declared without <T> (or <?>?). Does that make
a difference?


Well that was annoying. I refactored from a SortTask that wasn't
generic. After eliminating the all the errors, I was left with a
warning on the executor.submit() invocation. You'd think maybe the
compiler would complain about the raw type instead?

Anyhoo, that was it. Thanks for spotting that.
 
D

Donkey Hottie

Here's a little issue from my code that bugging me right now. I have a
generic class that implements Callable<Void>

However this makes me suspicious that there's a hidden cast in
there now, and I'd prefer not to do that because the algorithm is very
time critical.

Is a cast somehow a runtime operation? In C it used to be a compile time
operation, and does not add any runtime penalty. A warning will be
issued, but any extra code hardly will be generated. I may be wrong with
Java, though.
 
A

Alessio Stalla

Is a cast somehow a runtime operation? In C it used to be a compile time
operation, and does not add any runtime penalty. A warning will be
issued, but any extra code hardly will be generated. I may be wrong with
Java, though.

In Java a cast is a runtime operation because it implies a runtime
type check. In C a cast is merely a "promise" by the programmer to the
compiler that a certain datum is of a certain type, so if the
programmer makes a mistake no error is signaled and things break
horribly. (some casts in C and Java are actually type conversions,
e.g. from int to long).

Alessio
 
E

Eric Sosman

In Java a cast is a runtime operation because it implies a runtime
type check.

Right, except (as you mentioned later) that sometimes the
run-time action is a conversion, not a type check. I imagine
that some nearly-vacuous casts like `(int)42' or `(Object)"Hello"'
might have no run-time image at all.
In C a cast is merely a "promise" by the programmer to the
compiler that a certain datum is of a certain type,

Wrong, but the wrongness isn't especially topical for a
Java forum. C's casts -- *all* C's casts -- are conversions
(some may be vacuous).
 
A

Alessio Stalla

     Wrong, but the wrongness isn't especially topical for a
Java forum.  C's casts -- *all* C's casts -- are conversions
(some may be vacuous).

I'm going completely off topic now, but I'm curious. I know C only
superficially, and I can't understand what you said. How is, e.g.,
struct something* castPtr = (struct something*) ptr; a conversion?
Doesn't this just say to the compiler that 'castPtr' points to a
struct something, so when it will generate code for, say, castPtr-
someField, it should dereference castPtr + an offset of, say, 42 to
access someField?

Alessio
 
E

Eric Sosman

I'm going completely off topic now, but I'm curious. I know C only
superficially, and I can't understand what you said. How is, e.g.,
struct something* castPtr = (struct something*) ptr; a conversion?

It converts the value of `ptr' from whatever `ptr's type
is to the new type `struct something *'. On many systems it
happens that all data pointers have the same representation,
so the converted value is bit-for-bit the same as the original
(if `ptr' was in fact a pointer). But on some systems --
word-addressed systems, especially -- different pointer types
have different representations and sometimes even different sizes,
and the conversion actually stirs the bits around.

Example #1: C doesn't nail down the ranges of its primitive
types as tightly as Java does, with the result that `long' and
`int' sometimes share the same range and representation; they're
just different names for the same underlying "machine thing."
Yet `(long)42' is still a conversion of the value 42 from `int'
to `long' -- and on a machine where `int' and `long' are *not*
the same, the conversion actually supplies new bits that the
original value didn't have. Either way, it's a conversion of
a value from one type to another, whether the representation
changes or not.

Example #2: `(double)42' converts the value 42 from `int'
to `double', which almost certainly scrambles the bits even
though it preserves the numerical value. The cast does not say
"Just pretend the bits of the `int' constant 42 are the bits
of a `double' object." (For one thing, it's quite likely that
an `int' object has too few bits to make a `double', so "just
pretend" would be doomed from the outset.)
Doesn't this just say to the compiler that 'castPtr' points to a
struct something, so when it will generate code for, say, castPtr-
access someField?

The part that says `castPtr' points to a `struct something'
is not the cast operator, but the declaration of `castPtr' itself.
`struct something * castPtr;', even with no initialization at all,
says that much. The initialization provides a value, and the cast
operator in the initializing expression makes sure that the value
is of type `struct something *' by converting its operand's value
from whatever the operand's own type was.

Followups set to comp.lang.c, because we're really not
talking about Java any more.
 
M

markspace

Donkey said:
Is a cast somehow a runtime operation?

As other have pointed out, yes it is. However, in this particular case,
I checked the byte codes and it did appear that the compiler didn't
insert any runtime checks. In fact the "call" variable appeared to be
removed completely. There was just a push operation (to push the
parameter on the stack) and an invokeInterface opcode, to call the
sumbit() method.
In C it used to be a compile time
operation, and does not add any runtime penalty.


Your understanding jibes with mine. However, it seems it's machine
dependent. Ol' C itself is pretty machine dependent. I remember I used
to cast integers to pointers like so:

#define SPORT_1 (*(void*)0x10001234)

And there would be no runtime penalty, because the Motorola 68000's
representation of ints and pointers was exactly the same. For other
architectures (Intel with their segmented pointers) I can see how there
might be some runtime overhead to split up the integer value.
 
A

Arne Vajhøj

Your understanding jibes with mine. However, it seems it's machine
dependent. Ol' C itself is pretty machine dependent. I remember I used
to cast integers to pointers like so:

#define SPORT_1 (*(void*)0x10001234)

And there would be no runtime penalty, because the Motorola 68000's
representation of ints and pointers was exactly the same. For other
architectures (Intel with their segmented pointers) I can see how there
might be some runtime overhead to split up the integer value.

Not that it is significant for your point, but I assume the first
asterisk should not be there.

Arne
 
M

Mike Schilling

Alessio said:
In Java a cast is a runtime operation because it implies a runtime
type check.

Surely

List list;
List<String> slist = (List<String>)list;

doesn't do a run-time type check. There's nothing checkable about it.
 
M

Mike Schilling

Thomas said:
The C standard allows pointers of distinct types to have distinct
in-memory representations. For instance, this is not valid C:

char *fake_cast_wrong(int *x)
{
char *y;

memcpy(&y, &x, sizeof x);
return y;
}

because this code tries to interpret the memory representation of 'x'
(a pointer to int) as the memory representation of a pointer to char,
without using a cast. For that matter, the memory representation of a
pointer to char may have a different length than the memory
representation of a pointer to int, so the code above could be a
devious example of a buffer overflow.

Such architectures are now quite rare(*).

Ah, the late and unlamented Data General Eclipse. (The computer from Tracy
Kidder's _The Soul of a New Machine_, which is a fine book, and even better
if you've never had to work on one of those pieces of crap.)
 
M

markspace

Arne said:
Not that it is significant for your point, but I assume the first
asterisk should not be there.


I think it should, although I could be wrong. The idea is to read and
write SPORT_1 as if it were a variable, without having to apply further
modifiers.

int value = SPORT_1;
value &= 0xF;
SPORT_1 = value;

Although I admit I may have messed up the syntax in my previous post.
 
L

Lew

Mike said:
Surely

List list;
List<String> slist = (List<String>)list;

doesn't do a run-time type check. There's nothing checkable about it.

It doesn't do a cast, either. Well, it does, but it's the equivalent of

List slist = (List) list;

Come to think of it, that cast might involve a runtime type check.
 
T

Tom Anderson

Ah, the late and unlamented Data General Eclipse. (The computer from
Tracy Kidder's _The Soul of a New Machine_, which is a fine book, and
even better if you've never had to work on one of those pieces of crap.)

I love that book.

tom
 
E

Eric Sosman

Arne said:
[...]

#define SPORT_1 (*(void*)0x10001234)
Not that it is significant for your point, but I assume the first
asterisk should not be there.


I think it should, although I could be wrong. The idea is to read and
write SPORT_1 as if it were a variable, without having to apply further
modifiers.

int value = SPORT_1;
value &= 0xF;
SPORT_1 = value;

Although I admit I may have messed up the syntax in my previous post.

<off-topic>

The syntax is fine; the error is in the semantics. A C
compiler must issue a diagnostic message for your sample code.

Follow-ups set to comp.lang.c; this isn't about Java.

</off-topic>
 
A

Arne Vajhøj

I think it should, although I could be wrong. The idea is to read and
write SPORT_1 as if it were a variable, without having to apply further
modifiers.

int value = SPORT_1;
value &= 0xF;
SPORT_1 = value;

Although I admit I may have messed up the syntax in my previous post.

Something was wrong, because (xxx*)someint gives a pointer to xxx but
*(xxx*)someint gives xxx - for xxx not being void, for xxx being void
you will get bunch of errors.

Arne
 
M

markspace

Arne said:
Something was wrong, because (xxx*)someint gives a pointer to xxx but
*(xxx*)someint gives xxx - for xxx not being void, for xxx being void
you will get bunch of errors.

I might be thinking of volatile -- *(volatile char*)0x10001234 -- but
it's also possible that it's just really old or idiosyncratic syntax.
This is from a system I programmed on around 1990 or so, practically the
stone age.
 
M

Martin Gregorie

This is from a system I programmed on around 1990 or so, practically the
stone age.
The computing stone age was prior to 1964, when IBM's System/360 and
ICL's 1900 ranges were rolled out.

These two mainframe series introduced the idea of a compatible range of
computers - before that programs only ran on a single CPU and about the
only scalability was to change the amount of memory or the number and
type of peripheral devices attached to it.

Integrated circuits, microprocessors and microcomputers appeared in the
mid 70s and the IBM PC in 1982 - very little thats radically new has
happened since then. Unix? 1970. Networks? SNA and X.25 were early 80s
tech. TCP/IP was mid 80s.
 

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

generics puzzle 57
Generics ? 14
Generics 12
Generics for a multiplevalue hashmap 8
can this be done with generics? 32
Problem with reflection in C# 4
Trouble with reflection 0
Cast, generics and clone problem 15

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top