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.
Your 'task' variable is declared without <T> (or <?>?). Does that make
a difference?
SortTask<T> task = ...
Looks like the compiler doesn't recognise that SortTask implements
Callable<Void>, i.e. all generics have been stripped off by lack of <>,
including inherited details, even though the generic parameter doesn't
affect those.
--
ss at comp dot lancs dot ac dot uk
> SortTask task = new SortTask<T>( a, l, i - 1, counter );
What happens with:
SortTask<T> = new SortTask<T>( a, l, i - 1, counter );
--
Roedy Green Canadian Mind Products
http://mindprod.com
The future has already happened, it just isn�t evenly distributed.
~ William Gibson (born: 1948-03-17 age: 61)
> On 15/12/09 17:55, markspace wrote:
>> SortTask task = new SortTask<T>( a, l, i - 1, counter );
>> executor.submit( task ); // Unchecked
>
> 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.
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.
--
Your supervisor is thinking about you.
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
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).
--
Eric Sosman
eso...@ieee-dot-org.invalid
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
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(*). In most current systems which
support C compilation, all pointers have the same uniform in-memory
representation, and casts between pointer types occur no runtime cost:
the C compiler does not have to generate any conversion code since the
conversion turns out to be a no-operation.
In Java you do not have access to the in-memory representation; whether
some kind of references have a distinct representation is private
business to the JVM. Most JVM prefer a uniform in-memory representation
because it is easier and faster. However, a cast in Java usually implies
a runtime type check, which the C standard does not mandate (the C
standard does not _forbid_ runtime type checks, it even allows the
program to loudly complain in case of a "wrong cast", but it does not
mandates anything and most C compilers perform no runtime check). In
Java, if the cast leads to an incompatible type, then the JVM _must_
issue a ClassCastException. Therefore, casts in Java tend to be somewhat
more expensive than casts in C. On the other hand, casts between
reference types should be rare in a properly structured OO code.
--Thomas Pornin
(*) Old architectures never die, they just become cheaper, and therefore
more common. However, it is probable that the DSP which have
legal-but-weird constraints on C code are rarely programmed in C.
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-
>> someField, it should dereference castPtr + an offset of, say, 42 to
> 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.
--
Eric Sosman
eso...@ieee-dot-org.invalid
>
> 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.
Not that it is significant for your point, but I assume the first
asterisk should not be there.
Arne
> 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.
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 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.
Mike Schilling wrote:
> 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.
--
Lew
I love that book.
tom
--
see im down wid yo sci fi crew
<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>
--
Eric Sosman
eso...@ieee-dot-org.invalid
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
> 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.
> 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.
--
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |