13

Ada, Pascal and many other languages support ranges, a way to subtype integers. A range is a signed integer value which ranges from a value (first) to another (last). It's easy to implement a class that does the same in OOP but I think that supporting the feature natively could let the compiler to do additional static checks.

I know that it's impossible to verify statically that a variabile defined in a range is not going to "overflow" runtime, i.e. due to bad input, but I think that something could be done. I think about the Design by Contract approach (Eiffel) and the Spec# ( C# Contracts ), that give a more general solution.

Is there a simpler solution that checks, at least, static out-of-bound assignment at compile time in C++, C# and Java? Some kind of static-assert?

edit: I understand that "ranges" can be used for different purpose:

  1. iterators
  2. enumerators
  3. integer subtype

I would focus on the latter, because the formers are easily mappable on C* language . I think about a closed set of values, something like the music volume, i.e. a range that goes from 1 up to 100. I would like to increment or decrement it by a value. I would like to have a compile error in case of static overflow, something like:

volume=rangeInt(0,100);
volume=101;  // compile error!
volume=getIntFromInput(); // possible runtime exception

Thanks.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Zen
  • 917
  • 1
  • 7
  • 20

11 Answers11

4

Subrange types are not actually very useful in practice. We do not often allocate fixed length arrays, and there is also no reason for fixed sized integers. Usually where we do see fixed sized arrays they are acting as an enumeration, and we have a better (although "heavier") solution to that.

Subrange types also complicate the type system. It would be much more useful to bring in constraints between variables than to fixed constants.

