generic ordinal-relevant operators
Hello, Considering this context of comparison operators: Generic Num Str --- =:= # equality (container) !=:= # negated equality (container) === # equality (value, eternal semantics) !=== # negated equality (value, eternal semantics) eqv ==eq# equality (value, snapshot semantics) !eqv !== !eq # negated equality (value, snapshot semantics) !=ne# traditional shortcuts for previous < lt# less than > gt# greater than <=le# less than or equal to >=ge# greater than or equal to cmp <=> leg # lt => -1, eq => 0, gt => +1 ~~# smart match (see smartmatch) !~~ # negated smart match It stands out that there seems to be no generic ordinal-relevant operators specifically for less-than, greater-than, etc, while there are such that cast their arguments as Num or Str. While one can still emulate such operators on generic types using cmp (whose existence I am very glad for), I would like to propose that explicit less-than, greater-than etc exist partly for reasons of parity, so for example, one can take for example 2 Date-representing types and ask simply if one is earlier than the other, etc, and do this within the native type. For simplicity, these operators would just work using snapshot semantics as, AFAIK, cmp and the Num and Str specific operators do. Barring any better suggestions for names of such operators, I suggest we could follow a precedent laid down by eqv and name them: ltv, gtv, lev, gev (and also nev if that is useful); and we have visual consistency in that way. On a tangential matter, I believe there should also be generic 'min' and 'max' type operators for all ordinal types, which would be useful in list summarizing activities; they would return the value from a list that would sort first or last. I don't see the reduce meta-operator as being applicable to this, since reducing using less-than eg, will return a boolean result. Unlike, say, 'avg' or 'sum', 'min' and 'max' are conceptually generic to all ordinal types. So, is this workable? -- Darren Duncan
Re: generic ordinal-relevant operators
Darren Duncan wrote: Considering this context of comparison operators: Generic Num Str --- =:= # equality (container) !=:= # negated equality (container) === # equality (value, eternal semantics) !=== # negated equality (value, eternal semantics) eqv ==eq# equality (value, snapshot semantics) !eqv !== !eq # negated equality (value, snapshot semantics) !=ne# traditional shortcuts for previous Remind me again why it's a good idea to have distinct eqv, ==, and eq operators, and for == to represent the numeric equivalence test instead of an argument-based equivalence test? Personally, I'd rather replace ('eqv', '==', 'eq') with either ('==', '+==', '~==') or just '=='. In the latter case, the current '==' and 'eq' semantics could be preserved by applying the unary '+' or '~' operators to both operands: as I understand it, "$a == $b" is semantically indistinguishable from "+$a eqv +$b". In terms of ordinal types, '>', '<', '>=', and '<=' would be the "generic" ordinal comparators, and you'd do the same sort of implicit or explicit type coercion that's done with '=='. Mind you, if you go with the ('==', '+==', '~==') set of equivalence operators, '+>' and '+<' would now mean "numerically greater than" and "numerically less than", respectively, and the shift-right and shift-left operators would have to be relabelled (e.g., to '+>>' and '+<<'). Likewise, ('cmp', '<=>', 'leg') would become ('<=>', '+<=>', '~<=>'), or just '<=>'. (Technically, the existence of '+==' and '~==' would imply the existence of '?==' for completeness sake; but I can't think of any reasonable case where '?==' would be used.) While one can still emulate such operators on generic types using cmp (whose existence I am very glad for), I would like to propose that explicit less-than, greater-than etc exist partly for reasons of parity, so for example, one can take for example 2 Date-representing types and ask simply if one is earlier than the other, etc, and do this within the native type. Agreed. If we assume that the semantics of '==' are non-negotiable, then: Barring any better suggestions for names of such operators, I suggest we could follow a precedent laid down by eqv and name them: ltv, gtv, lev, gev (and also nev if that is useful); and we have visual consistency in that way. My problem with these is the alphabet soup mentality that they entail: 'eq' meaning "string-based equivalence" makes _some_ sense because 'eq' is composed of letters and strings are composed of letters; but even here, there's cognitive dissonance as my brain sees things like '<=>' vs. 'leg' and has to reconcile them as being essentially the same thing. Extending this to generic ordinal comparisons aggravates the problem without even the tenuous "use letters to compare letters" reasoning to back it up. If you're going to use letter-based operators, follow the precedence set by 'cmp' (which abbreviates 'compare'): use something like 'before' and 'after' for the generic versions of '<' and '>'. Better, ditch the letter soup entirely: in reverse analogy to my original suggestion, use a '*' leading character to denote the generic comparators: '*<', '*>', '*<=', and '*>='. On a tangential matter, I believe there should also be generic 'min' and 'max' type operators for all ordinal types, which would be useful in list summarizing activities; they would return the value from a list that would sort first or last. Agreed. I don't see the reduce meta-operator as being applicable to this, since reducing using less-than eg, will return a boolean result. And rightfully so: '[<] $a, $b, $c, ...' is asking "are these arguments in a strictly decreasing order?" which is a perfectly valid question to ask. Unlike, say, 'avg' or 'sum', 'min' and 'max' are conceptually generic to all ordinal types. And they're more readable (and probably faster) than 'sort(...)[0]' and 'sort(...)[-1]', which would accomplish the same thing. In effect, we're talking about an Ordinal role, which would package together the generic ordinal comparators ('*<', '*>', '*<=', '*>=', and 'cmp'), along with 'sort', 'min', and 'max'. Tangentially related, I'd like to suggest that the negation meta-operator be generalized from comparison operators to any binary operator that returns a boolean value (or possibly even to any operator that returns a boolean value, so that '!?$x' would mean "coerce to boolean, then negate its value"). -- Jonathan "Dataweaver" Lang
Re: generic ordinal-relevant operators
At 5:24 PM -0800 11/11/06, Jonathan Lang wrote: Remind me again why it's a good idea to have distinct eqv, ==, and eq operators, and for == to represent the numeric equivalence test instead of an argument-based equivalence test? Personally, I'd rather replace ('eqv', '==', 'eq') with either ('==', '+==', '~==') or just '=='. In the latter case, the current '==' and 'eq' semantics could be preserved by applying the unary '+' or '~' operators to both operands: as I understand it, "$a == $b" is semantically indistinguishable from "+$a eqv +$b". In terms of ordinal types, '>', '<', '>=', and '<=' would be the "generic" ordinal comparators, and you'd do the same sort of implicit or explicit type coercion that's done with '=='. Mind you, if you go with the ('==', '+==', '~==') set of equivalence operators, '+>' and '+<' would now mean "numerically greater than" and "numerically less than", respectively, and the shift-right and shift-left operators would have to be relabelled (e.g., to '+>>' and '+<<'). Likewise, ('cmp', '<=>', 'leg') would become ('<=>', '+<=>', '~<=>'), or just '<=>'. Better, ditch the letter soup entirely: in reverse analogy to my original suggestion, use a '*' leading character to denote the generic comparators: '*<', '*>', '*<=', and '*>='. I like that proposal a lot, in principle, as it gives us a lot more flexability and visual consistency. I hope that @Larry can get behind something like it. One detail to work out is whether we use *< etc or < etc for the generic. Either option has its advantages or disadvantages. (Whatever's chosen and any renaming fall-out from that, I don't think a main operator can contain a << or >> like your bit-shift examples since those could be confused with hyper-operators.) (Technically, the existence of '+==' and '~==' would imply the existence of '?==' for completeness sake; but I can't think of any reasonable case where '?==' would be used.) I don't see that it would be a bad thing. Even if little used, it does make conceptual sense. ?== checks if both arguments are the same truth-wise, and !?== checks if they are different. Assuming we defined for repeatable ordering purposes that False < True (which is consistent with any common string or numifications of booleans), then ?< et al produce predictable results. If we assume that the semantics of '==' are non-negotiable, then: Barring any better suggestions for names of such operators, I suggest we could follow a precedent laid down by eqv and name them: ltv, gtv, lev, gev (and also nev if that is useful); and we have visual consistency in that way. My problem with these is the alphabet soup mentality that they entail: 'eq' meaning "string-based equivalence" makes _some_ sense because 'eq' is composed of letters and strings are composed of letters; but even here, there's cognitive dissonance as my brain sees things like '<=>' vs. 'leg' and has to reconcile them as being essentially the same thing. Extending this to generic ordinal comparisons aggravates the problem without even the tenuous "use letters to compare letters" reasoning to back it up. If you're going to use letter-based operators, follow the precedence set by 'cmp' (which abbreviates 'compare'): use something like 'before' and 'after' for the generic versions of '<' and '>'. I agree. And in fact, once we have a third column of order-determing operators rather than just Num + Str, the arrangement of some alphabetic and some not comes to look positively ugly. So better to make them all alpha or all non, and it would seem non is better. So == and < and so on for all comparing operators. (And as an aside, we get rid of !ne.) In effect, we're talking about an Ordinal role, which would package together the generic ordinal comparators ('*<', '*>', '*<=', '*>=', and 'cmp'), along with 'sort', 'min', and 'max'. Yes. And I was thinking about an Ordinal role before too. Logically, some types are ordinal (eg, numbers (except complex?), strings, dates), or could be assigned a canonical ordinal form (eg, booleans, bits) and some are simply not ordinal (probably eg, a polygon or a collection type). So, while it could make sense to have an Ordinal role, which types individually can .does(), and only those have <, >, <=, >=, <=>, min, max, sort, etc, there is the question about how to handle types that don't .does() Ordinal in some generic situations. Either they fail, or there is some sort of fallback provided by Object, such as they end up sorting on their memory addresses; but in the latter case, we don't need an Ordinal role because every type will be doing it in some fashion or other due to Object's defaults. Tangentially related, I'd like to suggest that the negation meta-operator be generalized from comparison operators to any binary operator that returns a boolean value (or possibly even to any operator that returns a boolean value, so that '!?$x' would mean "coerce to boolean,
Re: generic ordinal-relevant operators
Darren Duncan wrote: Jonathan Lang wrote: >In terms of ordinal types, '>', '<', '>=', and '<=' would be the >"generic" ordinal comparators, and you'd do the same sort of implicit >or explicit type coercion that's done with '=='. Mind you, if you go >with the ('==', '+==', '~==') set of equivalence operators, '+>' and >'+<' would now mean "numerically greater than" and "numerically less >than", respectively, and the shift-right and shift-left operators >would have to be relabelled (e.g., to '+>>' and '+<<'). -snip- > Better, ditch the letter soup entirely: in >reverse analogy to my original suggestion, use a '*' leading character >to denote the generic comparators: '*<', '*>', '*<=', and '*>='. I like that proposal a lot, in principle, as it gives us a lot more flexability and visual consistency. I hope that @Larry can get behind something like it. Note that this is two competing suggestions: one where '==' means 'generic equivalence', '+==' means 'numeric equivalence', and '*==' means 'string equivalence'; and another where '*==' means 'generic equivalence', '==' means 'numeric equivalence', and 'eq' means 'string equivalence' (with '<', '>', etc. following suit). The goal of the second proposal is to leave existing operator names unchanged, while the goal of the first proposal is to provide a consistent and intuitive naming convention. One detail to work out is whether we use *< etc or < etc for the generic. Either option has its advantages or disadvantages. (Whatever's chosen and any renaming fall-out from that, I don't think a main operator can contain a << or >> like your bit-shift examples since those could be confused with hyper-operators.) Yes and no; binary hyper-operators require double arrows on both sides, so it's possible that the parser _could_ distinguish double-angle bit-shift operators from hyper-operators. Still, for the sake of clarity, I could see basing bit-shifting off of thin-tailed arrowheads: '+->' and '+<-'. Note that this isn't a problem with the '*<' model: '*<' would be a generic less-than; '<' would be a numeric less-than; 'lt' would be a stringified less than; '+<' would be a numeric bit-shift; and '~<' would be a string-based bit-shift. No ambiguity. >(Technically, the existence of '+==' and '~==' would imply the >existence of '?==' for completeness sake; but I can't think of any >reasonable case where '?==' would be used.) I don't see that it would be a bad thing. Even if little used, it does make conceptual sense. ?== checks if both arguments are the same truth-wise, and !?== checks if they are different. Assuming we defined for repeatable ordering purposes that False < True (which is consistent with any common string or numifications of booleans), then ?< et al produce predictable results. True enough. It's not _much_ of a mark in favor of the 'consistent and intuitive naming convention' proposal; but it's a mark in its favor nonetheless. And in fact, once we have a third column of order-determing operators rather than just Num + Str, the arrangement of some alphabetic and some not comes to look positively ugly. So better to make them all alpha or all non, and it would seem non is better. So == and < and so on for all comparing operators. (And as an aside, we get rid of !ne.) Another mark in its favor... :) The two biggest marks against it are what it does to the bit-shift operators (which isn't much of an issue IMHO; they're already changed from perl5) and the drastic change from perl5-style thinking, where numeric comparisons are effectively the default (which could very well be a show-stopper). >In effect, we're talking about an Ordinal role, which would package >together the generic ordinal comparators ('*<', '*>', '*<=', '*>=', >and 'cmp'), along with 'sort', 'min', and 'max'. Yes. And I was thinking about an Ordinal role before too. Logically, some types are ordinal (eg, numbers (except complex?), strings, dates), or could be assigned a canonical ordinal form (eg, booleans, bits) and some are simply not ordinal (probably eg, a polygon or a collection type). Complex numbers can be ordered, but only if you're willing to accept that multiplication by a complex number will mess with that order in a not-always-intuitive way (as opposed to non-zero real numbers, where the order will always be either preserved exactly or completely reversed). I've seen the arguments against the validity of ordering complex numbers, and I don't find them very persuasive. That said, even if complex numbers aren't ordinal, they _can_ be assigned a canonical ordinal form. Perhaps a better name for the role might be something along the lines of "Sortable"... And yes, there _are_ cases where assigning a canonical ordering to a type is counterintuitive at best. So, while it could make sense to have an Ordinal role, which types individually can .does(), and only those have <, >, <=, >=, <=>, min, max, sort, etc, there is the question about how to h
Re: generic ordinal-relevant operators
At 10:30 PM -0800 11/11/06, Jonathan Lang wrote: Note that this is two competing suggestions: one where '==' means 'generic equivalence', '+==' means 'numeric equivalence', and '*==' means 'string equivalence'; and another where '*==' means 'generic equivalence', '==' means 'numeric equivalence', and 'eq' means 'string equivalence' (with '<', '>', etc. following suit). The goal of the second proposal is to leave existing operator names unchangÄed, while the goal of the first proposal is to provide a consistent and intuitive naming convention. For the record, my preference is to have the generics be the shortest, [==,!==,<=>,<,>,<=,>=], and use [+,~] prefixes for Num or Str casting versions. And lengthen the bit-shift operators to use thin-tailed arrowheads as you suggested. If this practice is followed, then we get these benefits: 1. Better self-documenting of code. 2. Better visual consistency of comparison operators - easier to learn. 3. Fewer base operators and/or fewer alternate shorthands - simplicity. 4. Eliminate the alphabet soup and related ugliness. 5. Better huffman coding because most people will want to sort their values by their native types; people normally want to sort Str as Str and Num as Num, and plain == etc will do that. I don't see any use of weak types as reducing the benefits either. 6. In my mind, bit shifting is a less commonly coded activity, so making those ops a bit longer shouldn't hurt anything. -- Darren Duncan