methods with "short"-typed arguments.

  • Thread starter Andreas Leitgeb
  • Start date
A

Andreas Leitgeb

Given a method:
void foo (int x, short y) { ... }

How would I call it with an immediate value for the second argument?

foo ( 42, (short)43);

Or did I miss some postfix-char for short literals (like "L" for long)?
(according to http://mindprod.com/jgloss/jcheat.html there isn't one)

Why is this cast necessary at all?
Why doesn't the /$(%$&/ compiler notice, that 43 is just fine and
provably without any loss of real information castable to a short?

Instead it tells me:
Test1.java:29: foo(int,short) in Test1 cannot be applied to (int,int)
foo( someIntVar, 43 );


PS: Yes, yes, changing foo to (int,int) would solve the problem, too,
but that's a different story.

PPS: don't take my swear-chars used with "compiler" too literally.
Surely, the compiler is "/$(%$&/" only because some /$(%$&/ speci-
fication demanded it to be so.
 
A

Andreas Leitgeb

Lew said:
Which entry, incidentally, includes an answer to the OP's question.

Indeed. The jls is the one to attribute the swear-chars to. (see
original post of this thread)
 
J

Joshua Cranmer

Andreas said:
Given a method:
void foo (int x, short y) { ... }

How would I call it with an immediate value for the second argument?

foo ( 42, (short)43);

Why is this cast necessary at all?

While you said you didn't want to be told based on the JLS, it is
actually informative as to why it's done this way:

«Method invocation conversions specifically do not include the implicit
narrowing of integer constants which is part of assignment conversion.
The designers of the Java programming language felt that including these
implicit narrowing conversions would *add additional complexity* to the
overloaded method matching resolution process.

Thus, the example:

class Test {
static int m(byte a, int b) { return a+b; }
static int m(short a, short b) { return a-b; }
public static void main(String[] args) {
System.out.println(m(12, 2));
}
}

[ ... ] A language that included implicit narrowing of integer constants
would *need additional rules to resolve cases* like this example.»

(emphasis added, removed references and non-pertinent material)

In short, it's an idea that seems easy to put into practice but quickly
runs into pitfalls when you get to the corner cases that compilers have
to warn about.

To paraphrase what somebody once said about the design of CSS, designing
a programming language specification requires you to specify what
happens in the edgiest edge cases. You might not write code that has a
method name overloaded to have every possible pair of primitive types,
but the compiler still has to worry about that case.
 
A

Andreas Leitgeb

Joshua Cranmer said:
To paraphrase what somebody once said about the design of CSS, designing
a programming language specification requires you to specify what
happens in the edgiest edge cases. You might not write code that has a
method name overloaded to have every possible pair of primitive types,
but the compiler still has to worry about that case.

First of all, I thank for the reference to the original reasoning
behind that behaviour.

I'd find it ok for the compiler to be fussy in light of two
or more overload-candidates, but less so in light of only
one candidate.

Also, I don't see the principial difference between widening
a small integral primitive type (if taken as byte, and upcasted/
widened to short or int as opportune) and up-casting in a class
tree.

It is no problem for the compiler to deal with
... methodA(Object o, Integer i) ...
... methodA(Number n1,Number n2) ...
methodA ( new Integer(42), new Integer(43) );
and correctly recognize this particular situation as ambiguous,
but successfully call the remaining method, once I remove one of
the candidates.

If the compiler (in accordance with a virtual "corrected jls")
treated byte-short-integer like Integer-Number-Object, with
small numeric literal considered to be byte/short literals and
implicitly "upcasted" to int as needed, and if it treated resulting
possible ambiguities of called methods the same way as with Classes,
then I'd be a lot more happy. (now isn't that a worthy goal?? :)

I know it isn't so, but it would be just as reasonable, even less
complex, and be just so much better :)
 
O

ojacobson


