Rebol interpreter bug with comparison of dates
[1/25] from: al:bri:xtra at: 4-Dec-2002 11:34
I discovered a problem with dates and comparisons:
>> 'foo < 4/Dec/2002
== false
>> 4/Dec/2002 < 'foo
** Script Error: Cannot use lesser? on date! value
** Near: 4-Dec-2002 < 'foo
Note that the comparison can't be reversed. This seems to affect all Rebol versions,
including Rebol/Base.
The correct response from Rebol should be like:
>> 4/Dec/2002 < 'foo
== false
Andrew Martin
-><-
Andrew Martin
[2/25] from: jan:skibinski:sympatico:ca at: 3-Dec-2002 18:51
Hi Andrew,
The problem seems to be much broader:
>> 2 < 'foo
** Script Error: Expected one of: integer! - not: word!
But at least in this case the error message makes some sense.
Personally, I don't mind such a behaviour, which disallows
comparison of apples to oranges. But I think the definition
of (<) is too broad: it should be more specific - narrowed
down to the orderable things, such as numbers, dates,
but not points, etc. However, since the arguments of this
operator are untyped, the "help <" suggests that one can
compare anything to anything - and hence those unpleasent
runtime surprises.
Jan
[al--bri--xtra--co--nz] wrote:
[3/25] from: carl:cybercraft at: 4-Dec-2002 13:51
On 04-Dec-02, [al--bri--xtra--co--nz] wrote:
> I discovered a problem with dates and comparisons:
>>> 'foo < 4/Dec/2002
<<quoted lines omitted: 7>>
>>> 4/Dec/2002 < 'foo
> == false
Don't you mean true? Surely they both can't be greater than each
other?
--
Carl Read
[4/25] from: carl:cybercraft at: 4-Dec-2002 15:23
On 04-Dec-02, Jan Skibinski wrote:
> Hi Andrew,
> The problem seems to be much broader:
<<quoted lines omitted: 10>>
> runtime surprises.
> Jan
Going by previous comments, I think the comparing of different types
is allowed so routines for soting them will work. ie...
>> sort [2 foo]
== [foo 2]
>> sort [foo 2]
== [foo 2]
--
Carl Read
[5/25] from: jan:skibinski:sympatico:ca at: 3-Dec-2002 21:56
Carl Read wrote:
> On 04-Dec-02, Jan Skibinski wrote:
> > Hi Andrew,
<<quoted lines omitted: 19>>
> --
> Carl Read
Hi Carl,
But there is a lack of consequence, because this works:
>> sort/compare [1 3 11 2] (func[x y][x > y])
== [11 3 2 1]
and this fails:
>> sort/compare [2 foo] (func[x y][x > y])
** Script Error: Expected one of: integer! - not: word!
Jan
[6/25] from: al:bri:xtra at: 4-Dec-2002 16:14
Carl wrote:
> Andrew wrote:
> > The correct response from Rebol should be like:
> >>> 4/Dec/2002 < 'foo
> > == false
>
> Don't you mean true? Surely they both can't be greater than each other?
I'm right. :) Both:
4/Dec/2002 < 'foo
and:
'foo < 4/Dec/2002
should return 'false, because both are invalid comparisons.
Andrew Martin
ICQ: 26227169 http://valley.150m.com/
[7/25] from: al:bri:xtra at: 4-Dec-2002 16:24
Jan wrote:
> Personally, I don't mind such a behaviour, which disallows comparison of
apples to oranges. But I think the definition of (<) is too broad: it should
be more specific - narrowed down to the orderable things, such as numbers,
dates, but not points, etc. However, since the arguments of this operator
are untyped, the "help <" suggests that one can compare anything to
anything - and hence those unpleasant runtime surprises.
I prefer being able to compare any-value with any-value. I think it's more
versatile, as it enables one to write 'find -like functions that can find
values in a series and not have to type check first. Here's an example that
I was working on today (and where I found the problem):
Find-Range: function [Ranges [block!] Value [any-type!] /Strict] [Range] [
repeat Index length? Ranges compose [ ; 'Compose adds more
comparisons!
Range: Ranges/:Index
if all [Value >= Range/1 Value <= Range/2] [
return at Ranges Index
]
(
if not Strict [
[
if Value < Range/1 [
return at Ranges max 1 Index - 1
]
if all [
Value > Range/2
Index >= length? Ranges
] [
return at Ranges Index
]
]
]
)
]
]
; The following is normally in a separate file:
save %Term.r [; First and Last dates for each term.
[28/Jan/2002 28/Mar/2002]
[15/Apr/2002 28/Jun/2002]
[15/Jul/2002 20/Sep/2002]
[ 7/Oct/2002 6/Dec/2002]
]
Term: first Find-Range load %Term.r now/date
First_day_of_Term: first Term
Last_day_of_Term: last Term
Which finds the current (school) term for the current date (with allowance
for a date before or after the individual terms).
Andrew Martin
ICQ: 26227169 http://valley.150m.com/
[8/25] from: al:bri:xtra at: 4-Dec-2002 17:07
Jan wrote:
> >> sort/compare [1 3 11 2] (func[x y][x > y])
> == [11 3 2 1]
Just a helpful hint: One doesn't need to use parenthesis around the func and
it's two blocks. So:
>> sort/compare [1 3 11 2] func[x y][x > y]
== [11 3 2 1]
:)
Andrew Martin
ICQ: 26227169 http://valley.150m.com/
[9/25] from: jan:skibinski:sympatico:ca at: 3-Dec-2002 23:44
Hi Andrew,
> I prefer being able to compare any-value with any-value. I think it's more
> versatile, as it enables one to write 'find -like functions that can find
> values in a series and not have to type check first. Here's an example that
> I was working on today (and where I found the problem):
One of us is really confused here. :-)
I am provoked to use the type annotations here,
but believe me - that was not my intention to start with. :-)
You wrote a generic function
find-range :: [[b]] -> b -> [[b]]
which accepts a block of blocks of entities 'b and an entity 'b
as its two arguments, which you call 'Ranges and 'Value.
Your function produces as a result a block of blocks of the same entity 'b.
And you do not compare apples to oranges inside your function!
You correctly compare entities of the same type. But you wrote
the GENERIC function, which can work on any GENERIC
variable 'b, such as DATE, or an INTEGER, etc. For example::
>> find-range [[1 3][31 35] [38 91]] 32
== [[31 35] [38 91]]
So why do you need comparing apples to oranges, may I ask?
Best wishes,
Jan
P.S. Thanks for the advice about redundant parenthesis
[10/25] from: jan:skibinski:sympatico:ca at: 4-Dec-2002 0:35
> I wrote:
>
> You correctly compare entities of the same type. But you wrote
> the GENERIC function, which can work on any GENERIC
> variable 'b, such as DATE, or an INTEGER, etc.
To be more precise I should have added to the above:
- subject to the condition that 'b is orderable.
Generic as it is, your function should fail for a type b = POINT
and many other unorderable entities.
[11/25] from: anton:lexicon at: 4-Dec-2002 17:00
Andrew,
An invalid comparison should throw an
invalid comparison
error.
If a < b returns false, that implies
that a >= b should return true, but
under your scheme it would also return false.
I think your scheme would produce far more
complications.
Maybe an explanation for the problem is that
the < operator tries to convert the second
argument to the datatype of the first argument.
So a word can perhaps be converted to a date
(I did this in the console via a string).
But I had trouble converting a word to a date!
Anton.
[12/25] from: al:bri:xtra at: 4-Dec-2002 20:15
Jan wrote:
> You correctly compare entities of the same type. But you wrote the GENERIC
function, which can work on any GENERIC variable 'b, such as DATE, or an
INTEGER, etc. For example::
> >> find-range [[1 3][31 35] [38 91]] 32
> == [[31 35] [38 91]]
>
> So why do you need comparing apples to oranges, may I ask?
Unfortunately, my example wasn't good enough to show why. Sorry about that.
I wanted to make 'Find-Range operate _exactly_ the same way as Rebol's 'find
works:
>> find [1 2 3 foo "test" #issue] 'bah
== none
>> find [1 2 3 foo "test" #issue] "test"
== ["test" #issue]
Note that 'find can find any value in the series, just like 'Find-Range can
find any range that matches the value. This allows me to extend the words in
my Rebol vocabulary.
Andrew Martin
ICQ: 26227169 http://valley.150m.com/
[13/25] from: carl:cybercraft at: 4-Dec-2002 21:08
On 04-Dec-02, Anton wrote:
> Andrew,
> An invalid comparison should throw an
<<quoted lines omitted: 4>>
> I think your scheme would produce far more
> complications.
I tend to agree here - it should return an error when it doesn't make
sense to compare different datatypes.
> Maybe an explanation for the problem is that
> the < operator tries to convert the second
<<quoted lines omitted: 18>>
>>
>> Andrew Martin
--
Carl Read
[14/25] from: anton:lexicon at: 4-Dec-2002 19:29
Sorry, I meant:
So a *date* can perhaps be converted to a *word*.
But I had trouble converting a word to a date!
Anton.
[15/25] from: g:santilli:tiscalinet:it at: 4-Dec-2002 11:49
Hi Andrew,
On Wednesday, December 4, 2002, 4:24:42 AM, you wrote:
AM> I prefer being able to compare any-value with any-value. I think it's more
AM> versatile, as it enables one to write 'find -like functions that can find
safe-greater?: func [
"A GREATER? that works with all datatypes"
value1
value2
] [
greater? reduce [:value1] reduce [:value2]
]
safe-lesser?: func [
"A LESSER? that works with all datatypes"
value1
value2
] [
LESSER? reduce [:value1] reduce [:value2]
]
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[16/25] from: jan:skibinski:sympatico:ca at: 4-Dec-2002 10:07
Hi Gabriele,
You just proved that you could do anything with Rebol. :-)
But what does this mean:
>> safe-greater? 2x4 1x3
== true
This is a classical example of concept stretching and this is what
bites later on.
(Ignore what follows, or read on - this is just and example
illustrating the above statement.)
..........
This is what happened in Haskell Prelude, where
someone erronously decided to define a class Num of numbers
as entities supporting: (+), (-), (*), (>), (<), (==) and few other
operations. (The comparison operations got there by inheritance
from the Ord class, but that's the minor detail .)
Any entity claiming to be an instance of the Number class, such
as Integer, is entitled to use any of those operators.
As a tradition has it with any newly designed language,
noone cared at that time about complex numbers.
[It happened in C, in Eiffel, in Java, in Rebol - you name it.]
So when the datatype Complex was finally introduced a natural
reaction was to make it an instance of a Num class, so
one could use (+) in expressions like this:
c + d where
c = (2, 3)
d = (1, 0)
But then the concept stretching took place, as far as the comparisons
are concerned. Complex numbers, similar as pairs in Rebol,
are not orderable. Of course, you can always make arbitrary decisions
and say: "Well, this is just one exceptional kind of number, so let
us compare it by its norm: square-root x * x + (y * y)". And so
they did. But this is not what the mathematicans like,
and unfortunately this is not the only one single exception.
People started thinking: "Why cannot I use (+) operation on my
matrix package? True, a matrix is not a number, but I can add
matrices, can't I? Give me back my (+) operator so I will use
it with grace anywhere where it make sense to use it!"
But the problem with this is that in order to use (+) one
would have to make Matrix datatype an instance of class Num,
which obviously is a gross misnomer. But even if this was
somehow acceptable, the Matrix would have to support
all other operations from the Num class - including
comparisons: (>), (<), etc.? But how to compare two
matrices? What does is mean: mat-a > mat-b?
Well, this is where the concept stretching has bitten again.
To start with, there was no need to throw all those arithmetic
and comparison operations into one common class and call it
the Num. One could start small and define a RING class
that supports only two operations: (+) and (-),
or (+) and 'negate if you wish.
Any number, including Complex could be made an instance
of a Ring. Matrices could be rings too. And Tensors ...
And one does not have to claim that one knows how to
compare Complex numbers or Matrices. There is no
need for it.
To finish up the story: From time to time people come up with
new proposals for alternative Haskell Prelude, where
those things are to be clarified and corrected. Everyone agrees
that this has to be done sooner or later. Unfortunately, things
got so far already that it is hard to untangle the old jungle
of misconceptions and its hard to decide on what is supposed
to be backward compatible and whatt not. And the old Prelude
still persists even though people complain, complain, complain....
Jan
Gabriele Santilli wrote:
[17/25] from: g:santilli:tiscalinet:it at: 4-Dec-2002 16:58
Hi Jan,
On Wednesday, December 4, 2002, 4:07:13 PM, you wrote:
JS> But what does this mean:
JS> >> safe-greater? 2x4 1x3
JS> == true
That REBOL will, for some reason, sort 2x4 after 1x3. (I wrote
those two functions to use them in my b*tree implementation; you
will want to insert in it any REBOL value like you can do in a
REBOL hash!, and you will want it to sort values in the same way
SORT does...)
I know that this does not make sense, and RT knows too. A couple
versions before the current one (maybe you were not here yet)
GREATER? and LESSER? were able to compare pair!s; Carl decided
that it wasn't a good thing after all and so now it gives an
error.
So, I agree with you that comparison only makes sense to things
that can be ordered; however, due to its nature, REBOL will
actually order any value, even if this ordering is absolutely
arbitrary. You don't really want SORT to give back an error, and
once we have a function that can sort any couple of REBOL values,
we have an implicit (even if arbitrary) ordering relation between
all of the REBOL values.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[18/25] from: joel:neely:fedex at: 4-Dec-2002 14:57
Hi, Jan,
Just to take the "road less travelled"... ;-)
Jan Skibinski wrote:
> But what does this mean:
> >> safe-greater? 2x4 1x3
> == true
>
> This is a classical example of concept stretching and this
> is what bites later on...
>
I'm actually sympathetic toward your skepticism re "concept stretching"
and have raised questions about how much we can sweep under the rug of
polymorphism
.
However, on the specific issue of comparing PAIR! values, we've had
this debate on the list a while back, and my personal conclusion was
that
2x4 > 1x3
should evaluate to TRUE (and, of course, reversing the values should
return FALSE ;-) My basis for arguing that position was that REBOL
already has "unified" a number of data types through the concept
(though without official terminology) of ordered composite values.
Specifically, there are many types for which FIRST , SECOND , and so
on, are defined. For example, in addition to the series types, for
which the ordinal selectors have the obvious meaning, REBOL applies
the selectors to dates as follows:
>> foo: now/date == 4-Dec-2002
>> first foo == 2002
>> second foo == 12
>> third foo == 4
to times as:
>> foo: now/time == 14:27:01
>> first foo == 14
>> second foo == 27
>> third foo == 1
and so on. (And we have the shorthand of X/1 for FIRST X and so on.)
Now, if we have a type which is a sequence of component types, where
each component type posesses a set of ordering relations, it seems
perfectly reasonable to define the ordering relations on the
(top-level) type in terms of the lexicographic ordering across the
collection. In pseudo-REBglish,
a < b
whenever
any [
a/1 < b/1
all [a/1 = b/1 a/2 < b/2]
all [a/1 = b/1 a/2 = b/2 a/3 < b/3]
... and so on ...
]
This works exactly as expected for DATE! and TIME! values, but also
works for heterogeneous series values! (See the postscript for an
exhaustive/exhausting illustration. ;-) The same game can be played
for tuple values, BTW.
That said, even though I completely agree that there is no "natural"
ordering for cartesian coordinates *as spatial coordinates* I believe
that there *is* a natural ordering for ordered pairs of integers,
namely the lexicographic order. The PAIR! type certainly has all of
the symptoms of being an ordered pair of integers, and has FIRST and
SECOND (or /1 and /2) defined. Allowing PAIR! values to be treated
as ordered pairs (including the support for lexicographic ordering
in support of such an interpretation) shouldn't break any code that
simply uses them as e.g. pixel coordinates, but would extend their
range of possible applicability.
In short, things that otherwise behave as tuples (in the Mathematical
sense of the word, not in the REBOL TUPLE! sense) should all be able
to participate in meaningful tuple-like behavior, including the
ability to be lexicographically ordered.
I'm now climbing down off my soapbox... ;-)
-jn-
Here's a generated example showing how REBOL handles order inquiries
over heterogeneous blocks. (This is output from a wad of nested loops
that actually set up the values and printed the output; I assume it
is too obvious to waste bandwidth on.)
[1 "A" #"a"] < [1 "A" #"a"] = false
[1 "A" #"a"] < [1 "A" #"b"] = true
[1 "A" #"a"] < [1 "B" #"a"] = true
[1 "A" #"a"] < [1 "B" #"b"] = true
[1 "A" #"a"] < [2 "A" #"a"] = true
[1 "A" #"a"] < [2 "A" #"b"] = true
[1 "A" #"a"] < [2 "B" #"a"] = true
[1 "A" #"a"] < [2 "B" #"b"] = true
[1 "A" #"b"] < [1 "A" #"a"] = false
[1 "A" #"b"] < [1 "A" #"b"] = false
[1 "A" #"b"] < [1 "B" #"a"] = true
[1 "A" #"b"] < [1 "B" #"b"] = true
[1 "A" #"b"] < [2 "A" #"a"] = true
[1 "A" #"b"] < [2 "A" #"b"] = true
[1 "A" #"b"] < [2 "B" #"a"] = true
[1 "A" #"b"] < [2 "B" #"b"] = true
[1 "B" #"a"] < [1 "A" #"a"] = false
[1 "B" #"a"] < [1 "A" #"b"] = false
[1 "B" #"a"] < [1 "B" #"a"] = false
[1 "B" #"a"] < [1 "B" #"b"] = true
[1 "B" #"a"] < [2 "A" #"a"] = true
[1 "B" #"a"] < [2 "A" #"b"] = true
[1 "B" #"a"] < [2 "B" #"a"] = true
[1 "B" #"a"] < [2 "B" #"b"] = true
[1 "B" #"b"] < [1 "A" #"a"] = false
[1 "B" #"b"] < [1 "A" #"b"] = false
[1 "B" #"b"] < [1 "B" #"a"] = false
[1 "B" #"b"] < [1 "B" #"b"] = false
[1 "B" #"b"] < [2 "A" #"a"] = true
[1 "B" #"b"] < [2 "A" #"b"] = true
[1 "B" #"b"] < [2 "B" #"a"] = true
[1 "B" #"b"] < [2 "B" #"b"] = true
[2 "A" #"a"] < [1 "A" #"a"] = false
[2 "A" #"a"] < [1 "A" #"b"] = false
[2 "A" #"a"] < [1 "B" #"a"] = false
[2 "A" #"a"] < [1 "B" #"b"] = false
[2 "A" #"a"] < [2 "A" #"a"] = false
[2 "A" #"a"] < [2 "A" #"b"] = true
[2 "A" #"a"] < [2 "B" #"a"] = true
[2 "A" #"a"] < [2 "B" #"b"] = true
[2 "A" #"b"] < [1 "A" #"a"] = false
[2 "A" #"b"] < [1 "A" #"b"] = false
[2 "A" #"b"] < [1 "B" #"a"] = false
[2 "A" #"b"] < [1 "B" #"b"] = false
[2 "A" #"b"] < [2 "A" #"a"] = false
[2 "A" #"b"] < [2 "A" #"b"] = false
[2 "A" #"b"] < [2 "B" #"a"] = true
[2 "A" #"b"] < [2 "B" #"b"] = true
[2 "B" #"a"] < [1 "A" #"a"] = false
[2 "B" #"a"] < [1 "A" #"b"] = false
[2 "B" #"a"] < [1 "B" #"a"] = false
[2 "B" #"a"] < [1 "B" #"b"] = false
[2 "B" #"a"] < [2 "A" #"a"] = false
[2 "B" #"a"] < [2 "A" #"b"] = false
[2 "B" #"a"] < [2 "B" #"a"] = false
[2 "B" #"a"] < [2 "B" #"b"] = true
[2 "B" #"b"] < [1 "A" #"a"] = false
[2 "B" #"b"] < [1 "A" #"b"] = false
[2 "B" #"b"] < [1 "B" #"a"] = false
[2 "B" #"b"] < [1 "B" #"b"] = false
[2 "B" #"b"] < [2 "A" #"a"] = false
[2 "B" #"b"] < [2 "A" #"b"] = false
[2 "B" #"b"] < [2 "B" #"a"] = false
[2 "B" #"b"] < [2 "B" #"b"] = false
--
----------------------------------------------------------------------
Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446
[19/25] from: jan:skibinski:sympatico:ca at: 4-Dec-2002 16:05
Hi Gabriele,
A summary of this thread - as I see it:
Things that break Joel's "Principle of the Least Surprise":
+ comparison functions are improperly documented
+ 'sort and 'sort/compare are logically incompatible.
+ arbitrary ordering of incompatible things is
undocumented and subject to wild guesses, experiments
and luck - if a third party code is documented.
.
Best wishes
Jan
Gabriele Santilli wrote:
[20/25] from: jan:skibinski:sympatico:ca at: 4-Dec-2002 16:53
Ho Joel,
Actually I do not mind lexicographical ordering -
providing that I exactly know what it is. Some simple
official rules would be helpful, such as
a < b means mold a < mold b
, or whatever.
What to do when 'a is an object? Mold it?
And I simply do not know, whether your list
of rules is a norm, a suggestion, or whatever.
My first sentence ever voiced in this thread was using
words like "Personally, I do not mind". I am not trying
to convince anyone to anything, and I consider it
a personal choice whether or not someone wishes
to take some kind of risks with their code. My personal
choice is: "play it safe, play it by simple predictable rules."
All the best,
Jan
[21/25] from: lmecir:mbox:vol:cz at: 5-Dec-2002 10:52
Hi Gabriele,
> So, I agree with you that comparison only makes sense to things
> that can be ordered; however, due to its nature, REBOL will
<<quoted lines omitted: 3>>
> we have an implicit (even if arbitrary) ordering relation between
> all of the REBOL values.
just a little nitpicking: unfortunately, your comparison functions will not
compare any Rebol values. You would have to work harder to achieve that. The
trouble is with:
1) errors
2) cyclic series
Some inspiration can be found in
http://www.rebolforces.com/~ladislav/evaluation.html .
As to whether it is useful to have such comparison:
Some applications may need it, therefore it might be handy.
Ciao
-L
[22/25] from: g:santilli:tiscalinet:it at: 5-Dec-2002 12:35
Hi Ladislav,
On Thursday, December 5, 2002, 10:52:18 AM, you wrote:
LM> 1) errors
LM> 2) cyclic series
Is SORT able to put them in some order? (It looks like REBOL
considers all error!s to be equal, and I was able to compare some
simple cyclic blocks with my functions...)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[23/25] from: lmecir:mbox:vol:cz at: 5-Dec-2002 21:47
Hi Gabriele,
> I was able to compare some
> simple cyclic blocks with my functions...)
interesting, Rebol crashed here, but you probably used a beta, didn't you?
Ciao
-L
[24/25] from: rotenca:telvia:it at: 5-Dec-2002 22:44
Hi Ladislav and Gabriele,
I did not have any crash here.
But how rebol sort Object? I did not see a logic in what happens:
>> sort reduce [context [a: "a"]context [b: "b"]]
== [
make object! [
b: "b"
]
make object! [
a: "a"
]]
---
Ciao
Romano
[25/25] from: g:santilli:tiscalinet:it at: 6-Dec-2002 2:26
Hi Ladislav,
On Thursday, December 5, 2002, 9:47:08 PM, you wrote:
LM> interesting, Rebol crashed here, but you probably used a beta, didn't you?
Yep, this is View 1.2.8.3.1.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted