REBOL3 tracker
  0.9.12 beta
Ticket #0002110 User: anonymous


TypeWish Statussubmitted Date20-Feb-2014 21:29
Versionr3 master CategoryNative Submitted byBrianH
PlatformAll Severityminor Prioritynormal

Summary DO-COMPARE function
Description DO-COMPARE would take two offset series references and three code blocks, and the same /case, /skip and /compare options that are to be standardized in #428 (same as SORT once that's fixed to match). The two series would be compared based on the #428 rules for a single comparison, and depending on the results one of the code blocks would be executed. By "a single comparison", that means that without /skip only the element at the series position is compared, while with /skip only the first span of that record size is compared. No /skip is the same as /skip 1, basically. The #428 rules mean that /all is not required, it's the default.

The three blocks would be for when the comparison finds the first series to be lesser than the second series at that spot, for when they're equal, or for when the first series is greater than the second series. These are the basic conditions that are used by sorting functions like quicksort. Having the three code blocks means that we don't need a /reverse option. The result of evaluating the block chosen is returned from DO-COMPARE.

The /compare option can take an integer or a comparator function. If it's an integer, it will be the (1-based) index of the element in the span to be compared, range-checked from 1 to the /skip size. If it's a function, the function gets called with the values at the positions if no /skip, or the series references at the positions if /skip; returning a positive number or true runs the first (lesser) block, returning 0 runs the second (equal) block, returning a negative number or false runs the third (greater) block. You may need to use a comparator function that returns the numbers if you want stable comparisons, since you need to use the equal block for that.

DO-COMPARE would be used to implement mezzanine database functions that follow the #428 rules, like #1971 and #1972. The underlying code might also be usable by native functions that follow those rules, like those mentioned in #428.

If DO-COMPARE has the same option style as the rest of the #428 functions then it will almost always need to be called using APPLY in mezzanine functions like FIND-MIN and FIND-MAX (#1971) - if we want to avoid that we should convert case, size and comparator to nullable direct parameters. However, if we do that then DO-COMPARE would be more awkward to use directly in user code. If it won't be significantly slower to have the regular options, the consistency would be a usability bonus.
Example code
>> do-compare "a" "A" ['lesser] ['equal] ['greater]
== equal
>> do-compare/case "a" "A" ['lesser] ['equal] ['greater]
== greater

>> do-compare "aa" "ab" ['lesser] ['equal] ['greater]
== equal  ; without /skip only the first element is compared
>> do-compare/skip "aabb" "abab" ['lesser] ['equal] ['greater] 2
== lesser  ; with /skip the first span is compared, the whole span compared by default
>> do-compare/skip/compare "aabb" "abab" ['lesser] ['equal] ['greater] 2 1
== equal  ; use /skip /compare integer! to just compare a single element

>> do-compare/skip/compare "aabb" "abab" ['lesser] ['equal] ['greater] 2 3
** out of range error triggered **
>> do-compare/compare "aabb" "abab" ['lesser] ['equal] ['greater] 1
== equal  ; no /skip the same as /skip 1, as far as /compare integer! range considered
>> do-compare/compare "aabb" "abab" ['lesser] ['equal] ['greater] 0
** out of range error triggered **

>> do-compare/compare "a" "b" ['lesser] ['equal] ['greater] :lesser?
== lesser
>> do-compare/compare "b" "a" ['lesser] ['equal] ['greater] :lesser?
== greater
>> do-compare/compare "a" "a" ['lesser] ['equal] ['greater] :lesser?
== greater  ; equal condition not detected by logic! return value
>> do-compare/compare "a" "a" ['lesser] ['equal] ['greater] func [a b] [case [a < b [1] a = b [0] 'else [-1]]]
== equal  ; equal detected by numeric return value

>> do-compare/compare "a" "b" ['lesser] ['equal] ['greater] func [a b] [print [type? a type? b] case [a < b [1] a = b [0] 'else [-1]]]
char! char!  ; with no /skip the element is passed to the comparator
== lesser
>> do-compare/skip/compare "a" "b" ['lesser] ['equal] ['greater] 1 func [a b] [print [type? a type? b] case [a < b [1] a = b [0] 'else [-1]]]
string! string!  ; with /skip the series is passed to the comparator, at the position
== lesser

>> do-compare/case/compare "a" "A" ['lesser] ['equal] ['greater] func [a b] [case [a < b [1] a = b [0] 'else [-1]]]
== equal  ; /compare function! overrides /case, but there's no need to trigger an error here

>> do-compare/case/compare "a" "A" ['lesser] ['equal] ['greater] func [a b] [case [a < b [1] a = b [0] 'else [-1]]]
== equal  ; /compare function! overrides /case, but there's no need to trigger an error here

>> do-compare/compare "a" "A" ['lesser] ['equal] ['greater] func [a b] ["not a number or logic"]
** trigger an error here about the unsupported type or bad value **

Assigned ton/a Fixed in- Last Update20-Feb-2014 22:31


Date User Field Action Change
20-Feb-2014 22:31 BrianH Code Modified -
20-Feb-2014 22:24 BrianH Code Modified -
20-Feb-2014 22:16 BrianH Code Modified -
20-Feb-2014 22:05 BrianH Description Modified -
20-Feb-2014 22:02 BrianH Description Modified -
20-Feb-2014 22:02 BrianH Code Modified -
20-Feb-2014 21:29 BrianH Ticket Added -