(Obligatory mention that integers should be arbitrary size in any sensible language.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • I agree. I did a fair amount of Pascal programming and frankly, ranges were more of a pain than a benefit. – plinth Jan 29 '09 at 13:00
  • 2
    I actually disagree. Ranged numeric values can be extremely useful in certain applications, particularly in the embedded world and also allow for some static, compile-time checking as well. – Scott Dorman Jan 30 '09 at 20:39
  • 1
    perhaps you also found types in general a pain, why specify a short when you can just use longlong everywhere? We allocate fixed length arrays all the time - or do you not use strings? – gbjbaanb Jan 31 '09 at 00:17
  • *confused* No, I'm fine with (static) typing. Why bother distinguishing a short from a long long when neither have sensible semantics. By fixed length arrays, I mean arrays fixed at compile time. – Tom Hawtin - tackline Feb 02 '09 at 11:40
  • @Tom: Why do neither have sensible semantics? Computers do not have arbitrary sized integers. Acting like you're not running on real hardware isn't sensible either. – Billy ONeal Jul 26 '10 at 21:04
  • @Billy We have plenty of abstractions. This one is well overdue. We have fast computers, fast compilers and massive economies of scale (that is to say the number of people implementing language systems is much smaller than the number using them). – Tom Hawtin - tackline Jul 26 '10 at 22:25
  • @Tom: Perhaps. But some of us don't want machines that run at 20% of the speed they would otherwise as a result of constantly needing to use BigInt. Language designers aren't stupid -- and very few languages have arbitrary precision integers as a default setting. – Billy ONeal Jul 26 '10 at 22:29
  • @Billy I believe Smalltalk has arbitrary integers but is typically implemented such that normal-sized integers do not require allocated memory. This stuff is decades old. Claims of such a slow down are utter nonsense. – Tom Hawtin - tackline Jul 26 '10 at 23:49
  • @Tom: Yes. Because Smalltalk is a language that produces *fast* programs. Oh, wait. – Billy ONeal Jul 27 '10 at 00:04
  • @Tom: To be clear: I'm not disagreeing with you that large integers should be available. They should not, however, be the *default*. – Billy ONeal Jul 27 '10 at 00:05
  • The core use of ranges in Wirthian languages is to confine ordinal types to a range and enforce that using runtime checking. The "use as index of array" is only some minor syntactic sugar. Consider it asserts you get for free. – Marco van de Voort Dec 19 '11 at 21:30
  • Very late to the party but I also disagree. I found them very useful when I wrote Pascal and miss them since in C, C++, Java. Using them (e.g. DayOfMonth) in a method signature would allow a compiler (and decent IDE's) to reject more incorrect code; e.g. the caller needs to safely convert a vanilla Int to a DayOfMonth before calling some function. This removes need for defensive programming. This, to me, is like languages (e.g. Kotlin, Rust) rejecting "null" and the improvements are well worthwhile. Anything to improve correctness without needing reams of unit tests and human comprehension. – David Kerr Jan 10 '23 at 13:05
4

Ranges are most useful when you can do something over that range, concisely. That means closures. For Java and C++ at least, a range type would be annoying compared to an iterator because you'd need to define an inner class to define what you're going to do over that range.

Craig P. Motlin
  • 26,452
  • 17
  • 99
  • 126
3

Java has had an assert keyword since version 1.4. If you're doing programming by contract, you're free to use those to check proper assignment. And any mutable attribute inside an object that should fall within a certain range should be checked prior to being set. You can also throw an IllegalArgumentException.

Why no range type? My guess is that the original designers didn't see one in C++ and didn't consider it as important as the other features they were trying to get right.

duffymo
  • 305,152
  • 44
  • 369
  • 561
3

For C++, a lib for constrained values variables is currently being implemented and will be proposed in the boost libraries : http://student.agh.edu.pl/~kawulak/constrained_value/index.html

Klaim
  • 67,274
  • 36
  • 133
  • 188
2

This is an old question, but just wanted to update it. Java doesn't have ranges per-se, but if you really want the function you can use Commons Lang which has a number of range classes including IntRange:

IntRange ir = new IntRange(1, 10);

Bizarrely, this doesn't exist in Commons Math. I kind of agree with the accepted answer in part, but I don't believe ranges are useless, particularly in test cases.

Jonathan Holloway
  • 62,090
  • 32
  • 125
  • 150
2

Pascal (and also Delphi) uses a subrange type but it is limited to ordinal types (integer, char and even boolean).

It is primarilly an integer with extra type checking. You can fake that in an other language using a class. This gives the advantage that you can apply more complex ranges.

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
2

I would add to Tom Hawtin response (to which I agree) that, for C++, the existence of ranges would not imply they would be checked - if you want to be consistent to the general language behavior - as array accesses, for instance, are also not range-checked anyway. For C# and Java, I believe the decision was based on performance - to check ranges would impose a burden and complicate the compiler.

Notice that ranges are mainly useful during the debugging phase - a range violation should never occur in production code (theoretically). So range checks are better to be implemented not inside the language itself, but in pre- and post- conditions, which can (should) be stripped out when producing the release build.

Fabio Ceconello
  • 15,819
  • 5
  • 38
  • 51
1

C++ allows you to implement such types through templates, and I think there are a few libraries available doing this already. However, I think in most cases, the benefit is too small to justify the added complexity and compilation speed penalty.

As for static assert, it already exists. Boost has a BOOST_STATIC_ASSERT, and on Windows, I think Microsoft's ATL library defines a similar one.

boost::type_traits and boost::mpl are probably your best friends in implementing something like this.

jalf
  • 243,077
  • 51
  • 345
  • 550
1

The flexibility to roll your own is better than having it built into the language. What if you want saturating arithmetic for example, instead of throwing an exception for out of range values? I.e.

MyRange<0,100> volume = 99;
volume += 10; // results in volume==100
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Unfortunately Java can't do that, as it supports generics only, which is quite different from general templates. They solve a similar problem, but in a much, much restricted way. – Joachim Sauer Jan 30 '09 at 21:32
  • 1
    As far as I can see it's a flexibility that you can experience only at runtime. Why can't you have a compile error in the example you showed? – Zen Jan 30 '09 at 23:52
  • for the same reason that "byte x = 250; x += 10;" doesn't error at compile time. – gbjbaanb Jan 31 '09 at 00:18
0

In C# you can do this:

foreach(int i in System.Linq.Enumerable.Range(0, 10))
{
    // Do something
}
Svish
  • 152,914
  • 173
  • 462
  • 620
0

JSR-305 provides some support for ranges but I don't know when if ever this will be part of Java.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130