Java generics (I think) question

snotnose

Ars Tribunus Militum
2,747
Subscriptor
I have a method that does the same thing to multiple data types. Think:
Code:
float update(float value, float minimum, float maximum) {
    if(value < minimum)
        value = minimum;
    else if(value > maximum)
        value = maximum;

    return value;
}
How can I modify that so it will take and return int, float, or double, depending on what it's passed? There's no type mixing, if 1 value is a float they're all floats.

Been farting with Generics and Integer, Float, and Double with no joy.

My code's a bit more involved, I've been using the bit above to try and get something to compile.
 
Last edited:

kosh_tosh

Seniorius Lurkius
10
Subscriptor
Integer, Float, and Double wrapper classes all extend Number and implement the Comparable interface

Hopefully this will meet your needs:
Java:
<T extends Number & Comparable<T>> T update(T value, T minimum, T maximum) {
       
        if (value.compareTo(minimum) < 0) {
            value = minimum;
        } else if (value.compareTo(maximum) > 0) {
            value = maximum;
        }
       
        return value;
    }

edit:
You should be able to pass in primitive numeric values as method parameters. They will autobox to wrapper types.
 

snotnose

Ars Tribunus Militum
2,747
Subscriptor
It occurs to me this is why learning programming via google is A Bad Idea. I spent a couple hours yesterday trying to make my routine work with no joy. The provided code above didn't work out of the box, I got weird compiler errors I didn't understand.

This morning I spent 30 minutes with an old Java book (now includes Java 5!) and learned more than I did with all my googling yesterday. The very first example had compareTo, which I never ran across yesterday.

It's like stack overflow. Google something, get a SO answer that almost works. I suspect most beginning programmers hack around a bit until it compiles and (usually) works; and stop there. I've been at this a while and want to understand how it works, so my 5 minute google often leads to a few hours of "goddamit, now what's the problem?".

The problem is google et all only give a little snippet of information, usually without supporting theory. Without that supporting theory you have no clue what to do when things go wrong.

Oh, the mysterious error I was getting? The compiler was interpreting a 0 as an integer, solved via 0F. The code above is fine, the error was in how I called it. I doubt I'd have ever figured that out without my Head First Java book.
 
Last edited:

koala

Ars Tribunus Angusticlavius
7,579
Everything has its place. Googling is sometimes useful- but normally, Googling is more useful as you know more.

The fastest way to learn how to do X is to do X with someone by your side that knows more than you.

With a book, someone that knows more than you is still giving you "structure" (the structure of the book). With Googling, there is no structure.

...

Also, in your code above, I'd avoid modifying value. Modifying passed-in arguments is a bit counterintuitive.

BTW, this function you are implementing is commonly called "clamp". And apparently, from a quick Google search, it was added in Java 21?

(edit: I love Hoogle. OK, it's just the fourth result, but I love it.)
 

Tristram

Ars Scholae Palatinae
1,428
Subscriptor
Integer, Float, and Double wrapper classes all extend Number and implement the Comparable interface

Hopefully this will meet your needs:
Java:
<T extends Number & Comparable<T>> T update(T value, T minimum, T maximum) {
      
        if (value.compareTo(minimum) < 0) {
            value = minimum;
        } else if (value.compareTo(maximum) > 0) {
            value = maximum;
        }
      
        return value;
    }

edit:
You should be able to pass in primitive numeric values as method parameters. They will autobox to wrapper types.
Possible bug: there is no check to make sure minimum < maximum. So update(x, 100, 1) would likely give different values than update(x, 1, 100), depending on x (i.e. x between 1 and 100)
 

ShuggyCoUk

Ars Tribunus Angusticlavius
9,975
Subscriptor++
As an aside in java (unless something has got waaaaay better with the JIT/compiler) the resulting code you have will be horribly slow because it will box and allocate all over the place. Benchmark etc. and check.

"generics over numerical types with efficient maths" is one of the real hard problems with the generics systems in many popular languages (c#/dotnet and java included, though java's type erasure makes it so much worse)

c#/dotnet fixed this somewhat in c# 7 (reading that can explain somewhat why it's complicated).
f# always had an alternate which was inline, effectively doing meta programming more like a blend of dotnet generics and C++ style where the compiler wrote a different function for each type involved at compile time (so not usable by conventional reflection) rather than at runtime like conventional dotnet generics.

I can't find even an attempt at a JSR for java for this
 

koala

Ars Tribunus Angusticlavius
7,579
As an aside in java (unless something has got waaaaay better with the JIT/compiler) the resulting code you have will be horribly slow because it will box and allocate all over the place. Benchmark etc. and check.
This is why I checked if clamp was in the stdlib, and pointed to the implementation. They have one method for each numeric type. As long as you don't have to do that yourself... I'm fine with the Oracle devs doing those for me :)
 

Tristram

Ars Scholae Palatinae
1,428
Subscriptor
So waddaya do about it? Assume it's a developer bug and throw an exception? Assume it's user error and try to deal with it?

Not being a smartass, curious what y'all would do. Me? I'd throw the exception.
Id prefer to redefine the semantics of the call. Instead of maximum and mininim (implied ordering), I rename them boundary 1 and boundry 2, and document the behavior to be X is gauranteed to be in the closed interval [min(boundry1, boundry2), max(boundry1, boundry2)], which also takes care of the case where the bounds are equal.
 

Lt_Storm

Ars Praefectus
16,294
Subscriptor++
Integer, Float, and Double wrapper classes all extend Number and implement the Comparable interface

Hopefully this will meet your needs:
Java:
<T extends Number & Comparable<T>> T update(T value, T minimum, T maximum) {
     
        if (value.compareTo(minimum) < 0) {
            value = minimum;
        } else if (value.compareTo(maximum) > 0) {
            value = maximum;
        }
     
        return value;
    }
My one thought about this code is that the type is overspecified. There is no reason to demand T be a Number.

Edit: oh and just using the library function is really the right answer.