That all literals are of int type is a misfeature, IMO - the literal 1
should be of type byte, which can be wideningly-converted to any of
short, int, long, float, or double quite safely. Similarly, 128
should be of type short, and 32768 of type int. This'd probably
eliminate the need for an explicit 'L' qualifier: all literals greater
than 2,147,483,647 or less than -2,147,483,648 would logically be of
type 'long' without further effort.

We'd still need F for floats, though.

Alternately, the type suffixes for literals should be more thorough:
suffixes for literals of all numeric primitive types, including char.
The "implicit narrowing for assignment only" special case is confusing
and unnecessary.

-o
 
A

Andreas Leitgeb

That all literals are of int type is a misfeature,
numeric literals, of course. There are also String-literals, ...
IMO - the literal 1
should be of type byte, which can be wideningly-converted to any of
short, int, long, float, or double quite safely. Similarly, 128
should be of type short, and 32768 of type int. This'd probably
eliminate the need for an explicit 'L' qualifier:

Mostly, but not entirely!
1024 * 1024 * 1024 * 4 == 0
1024 * 1024 * 1024 * 4L == 4294967296L
Sometimes you need to specify a small literal as being
of some wider type, to ensure the math is done the right
way. That's ok.
all literals greater
than 2,147,483,647 or less than -2,147,483,648 would logically be of
type 'long' without further effort.
We'd still need F for floats, though.
float and double are different beasts :)
Alternately, the type suffixes for literals should be more thorough:
suffixes for literals of all numeric primitive types, including char.

At least better than the status quo.
The "implicit narrowing for assignment only" special case is confusing
and unnecessary.

yep, 100% agree.
 
T

Tom Anderson

That all literals are of int type is a misfeature, IMO - the literal 1
should be of type byte, which can be wideningly-converted to any of
short, int, long, float, or double quite safely. Similarly, 128 should
be of type short, and 32768 of type int. This'd probably eliminate the
need for an explicit 'L' qualifier: all literals greater than
2,147,483,647 or less than -2,147,483,648 would logically be of type
'long' without further effort.

Hmm. This doesn't feel like a good idea to me.
We'd still need F for floats, though.

Alternately, the type suffixes for literals should be more thorough:
suffixes for literals of all numeric primitive types, including char.
The "implicit narrowing for assignment only" special case is confusing
and unnecessary.

I like this suggestion best. As Tim Peters says, "explicit is better than
implicit".

tom

--
Wikipedia topics: lists of trains, Mortal Kombat characters, one-time
villains from Mario games, road intersections, boring suburban schools,
garage bands, cats, webcomics, Digimon, Bionicle characters, webforums,
characters from English soap operas, and Mortal Kombat characters that
don't exist -- Uncyclopedia
 
P

Patricia Shanahan

Tom said:
I like this suggestion best. As Tim Peters says, "explicit is better
than implicit".

I don't see why, except for the long and float cases, suffixes are
better than casts.

A suffix is needed for long because the default integer type is
narrower. A suffix is needed for float to avoid doing two rounding steps.

Neither issue applies to (short)42.

Patricia
 
L

Lew

Andreas said:
First of all, I thank for the reference to the original reasoning
behind that behaviour.

The JLS is often, but not always, the place to find the reasoning for
Java restrictions.
Also, I don't see the principial difference between widening
a small integral primitive type (if taken as byte, and upcasted/
widened to short or int as opportune) and up-casting in a class
tree.
...
If the compiler (in accordance with a virtual "corrected jls")
treated  byte-short-integer  like  Integer-Number-Object, with
small numeric literal considered to be byte/short literals and
implicitly "upcasted" to int as needed, and if it treated resulting
possible ambiguities of called methods the same way as with Classes,
then I'd be a lot more happy.  (now  isn't that a worthy goal?? :)

I know it isn't so, but it would be just as reasonable, even less
complex, and be just so much better :)

JLS 5.3 indicates that implicit widening conversions are permitted in
a method invocation.
Method invocation conversion is applied to each argument value in a method or constructor
invocation (§8.8.7.1, §15.9, §15.12): the type of the argument expression must be converted
to the type of the corresponding parameter. Method invocation contexts allow the use of one
of the following:
...
* a widening primitive conversion

