I wanted to make a JavaLanguage Replacement for AdaLanguage's type length is range 0 .. 31 ; Here it is.
An AbstractClass:
/** * BaseClass for a range checked int value */ public abstract class RangedInt { private int value; public abstract int getMaxValue(); public abstract int getMinValue(); public int getValue() { return value; } public void setValue(int value) throws IllegalArgumentException { if (value > getMaxValue()) { throw new IllegalArgumentException( "Value=" + value + " is geater than maxValue=" + getMaxValue()); } if (value < getMinValue()) { throw new IllegalArgumentException( "Value=" + value + " is smaller than minValue" + getMinValue()); } this.value = value; } }A sample concrete Class:
public class Length extends RangedInt { public final int getMaxValue() { return 32; } public final int getMinValue() { return 1; } }FranzHöpfinger 18.12.02
Refactoring Notes:
I've removed the comments, they had no value. Especially JavaDoc tags @returns int is funny, since it says literally nothing. Also I've renamed the methods getMINVALUE to getMinValue to make it more Sun-like. Also note that the instances of the class Length will be constructed in an inconsistent state, since the value is not initialized in the constructor.
Here after some more refactoring:
// No longer an AbstractClass. // Exception type changed to be more // evocative than IllegalArgumentException. -- EricJablow // But that's wrong -- there's no reason to suspect this integer is an -index- into anything... -- DavisHerring? public class RangedInt { public RangedInt(int minValue, int maxValue, int value) { this.minValue = minValue; this.maxValue = maxValue; // Unnecessary, as setValue(value) will throw. // But, gives a better error message. if (minValue > maxValue) throw new IllegalArgumentException("Min value greater than Max value"); setValue(value); } public final int getMaxValue() { return maxValue; } public final int getMinValue() { return minValue; } public final int getValue() { return value; } public final void setValue(int value) throws IndexOutOfBoundsException { if (value > getMaxValue()) { throw new IndexOutOfBoundsException( "Value=" + value + " is geater than maxValue=" + getMaxValue()); } if (value < getMinValue()) { throw new IndexOutOfBoundsException( "Value=" + value + " is smaller than minValue" + getMinValue()); } this.value = value; } private int value; private final int minValue; private final int maxValue; }
There is a big design difference between the former and the latter blocks of code; the former establishes a framework for defining new types (which is similar to what the AdaLanguage does), but the latter is basically just a holder for values (it has no static force). For example, if I write a method which needs a value in the range 0..32 and I take the second kind of RangedInt (call it 'ri'), I still have to test ((ri.getMinValue() >= 0) && (ri.getMaxValue() <= 32)), whereas with the former, I take a Length (which should really be called something more illuminating), and I know for sure that it's in the right range. Also, the latter carries two ints around with it that it really shouldn't need to.
The problem about initialisation to invalid states is easily solved; the AbstractBaseClass RangedInt must define these two constructors:
protected RangedInt( int value ) { setValue( value ) ; } protected RangedInt() { this( getMinValue() ) ; }Also, RangedInt should be immutable, like a String, but that's just a PersonalChoiceElevatedToMoralImperative.
To properly act as a new type, wouldn't you need math operations on this class as well? Methods like Multiply() and Divide() and even Add() and Subtract()? What is the behavior when you multiply two RangedInts and get a value higher than the maximum allowed? Does this act like a Ring?
No, it does not. And in the example above it should not, since length * length is not length but area. :-)
This does not look too promising, as ranged types are difficult to add retroactively in a language like Java with it's primitive types not being "at range" for extensions and the Object - counterparts being declared final.
The approaches above pretend to be a RangedInt but do not even extend Number and do not provide support for being Comparable.
To me it seems what they provide can be easier implemented as an IntegerRange providing an isInRange(int)-method.
Alternative approach: extend BigInteger. This would also inherit the requested math methods (which have to be implemented by calling super() and checking the result).
HorstMakitta?