jastrachan | 31 Mar 09:21 2005

Re: thoughts about the Range concept

On 30 Mar 2005, at 20:32, Dierk Koenig wrote:
> Hm,
> I'm a bit frustrated from being obviously unable
> to make my point clear.
> I'll give it a last try, and if I fail again, we
> just forget it and live happily ever after...
> For the moment, lets try to split design from
> implementation.
> Currently Range extends List - implementation wise.
> James and Martin said that Range is a _subtype_ of List
> - design wise.
> Like I learned OO, this means:
> - Range must at minimum provide List's API.
> - Range must not break List's invariants.
> - Range must have no stronger preconditions nor
>   weaker postconditions than List.
> These rules are just a formal way of making
> "Range IS-A List" concrete and testable.
> As I cannot possibly make my mind finding a
> notion of the word "Range" that IS-A List, I
> try to test it by the rules.

AFAIK we support all of the semantics of an immutable List

> What invariants has a List that users of a List
> rely upon? Let's take an easy one:
> a) For all elements e of List l,
>    l.contains(e) if and only if
>      there is an index i such that l[i] == e
> How does this relate to Float Ranges (or other
> "continuous" datatypes)?
> - either we follow Martin, comply to the invariant having
>   (0.0..1.0).contains(0.99999) == false
> - or we follow James' pragmatic way and Brad's advice of
>   implementing float ranges like they currently are,
>   breaking List's invariant a).

For float/double types, we need a step so that as we iterate through 
the range we know how to make each item in the range. Right now we use 
1.0 as the step.

> The latter allows a wider applicability of Ranges, e.g
> having Float ranges in grep filters and switch cases.
> But for a clear OO _design_ we should then release
> Range from the List dependency, honestly stating that
> Range is not a subtype of List.
> Where needed, Range.toList() can be used for convenient
> List creations, like in (0..1000).toList().
> There would be no need to implement plus(), minus(),
> retainAll(), etc. for Ranges.
> Ok, so.
> I apologize for being so tense with what some of you
> may dismiss as a minor issue. It's just that not having
> a clear concept drives me crazy.
> Thanks to everybody for participating, investing your time,
> and sharing your thoughts.

Ah I think I understand the disconnect now.

Currently Range (IntRange / ObjectRange) assume that there is a lower & 
upper bound and a way of stepping through the discrete values. IntRange 
uses 1 as the increment. ObjectRange currently uses 
incrementing/descrementing methods. (We could add support for a step 
value too)

Irrespective of the implementation, the Range implementations are 
currently equivalent to lists; logically containing a sequence of 
values (not a continuous range like 0.2 .. 0.5 including 
0.2123456643243 for example). Right now we don't have a Range 
implementation that can step in 0.25 intervals (though it would be 
fairly easy to write).

Now I think I get John's point about contains() versus 
intervalContains(). The former is true if the value is equal to an 
element in the List, the latter is true if the value is within the 
bounds of the range.

e g..

def r = (0.1..2.1).step(0.1)
assert r.contains(0.4)
assert r.contains(0.45) == false
assert r.intervalContains(0.45)