Happy?
 
O

Owen Jacobson

numeric literals, of course.  There are also String-literals, ...


Mostly, but not entirely!
   1024 * 1024 * 1024 * 4  == 0
   1024 * 1024 * 1024 * 4L  == 4294967296L
Sometimes you need to specify a small literal as being
of some wider type, to ensure the math is done the right
way.  That's ok.

That's an ugly edge case, for sure. The approach a lot of languages
have taken (going back at least to Lisp, and viable for imperative
languages since at least Smalltalk) is that numbers are instances of
an Integer or Number class, and operations return new instances; under
the hood, small numbers are represented using hardware ints and large
numbers using a bignum class, but all operations are in terms of
Number, not of hardware-int-Number or bignum-Number.

As far as I understand it, Java acquired primitives as a sop for
people coming to the language from C++; since that's no longer a major
concern, and since techniques for making object-like hardware ints
fast are fairly well known, I don't see a lot of value in keeping
primitives any more. Several newer JVM languages seem to agree; both
Scala and Groovy use a number class for everything, even given the
existing performance levels.

-o
 
O

Owen Jacobson

I don't see why, except for the long and float cases, suffixes are
better than casts.

There's a psychological reason (cases where casts are necessary
encourages people to use casts in other places) and a practical one (a
suffix character is shorter and potentially clearer). I don't like
suffixes at all; an ideal situation wouldn't require qualifying to the
compiler that, for example, literal 400 is assignable to short -- it
can work that out just fine for itself since all numeric types have
well-defined ranges -- but the JLS forbids it from doing so.
A suffix is needed for long because the default integer type is
narrower. A suffix is needed for float to avoid doing two rounding steps.

Floating-point initialization is a weird beast; the literal in the
code actually identifies "the closest representable value in FP system
X", where X is either float or double, and the density of possible
values at any given point is different for both types. I'd prefer to
eliminate the float type entirely (leaving 'double'; it might be worth
renaming double) in some hypothetical version of Java, since it's
rarely faster any more and always gives worse precision, but making
the compiler aware of which type the literal 1.2 is being assigned to
would be an acceptable solution, in line with making integer literals
of the narrowest applicable type.
 
O

Owen Jacobson

JLS 5.3 indicates that implicit widening conversions are permitted in
a method invocation.

I can think of no places where the JLS forbids an implicit widening
conversion, come to think of it; if there are any, there probably
shouldn't be.

-o
 
A

Arne Vajhøj

Owen said:
That's an ugly edge case, for sure. The approach a lot of languages
have taken (going back at least to Lisp, and viable for imperative
languages since at least Smalltalk) is that numbers are instances of
an Integer or Number class, and operations return new instances; under
the hood, small numbers are represented using hardware ints and large
numbers using a bignum class, but all operations are in terms of
Number, not of hardware-int-Number or bignum-Number.

As far as I understand it, Java acquired primitives as a sop for
people coming to the language from C++; since that's no longer a major
concern, and since techniques for making object-like hardware ints
fast are fairly well known, I don't see a lot of value in keeping
primitives any more. Several newer JVM languages seem to agree; both
Scala and Groovy use a number class for everything, even given the
existing performance levels.

I find it likely that the next big language will have such
a feature.

Type precision could become a thing of the past like
deallocation of memory.

But today we have Java and I don't think it is possible
to make this kind of changes without breaking existing
code, so we have what we have in Java and will have it for
the 1-3 decades that Java will last.

Arne
 
A

Arne Vajhøj

That all literals are of int type is a misfeature, IMO - the literal 1
should be of type byte, which can be wideningly-converted to any of
short, int, long, float, or double quite safely. Similarly, 128
should be of type short, and 32768 of type int. This'd probably
eliminate the need for an explicit 'L' qualifier: all literals greater
than 2,147,483,647 or less than -2,147,483,648 would logically be of
type 'long' without further effort.

It is possible.

