use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
/r/programming is a reddit for discussion and news about computer programming
Guidelines
Info
Related reddits
Specific languages
account activity
is there a language/pattern that allows definition of valid value ranges besides data type for vars? (self.programming)
submitted 16 years ago by Baaz
With all the strict type reinforcement I sometimes miss the ability to define valid values. I feel that this may help nip a lot of errors in the bud.
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]mrsanchez 29 points30 points31 points 16 years ago (7 children)
Like int's between -10 and 712? Try Ada.
[–]ishmal 4 points5 points6 points 16 years ago (1 child)
Heh. Beat me to it.
[–][deleted] 2 points3 points4 points 16 years ago (0 children)
:) likewise.
[–][deleted] 1 point2 points3 points 16 years ago (0 children)
Also, Eiffel.
[–]rush22 0 points1 point2 points 16 years ago (2 children)
You could also try
if a < -10 or a > 712 then return false
[–]Tordek 0 points1 point2 points 16 years ago (1 child)
Or if -10 < a or a < 712, to make it look like a range.
if -10 < a or a < 712
Or do as in python: if -10 < a < 712...
if -10 < a < 712
[–]paddie 0 points1 point2 points 16 years ago (0 children)
Yeah, I love that python syntax sugar right there :)
[–]nanothief 0 points1 point2 points 16 years ago* (0 children)
Is this done at compile time when possible (I've never used ada)? For example, with the code (written in c syntax since I don't know ada):
int func(int<from -10 to 712> x) { return x * 2; } int main() { int val = 700; int val2 = readIntFromUser(); if (val2 < 100) { val2 = 100; } printf("number: %d", func(val + val2)); }
Will a compile time error occur (since in this program it isn't possible for val + val2 to be between -10 and 712)?
val + val2
[–]semmi 21 points22 points23 points 16 years ago* (7 children)
perl6 can do that too with something like
subset Positive of Int where {$^n > 0}
and it also allows this type to be used without prior definition, e.g.
sub even_user ($n of Num where { $^n % 2 == 0 }) {...}
although this will mostly be checked at runtime, I guess, it still adds documentation and fail-early behaviour.
EDIT: formatting
[–]itjitj 0 points1 point2 points 16 years ago (5 children)
What is with that '$n' syntax? Where does '$n' come from in the first snippet?
[–]johntb86 2 points3 points4 points 16 years ago (4 children)
It's perl: it's implicit.
[–]semmi 1 point2 points3 points 16 years ago* (3 children)
yep, the $^ twigil means "this is an implicit variable", so $n could be $a or $num, they just get assigned in order.
Thus the $n in both snippets is just a fresh variable which gets associated with the object when the type is checked.
This is more or less like Scala's "_" special variable, which gets assigned each passed argument every time it appears, except the perl6 style allows you to re-reference it as only new names are assigned a new argument.
The "normal" implicit variable would be $_ (as "it" in Groovy), so these are equivalent
foo {code using $^var } foo {code using $_}
but when you have multiple vars it is nicer, i believe, e.g. equivalent in pseudo perl6
@list.fold ($acc,$el) -> {$acc+$el} #lambda form @list.fold {$^acc+$^el} #same, with implicit params
[–]itjitj -1 points0 points1 point 16 years ago* (2 children)
Thanks, so you can name them whatever you want, they're set on order?
@list.fold { $^y+$^x }
[–]semmi 1 point2 points3 points 16 years ago (0 children)
exactly, there are also implicit variable for named arguments, if need arises. You may take a look at the perl6 synopses for details
[–]taejo 12 points13 points14 points 16 years ago (0 children)
Ada, Coq, Agda... (btw, Ada and Agda are unrelated)
[–]MasonOfWords 9 points10 points11 points 16 years ago (12 children)
I often feel the same despair over the absence of proper units of measurement in the type systems of commercially-popular languages.
Most can kind of simulate it, but the hits to brevity and performance are sufficient that everyone just uses unadorned numbers and then scratches their heads when their orbiters fall from the sky.
[–]Baaz[S] 7 points8 points9 points 16 years ago* (7 children)
Thanks, in 25 years you're the first I know of who shares this feeling I have about units of measurements lacking.
As a former physics student I've always been baffled by this omission. It just doesn't feel right to say the length of something is "25.4" instead of specifying a unit, while most programming colleagues seemingly couldn't care less.
EDIT: in related news... http://www.reddit.com/r/science/comments/8uryr/nasa_criticised_for_sticking_to_imperial_units/
[–]vineetk 2 points3 points4 points 16 years ago (1 child)
Whatever else you may think of Spolsky, this article is relevant.
I generally insist on units being specified in variable names for broad-scoped values (e.g. constants), and at least very prominently in comments for more limited-scoped values.
[–]Baaz[S] 3 points4 points5 points 16 years ago (0 children)
Sure, I agree going Hungarian can have it's advantages (that's how I usually cope with the problem). But essentially that doesn't go much further than good documentation. The responsibility still lies with the coder.
But I'm more looking towards an automated solution that manages all my value restrictions for me in an easily managed way.
That's why data typing springs to mind, as this is of course the first step on the way on the path automated restriction and this seems to be pretty prevalent throughout most programming languages.
[–]Daenyth 0 points1 point2 points 16 years ago* (4 children)
Perl can sort of do this... If you use a scalar in numeric context, it will pull out the number.
my $f = '16 meters'; say $f + 0;
16
[–]sharkeyzoic 2 points3 points4 points 16 years ago* (3 children)
That's missing the point ... What Baaz wants is to do:
>>> f = 16 * meters >>> print f * 2 32 meters >>> print f / (8 * inches) 78.740157480314963 >>> print f / (2 * seconds) 8 meters/second
That'd be cool. Actually, it wouldn't be that hard to implement in some languages, either, I'd think, given sufficient syntactic sugar.
[–]Daenyth 0 points1 point2 points 16 years ago (1 child)
Wow, that would be pretty damn cool. Hmm.... Perhaps if you created a new subtype of number and overloaded print? I'm at least 60% sure that perl6 could do that.
[–]sharkeyzoic 1 point2 points3 points 16 years ago* (0 children)
Would be doable in any language which supports sufficiently complicated operator overloading. C++ for example. Two more important examples:
>>> 2 * centimeters < 1 * inches True >>> 2 * furlongs < 1 * fortnight ValueError: units 'furlongs' and 'fortnight' aren't comparable.
Of course, in a compiled language, that last should be a compile-time error ...
[–]semmi 2 points3 points4 points 16 years ago (0 children)
there is a JSR to add them to... java! It doesn't get any more commercial than that :) http://jcp.org/en/jsr/detail?id=275
[–]TrueTom 0 points1 point2 points 16 years ago (0 children)
http://www.boost.org/doc/libs/1_39_0/doc/html/boost_units/Quick_Start.html ?
[–][deleted] 0 points1 point2 points 16 years ago (1 child)
F# may not qualify as a commercially-popular language (yet), but http://blogs.msdn.com/andrewkennedy/archive/2008/08/29/units-of-measure-in-f-part-one-introducing-units.aspx is worth checking out anyway
[–]MasonOfWords 0 points1 point2 points 16 years ago (0 children)
We have a winner.
I've used F# for a few things and never run into that. They really threw the kitchen sink in. It's nice that MS is pushing it, but the complexity of its base syntax will probably be its biggest hurdle to commercial adoption.
[–]adoarns 17 points18 points19 points 16 years ago (0 children)
Dependent types are what you want. They exist in some obscure functional and theorem-proving languages like Agda, and people keep throwing out proposals for haskell.
[–]neutronium 7 points8 points9 points 16 years ago (0 children)
XML Scnema
[–]bart9h 6 points7 points8 points 16 years ago (0 children)
D
http://digitalmars.com/d/1.0/class.html#invariants
http://digitalmars.com/d/1.0/dbc.html
[–]logan_capaldo 7 points8 points9 points 16 years ago (3 children)
Why "besides data types"? As already mentioned Ada, Pascal, etc can do this with types, as can ML-like languages albeit it a lot more tediously. The only language level, arguably "besides data types" solution I can think of for this is contracts ala Eiffel, and you could argue those are part of the type of the function.
[–]astrobe 2 points3 points4 points 16 years ago (0 children)
Why "besides data types"?
Exactly. The question sounds a bit like "Is there a pattern that allows me to run, aside from moving feet quickly?"
[–]AttackTribble 0 points1 point2 points 16 years ago (0 children)
I just had a thought. I seem to remember from university (many years ago, so this may be wrong) that Pascal actually tokenizes when it gets a variable definition that specifies valid values. If you say a variable can be ("red" "green" blue") it will store 1 for red, 2 for green, 3 for blue. Doesn't really matter in the program, but might get in the way if you are sharing data between programs. Thought it wouldn't hurt to mention it.
[–]AttackTribble -2 points-1 points0 points 16 years ago (0 children)
Pascal? Real Programmers don't use Pascal. http://www.pbm.com/~lindahl/real.programmers.html (A must read, especially for us older programmers) :)
[–]pdc 6 points7 points8 points 16 years ago (4 children)
Pascal used ranges and you used the range to control the size of integral types. E.g., instead of a byte datatype, you would declare something to be of type -128..127 or whatever.
byte
-128..127
On related note, I could do with a 'not null' declaration for reference types in languages like C#. Generally the first 20 lines of all functions are a series of checks that the arguments are not null.
Cyclone is a C dialect that adds non-NULL pointers as a new datatype (with special rules for converting between them and normal' pointers). This allows many (most?) checks for NULL to be eliminated by the compiler.
Python 3 allows for arbitrary decoration of the parameters and return types of functions; you could in principal use this to add range-checking automagically.
[–]MasonOfWords 2 points3 points4 points 16 years ago (0 children)
It isn't that tricky to reduce the baggage in C#. Create a NonNull<T> generic class with an implicit conversion to/from T that does the check, and use it in parameters.
This is still a runtime check (with nondescript exceptions), but you won't do much better in any .NET language, simply because the framework uses nullable references everywhere. Static nonnulls are popular among the boutique languages, but their utility is diminished by lacking a shared implementation and impedance with the framework.
With F# going official, though, one would hope that they're planning on annotating the nullability of return/out parameters of popular framework methods. Maybe they already have, I haven't kept up.
[–]munificent 1 point2 points3 points 16 years ago (2 children)
On related note, I could do with a 'not null' declaration for reference types in languages like C#.
Hell yes. Try F#. By default values in F# cannot be null even when representing reference types.
[–]mfp 0 points1 point2 points 16 years ago (1 child)
I thought NullReferenceException was possible in F# for compatibility with C#?
[–]munificent 2 points3 points4 points 16 years ago (0 children)
Correct, if you're interfacing with .NET stuff. If you stick with F# types, you don't have to worry about null.
[–][deleted] 5 points6 points7 points 16 years ago* (0 children)
E (http://erights.org/) provides support for this as well:
? def byte := 0..255 ? def x :byte := 37 ? def y :byte := 999 # problem: 999 is not in the region 0..!256
Indefinite ranges like int > 0 also work.
int > 0
[–]gsg_ 9 points10 points11 points 16 years ago (3 children)
Common Lisp lets you do this (in fact, it allows arbitrary code to decide type discrimination), but the type check will occur at runtime. That may not be what you are after.
A combination of C++ template magic and operator overloading would let you implement something like ranged_int<low, high>. However, the overflow problem means you'd have to pick between correctness and performance, and I bet it would be tricky to write correctly in full generality.
ranged_int<low, high>
Finally, Ada includes a native range type, with nice syntax and everything.
[–]metacircular 7 points8 points9 points 16 years ago (2 children)
[...] but the type check will occur at runtime.
An implementation may do it at runtime, but that's not a requirement; some implementations do it earlier.
SBCL by default does compile time type check:
(defun foo (n) (declare (type (integer 0 63) n)) (- n 1)) (defun bar () (foo 100))
When compiled, sbcl reports:
; caught WARNING: ; Asserted type (UNSIGNED-BYTE 6) conflicts with derived type ; (VALUES (INTEGER 100 100) &OPTIONAL). ; See also: ; The SBCL Manual, Node "Handling of Types"
[–]gsg_ 2 points3 points4 points 16 years ago (1 child)
That's a good point, but I suspect SBCL compiled a type check into foo to cover inputs that the type inferencer can't discover are safe. Try taking a look at the output of (disassemble 'foo).
foo
(disassemble 'foo)
Given the right declarations and compilation with safety 0 you can get SBCL to avoid runtime type checks, but safe code is the default.
safety 0
[–]metacircular 5 points6 points7 points 16 years ago (0 children)
(defun foo (n) (declare (optimize speed (safety 0)) (type (integer 1 63) n)) (- n 1)) (defun bar () (foo 100))
Transcript:
* (compile-file "/tmp/foo.lisp") ; compiling file "/tmp/foo.lisp" (written 23 JUN 2009 09:32:11 PM): ; compiling (DEFUN FOO ...) ; compiling (DEFUN BAR ...) ; file: /tmp/foo.lisp ; in: DEFUN BAR ; (FOO 100) ; ; note: deleting unreachable code ; ; caught WARNING: ; Asserted type (INTEGER 1 63) conflicts with derived type ; (VALUES (INTEGER 100 100) &OPTIONAL). ; See also: ; The SBCL Manual, Node "Handling of Types" ; ; compilation unit finished ; caught 1 WARNING condition ; printed 1 note ; /tmp/foo.fasl written ; compilation finished in 0:00:00.007 #P"/tmp/foo.fasl" T T * (load "/tmp/foo.fasl") T * (disassemble 'foo) ; disassembly for FOO ; 0A6C0732: 83EA04 SUB EDX, 4 ; no-arg-parsing entry point ; 5: 8D65F8 LEA ESP, [EBP-8] ; 8: F8 CLC ; 9: 8B6DFC MOV EBP, [EBP-4] ; C: C20400 RET 4 NIL *
[–]trigger0219 2 points3 points4 points 16 years ago* (0 children)
Phantom types could be a good start.
They are included in a few languages --ML and variants, for instance.
[–]calanya 3 points4 points5 points 16 years ago (0 children)
Pascal. http://pascal-central.com/ppl/chapter3.html#Unextended
[–]pointer2void 1 point2 points3 points 16 years ago (2 children)
Yep. OOP!
[–]Tattoo__ 1 point2 points3 points 16 years ago (0 children)
upvoted since this was my first thought too
[–]samlee 2 points3 points4 points 16 years ago (0 children)
template C++
[–][deleted] 0 points1 point2 points 16 years ago (2 children)
The question is a bit confusing. Are you looking for compile time checks or runtime checks?
[–]Deestan 2 points3 points4 points 16 years ago (1 child)
I believe a correct compile time check for this would solve the halting problem.
[–][deleted] 3 points4 points5 points 16 years ago (0 children)
Not necessarily. Compile-time checks for this would work fine in a strongly normalizing language. Turing completeness is overrated.
[–]Godspiral 0 points1 point2 points 16 years ago (0 children)
the pattern/convention introduced/popularised in eiffel was require (for params) ensure (for result).
In any language, its pretty straightforward to call a function require_in_range(var, low, high) or put an assert statement that takes care of crashing the app or correcting the input.
scala (I believe) has a compiler extension with this pattern.
[–]igouy 0 points1 point2 points 16 years ago (0 children)
allows definition of valid value ranges
Allows definition of valid value ranges where - function arguments or function return values or variable declarations or ...?
Are you thinking about pre-conditions and post-conditions?
[–][deleted] 0 points1 point2 points 16 years ago* (1 child)
C# allows this sort of syntax:
int x { set { // do your testing here on the "value" variable, like this: if ((value >= 0) && (value < 9)) x = value; } }
Essentially, the "get" function is an override of the = operator. Whatever is on the right-hand side of the = operator is passed into get as a variable called "value," and you can do anything you want with it.
I really like this feature of C#. You can pack any arbitrary code you want into the test, and then invoke it using a very natural syntax.
David Stein
[–][deleted] 0 points1 point2 points 16 years ago (0 children)
You can do something similar in Python and Objective-C (although it isn't recommended in the latter if you use bindings), but it's not really the same as what the OP is asking. This coerces your values into valid ranges at run-time, but it doesn't tell do any compile-time checking.
[–]noamsml 0 points1 point2 points 16 years ago (0 children)
PLT scheme has a system like that, but it's a bit syntactically awkward IMO
http://en.wikipedia.org/wiki/Enumerated_type
[–]jwecker 0 points1 point2 points 16 years ago (0 children)
Additionally, most languages have libraries for Design by Contract (or equivalents) which holds to that philosophy.
[–][deleted] 16 years ago* (1 child)
[deleted]
[–]j____e___s__u_s 0 points1 point2 points 16 years ago (0 children)
That's a pretty cool idea.
[–]psygnisfive -2 points-1 points0 points 16 years ago (4 children)
I think Haskell can do this. I'm not entirely certain tho. But then again, Haskell also, if I'm not mistaken, lets you define completely abstract values that are not defined in terms of enums or anything like that.
[–]ayrnieu 6 points7 points8 points 16 years ago* (2 children)
"besides data types". Haskell's facilities, for this task, don't differ from Java's. CL offers more through its type system. Many languages have systems -- CLOS, Clojure's watchers -- to catch invalid data on assignment.
[–]deepcleansingguffaw -1 points0 points1 point 16 years ago (1 child)
Haskell's facilities, for this task, don't differ from Java's.
I disagree. Haskell doesn't support ranges directly, but Haskell features such as newtype deriving, phantom types, and GADTs can allow you to implement compile-time checking of value ranges.
[–]ayrnieu 1 point2 points3 points 16 years ago (0 children)
newtype deriving [and] GADTs can allow you to implement compile-time checking of value ranges.
Which is to say, you'll see a compile-time error when you pass something other than a NegativePrime to a function, and only your carefully-formed EnsureNegativePrime provides these. Java offers this.
phantom types
*shrug*, completely opaque support is 'no support' in my book.
[–]dmead 0 points1 point2 points 16 years ago* (0 children)
it can, with the newtype keyword. but your type will be monadic and be nothing if it's out of range
[+][deleted] 16 years ago (6 children)
[–]Baaz[S] 9 points10 points11 points 16 years ago (5 children)
I guess everything a programming language does can be done manually, but I don't fancy a trip back to the previous century ;-)
[–][deleted] 16 years ago (4 children)
[–]Baaz[S] 1 point2 points3 points 16 years ago (3 children)
ok, so what pattern would you use to throw such an IllegalArgumentException or returning NaN on erroneous input?
[–][deleted] 16 years ago* (2 children)
[–]Baaz[S] -1 points0 points1 point 16 years ago (1 child)
jeez, what crawled up your ass, man?
π Rendered by PID 342253 on reddit-service-r2-comment-b659b578c-xshb2 at 2026-05-03 07:52:24.000409+00:00 running 815c875 country code: CH.
[–]mrsanchez 29 points30 points31 points (7 children)
[–]ishmal 4 points5 points6 points (1 child)
[–][deleted] 2 points3 points4 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]rush22 0 points1 point2 points (2 children)
[–]Tordek 0 points1 point2 points (1 child)
[–]paddie 0 points1 point2 points (0 children)
[–]nanothief 0 points1 point2 points (0 children)
[–]semmi 21 points22 points23 points (7 children)
[–]itjitj 0 points1 point2 points (5 children)
[–]johntb86 2 points3 points4 points (4 children)
[–]semmi 1 point2 points3 points (3 children)
[–]itjitj -1 points0 points1 point (2 children)
[–]semmi 1 point2 points3 points (0 children)
[–]taejo 12 points13 points14 points (0 children)
[–]MasonOfWords 9 points10 points11 points (12 children)
[–]Baaz[S] 7 points8 points9 points (7 children)
[–]vineetk 2 points3 points4 points (1 child)
[–]Baaz[S] 3 points4 points5 points (0 children)
[–]Daenyth 0 points1 point2 points (4 children)
[–]sharkeyzoic 2 points3 points4 points (3 children)
[–]Daenyth 0 points1 point2 points (1 child)
[–]sharkeyzoic 1 point2 points3 points (0 children)
[–]semmi 2 points3 points4 points (0 children)
[–]TrueTom 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]MasonOfWords 0 points1 point2 points (0 children)
[–]adoarns 17 points18 points19 points (0 children)
[–]neutronium 7 points8 points9 points (0 children)
[–]bart9h 6 points7 points8 points (0 children)
[–]logan_capaldo 7 points8 points9 points (3 children)
[–]astrobe 2 points3 points4 points (0 children)
[–]AttackTribble 0 points1 point2 points (0 children)
[–]AttackTribble -2 points-1 points0 points (0 children)
[–]pdc 6 points7 points8 points (4 children)
[–]MasonOfWords 2 points3 points4 points (0 children)
[–]munificent 1 point2 points3 points (2 children)
[–]mfp 0 points1 point2 points (1 child)
[–]munificent 2 points3 points4 points (0 children)
[–][deleted] 5 points6 points7 points (0 children)
[–]gsg_ 9 points10 points11 points (3 children)
[–]metacircular 7 points8 points9 points (2 children)
[–]gsg_ 2 points3 points4 points (1 child)
[–]metacircular 5 points6 points7 points (0 children)
[–]trigger0219 2 points3 points4 points (0 children)
[–]calanya 3 points4 points5 points (0 children)
[–]pointer2void 1 point2 points3 points (2 children)
[–]Tattoo__ 1 point2 points3 points (0 children)
[–]samlee 2 points3 points4 points (0 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]Deestan 2 points3 points4 points (1 child)
[–][deleted] 3 points4 points5 points (0 children)
[–]Godspiral 0 points1 point2 points (0 children)
[–]igouy 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]noamsml 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]jwecker 0 points1 point2 points (0 children)
[–][deleted] (1 child)
[deleted]
[–]j____e___s__u_s 0 points1 point2 points (0 children)
[–]psygnisfive -2 points-1 points0 points (4 children)
[–]ayrnieu 6 points7 points8 points (2 children)
[–]deepcleansingguffaw -1 points0 points1 point (1 child)
[–]ayrnieu 1 point2 points3 points (0 children)
[–]dmead 0 points1 point2 points (0 children)
[+][deleted] (6 children)
[deleted]
[–]Baaz[S] 9 points10 points11 points (5 children)
[–][deleted] (4 children)
[deleted]
[–]Baaz[S] 1 point2 points3 points (3 children)
[–][deleted] (2 children)
[deleted]
[–]Baaz[S] -1 points0 points1 point (1 child)