But I really don't like the concept of the type depending
on the value.

Worst case would be a constant (static final) that is changed
and then causes a call to use another method due to different
overloaded arguments.
Alternately, the type suffixes for literals should be more thorough:
suffixes for literals of all numeric primitive types, including char.

That on the other hand would be nice !

Arne
 
A

Andreas Leitgeb

Lew said:
JLS 5.3 indicates that implicit widening conversions are permitted in
a method invocation.


Happy?

Halfly. So the widening is already in place, so the only part yet
missing is starting small numeric literals as the narrowest feasible
primitive type, so that widening actually has a chance of occurring
in more situations than just int->long.
As an extra bonus, no special rules for assignment would then be
necessary anymore.

Then me happy.
 
A

Andreas Leitgeb

Arne Vajhøj said:
Worst case would be a constant (static final) that is changed
and then causes a call to use another method due to different
overloaded arguments.

probably a bad example, because if you stored a literal in a
static final then it does have some very explicit type.
static final short ANSWER = 42;

while 42 should be treated as a byte, ANSWER is definitely
a short, despite it's value being inlined by the compiler.

If I had static final byte FOO = 1; I could use FOO for
calling a method taking a byte or a short even now.

If we're leaving static finals aside now, and use literals, then
it would be possible, that where previously the "int"-variant of
a method was called, that then a "byte"-variant could be called,
or in some multi-arguments cases the compiler could then error out
complaining about ambiguity, as it already does in some class-
hierarchy-related situations.

Having explicit byte- and short- literal postfixes would indeed
prevent a change in behaviour of old code. I think I start to like
that idea, as it's the least even possibly painful thing.

PS: to be honest, a postfix for byte/short literals would be mostly
syntactic sugar for the cast. I think it's good sugar, others may
disagree.
 
A

Andreas Leitgeb

Lew said:
You're not supposed to put magic numbers in code anyway. Declare static final
variables to hold your constants, then you get the rest of your wish.

Not all numbers are magic ;-)
static final byte MAGIC_NUMBER = 23;
invoke( MAGIC_NUMBER );

Good(tm) idea: I create Literals.java with roughly these contents:
class Literals {
public static final byte bm128=-128,bm127=-127,...,bm1=-1,
b0=0,b1=1,b2=2,...,b127=127;
public static final short sm32768=-32768,...,sm129=-129,...,sm1=-1,
s0=0,s1=1,...,s128=128,...,s32767=32767;
}
(probably I'm gonna need to split it into two
classes, one for >=0 and one for <0 "literals"
to avoid exceeding max# of fields per class)

Then use:
static import path.to.Literals.*;
... foo(s4200, bm42); // foo(short,byte)

and finally end up with a case-sensitive "prefix" instead of a
case-insensitive postfix notation.

PS: yeuch, but it would work.
 
L

Lew

Andreas said:
Good(tm) idea: I create Literals.java  with roughly these contents:
  class Literals {
    public static final byte bm128=-128,bm127=-127,...,bm1=-1,
                             b0=0,b1=1,b2=2,...,b127=127;
    public static final short sm32768=-32768,...,sm129=-129,...,sm1=-1,
                             s0=0,s1=1,....,s128=128,...,s32767=32767;

Seriously? You explicitly list 65,536 literal short values? You've
actually done this?
  }
(probably I'm gonna need to split it into two
classes, one for >=0 and one for <0 "literals"
to avoid exceeding max# of fields per class)

I am just shaking my head in incredulity.
Then use:
  static import path.to.Literals.*;
  ...  foo(s4200, bm42);   // foo(short,byte)

and finally end up with a case-sensitive "prefix" instead of a
case-insensitive postfix notation.

Here's a case-sensitive prefix that puts less strain on the constant
pool and the number of allowable fields per class. Let's say you have
a method that takes a 'short' argument:

public void foo( short val );

The case-sensitive prefix would look like this:

holder.foo( (short) 8191 );
 

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,051
Latest member
CarleyMcCr

Latest Threads

Top