Equalizer
From Erights
Kevin Reid (Talk | contribs) (fix arities) |
m (various renamings, extra links) |
||
(2 intermediate revisions not shown) | |||
Line 1: | Line 1: | ||
- | The | + | The [[Equalizer]] implements the algorithm for testing [[sameness]]. |
{{XXX}} explain further | {{XXX}} explain further | ||
+ | |||
+ | An Equalizer is present in the [[universal environment]]. | ||
+ | |||
+ | ? __equalizer | ||
+ | # value: <equalizer> | ||
== Protocol == | == Protocol == | ||
+ | |||
+ | ? def unresolved := [[Object Ref#promise/0|Ref.promise]]()[0] | ||
+ | # value: <Promise> | ||
{{instance msgdoc|sameEver|2|<var>a</var>, <var>b</var>|[[Boolean]]}} | {{instance msgdoc|sameEver|2|<var>a</var>, <var>b</var>|[[Boolean]]}} | ||
- | { | + | {| |
+ | ! When optSame returns !! sameEver | ||
+ | |- | ||
+ | | [[false]] || returns false | ||
+ | |- | ||
+ | | [[true]] || returns true | ||
+ | |- | ||
+ | | [[null]] || [[throw]]s [[NotSettledException]] | ||
+ | |} | ||
+ | |||
+ | (XXX don't use sugar?) | ||
+ | |||
+ | ? 1 == 1 | ||
+ | # value: true | ||
+ | |||
+ | ? 1 == 2 | ||
+ | # value: false | ||
+ | |||
+ | ? 1 == unresolved | ||
+ | # problem: <insufficientlySettledException: not sufficiently settled: 1 == <Promise>> | ||
+ | |||
+ | ? def _ {} == unresolved | ||
+ | # problem: <insufficientlySettledException: not sufficiently settled: <_> == <Promise>> | ||
{{instance msgdoc|sameYet|2|<var>a</var>, <var>b</var>|[[Boolean]]}} | {{instance msgdoc|sameYet|2|<var>a</var>, <var>b</var>|[[Boolean]]}} | ||
- | { | + | {| |
+ | ! When optSame returns !! sameYet | ||
+ | |- | ||
+ | | [[false]] || returns false | ||
+ | |- | ||
+ | | [[true]] || returns true | ||
+ | |- | ||
+ | | [[null]] || returns false | ||
+ | |} | ||
+ | |||
+ | ? __equalizer.sameYet(1, 1) | ||
+ | # value: true | ||
+ | |||
+ | ? __equalizer.sameYet(1, 2) | ||
+ | # value: false | ||
+ | |||
+ | ? __equalizer.sameYet(1, unresolved) | ||
+ | # value: false | ||
{{instance msgdoc|optSame|2|<var>a</var>, <var>b</var>|nullOk<nowiki>[</nowiki>[[Boolean]]]}} | {{instance msgdoc|optSame|2|<var>a</var>, <var>b</var>|nullOk<nowiki>[</nowiki>[[Boolean]]]}} | ||
- | {{XXX}} write documentation | + | {{XXX}} write documentation |
{{instance msgdoc|isSettled|1|<var>a</var>|[[Boolean]]}} | {{instance msgdoc|isSettled|1|<var>a</var>|[[Boolean]]}} | ||
- | {{XXX}} This is a proposed change, implemented in [[E-on-CL]]: that the isSettled operation be moved from [[Ref | + | {{XXX}} This is a proposed change, implemented in [[E-on-CL]]: that the isSettled operation be moved from [[Object Ref]] to Equalizer, since the definition of settledness is tightly related to the definition of sameness. |
{{XXX}} write tests | {{XXX}} write tests | ||
Line 27: | Line 74: | ||
{{XXX}} See comment and rationale on isSettled. | {{XXX}} See comment and rationale on isSettled. | ||
- | {{ | + | ==Tests== |
+ | |||
+ | {{XXX}} Discuss whether these tests should be placed on this page or on [[Sameness]], and whether these tests should be broken up by method documentation sections or all together like this. | ||
+ | |||
+ | {{XXX}} review whether these tests have good coverage (they were compiled by TDD in [[E-on-CL]]). | ||
+ | |||
+ | Just defining some objects to use later: | ||
+ | |||
+ | ? [[DefineExpr|def]] makeCoercedSlot := <elib:slot.makeCoercedSlot>; [[null]] | ||
+ | |||
+ | # {{XXX}} we should define our semitransparent type here, not rely on CoercedSlot being this incidentally | ||
+ | |||
+ | ? [[ObjectExpr|def]] a {} | ||
+ | # value: <a> | ||
+ | |||
+ | ? [[ObjectExpr|def]] b {} | ||
+ | # value: <b> | ||
+ | |||
+ | ? def semiA1 := makeCoercedSlot(any, 1, null) | ||
+ | > def semiA2 := makeCoercedSlot(any, 1, null) | ||
+ | > def semiB := makeCoercedSlot(any, 2, null) | ||
+ | > def semiU := makeCoercedSlot(any, Ref.promise()[0], null) | ||
+ | >null | ||
+ | |||
+ | ===Algorithm checking=== | ||
+ | |||
+ | Two [[selfish]] objects are different. | ||
+ | |||
+ | ? __equalizer.optSame(a, b) | ||
+ | # value: false | ||
+ | |||
+ | A selfish object is the same as itself. | ||
+ | |||
+ | ? __equalizer.optSame(a, a) | ||
+ | # value: true | ||
+ | |||
+ | An [[atomic selfless]] object is the same as any object with the same value. | ||
+ | |||
+ | ? [1, 1000000000000000000001 - 1000000000000000000000] | ||
+ | # value: [1, 1] | ||
+ | |||
+ | ? __equalizer.optSame(1, 1.0) | ||
+ | # value: false | ||
+ | |||
+ | ? __equalizer.optSame(1, 1000000000000000000001 - 1000000000000000000000) | ||
+ | # value: true | ||
+ | |||
+ | A [[transparent selfless]] object is the same as any object with the same [[portrayal]] as from [[Miranda optUncall/1|__optUncall]]. | ||
+ | |||
+ | ? __equalizer.optSame([1], [1]) | ||
+ | # value: true | ||
+ | |||
+ | ? __equalizer.optSame([1], [2]) | ||
+ | # value: false | ||
+ | |||
+ | An unresolved reference is the same as itself, but not the same or different as anything else. | ||
+ | |||
+ | {{XXX}} fix all updoc impls and eliminate use of [null] gimmick | ||
+ | |||
+ | ? [__equalizer.optSame(1, unresolved)] | ||
+ | # value: [null] | ||
+ | |||
+ | ? [__equalizer.optSame(unresolved, unresolved)] | ||
+ | # value: [true] | ||
+ | |||
+ | ? [__equalizer.optSame([unresolved], [unresolved])] | ||
+ | # value: [true] | ||
+ | |||
+ | ? [__equalizer.optSame(unresolved, Ref.promise()[0])] | ||
+ | # value: [null] | ||
+ | |||
+ | Cyclic Selfless objects are the same as each other provided they have the same structure. | ||
+ | |||
+ | ? [__equalizer.optSame(def circle := [circle], def loop := [loop])] | ||
+ | # value: [true] | ||
+ | |||
+ | ? [__equalizer.optSame(def circle := [1, [1, circle]], def loop := [1, loop])] | ||
+ | # value: [true] | ||
+ | |||
+ | More Selfless (XXX move these?) | ||
+ | |||
+ | ? [__equalizer.optSame('q', 'q')] | ||
+ | # value: [true] | ||
+ | |||
+ | ? [__equalizer.optSame('q', 'w')] | ||
+ | # value: [false] | ||
+ | |||
+ | ? "a" + "bc" | ||
+ | # value: "abc" | ||
+ | |||
+ | ? [__equalizer.optSame("abc", "a" + "bc")] | ||
+ | # value: [true] | ||
+ | |||
+ | A String is a kind of list but it isn't the same as a plain ConstList. | ||
+ | |||
+ | ? [__equalizer.optSame(['a', 'b', 'c'], "a" + "bc")] | ||
+ | # value: [false] | ||
+ | |||
+ | Tests of semitransparency ({{XXX}} document this; currently only actually implemented in general in [[E-on-CL]]; semitransparency is the general case of what [[SturdyRef]], and now [[CoercedSlot]] is): | ||
+ | |||
+ | ? [__equalizer.optSame(semiA1, semiA2)] | ||
+ | # value: [true] | ||
+ | |||
+ | ? [__equalizer.optSame(semiA1, semiB)] | ||
+ | # value: [false] | ||
+ | |||
+ | ? [__equalizer.optSame(semiA1, semiU)] | ||
+ | # value: [null] | ||
+ | |||
+ | This is a test for a former bug in [[E-on-CL]]: the sofar list was sometimes being filled with the right-side reference only (broken sort-by-hash swap), so a cycle on the right would be assumed to be a cycle on the left as well. The test is done with two sets of references because whether the swap occurs depends on the hash-values involved. | ||
+ | |||
+ | ? def l1 := <nowiki>[[[l1]]]</nowiki> | ||
+ | > def c1 := <nowiki>[[[[[['a']]]]]]</nowiki> | ||
+ | > def l2 := <nowiki>[[[l2]]]</nowiki> | ||
+ | > def c2 := <nowiki>[[[[[['b']]]]]]</nowiki> | ||
+ | > [c1 == l1, c1 == l2, c2 == l1, c2 == l2, | ||
+ | > l1 == c1, l1 == c2, l2 == c1, l2 == c2] | ||
+ | # value: [false, false, false, false, false, false, false, false] | ||
+ | |||
+ | ===isSettled=== | ||
+ | |||
+ | ? __equalizer.isSettled(semiA1) | ||
+ | # value: true | ||
+ | |||
+ | ? __equalizer.isSettled(semiU) | ||
+ | # value: false | ||
+ | |||
+ | {{XXX}} there are other isSettled tests from E-on-CL to be moved here | ||
+ | |||
[[Category:ELib specification]] | [[Category:ELib specification]] |
Latest revision as of 00:29, 14 January 2009
The Equalizer implements the algorithm for testing sameness.
XXX explain further
An Equalizer is present in the universal environment.
? __equalizer # value: <equalizer>
Contents |
Protocol
? def unresolved := Ref.promise()[0] # value: <Promise>
sameEver/2
- Signature: sameEver(a, b) :Boolean
When optSame returns | sameEver |
---|---|
false | returns false |
true | returns true |
null | throws NotSettledException |
(XXX don't use sugar?)
? 1 == 1 # value: true ? 1 == 2 # value: false ? 1 == unresolved # problem: <insufficientlySettledException: not sufficiently settled: 1 == <Promise>> ? def _ {} == unresolved # problem: <insufficientlySettledException: not sufficiently settled: <_> == <Promise>>
sameYet/2
- Signature: sameYet(a, b) :Boolean
When optSame returns | sameYet |
---|---|
false | returns false |
true | returns true |
null | returns false |
? __equalizer.sameYet(1, 1) # value: true ? __equalizer.sameYet(1, 2) # value: false ? __equalizer.sameYet(1, unresolved) # value: false
optSame/2
- Signature: optSame(a, b) :nullOk[Boolean]
XXX write documentation
isSettled/1
- Signature: isSettled(a) :Boolean
XXX This is a proposed change, implemented in E-on-CL: that the isSettled operation be moved from Object Ref to Equalizer, since the definition of settledness is tightly related to the definition of sameness.
XXX write tests
makeTraversalKey/1
- Signature: makeTraversalKey(a) :TraversalKey
XXX See comment and rationale on isSettled.
Tests
XXX Discuss whether these tests should be placed on this page or on Sameness, and whether these tests should be broken up by method documentation sections or all together like this.
XXX review whether these tests have good coverage (they were compiled by TDD in E-on-CL).
Just defining some objects to use later:
? def makeCoercedSlot := <elib:slot.makeCoercedSlot>; null # XXX we should define our semitransparent type here, not rely on CoercedSlot being this incidentally ? def a {} # value: <a> ? def b {} # value: <b> ? def semiA1 := makeCoercedSlot(any, 1, null) > def semiA2 := makeCoercedSlot(any, 1, null) > def semiB := makeCoercedSlot(any, 2, null) > def semiU := makeCoercedSlot(any, Ref.promise()[0], null) >null
Algorithm checking
Two selfish objects are different.
? __equalizer.optSame(a, b) # value: false
A selfish object is the same as itself.
? __equalizer.optSame(a, a) # value: true
An atomic selfless object is the same as any object with the same value.
? [1, 1000000000000000000001 - 1000000000000000000000] # value: [1, 1] ? __equalizer.optSame(1, 1.0) # value: false ? __equalizer.optSame(1, 1000000000000000000001 - 1000000000000000000000) # value: true
A transparent selfless object is the same as any object with the same portrayal as from __optUncall.
? __equalizer.optSame([1], [1]) # value: true ? __equalizer.optSame([1], [2]) # value: false
An unresolved reference is the same as itself, but not the same or different as anything else.
XXX fix all updoc impls and eliminate use of [null] gimmick
? [__equalizer.optSame(1, unresolved)] # value: [null] ? [__equalizer.optSame(unresolved, unresolved)] # value: [true] ? [__equalizer.optSame([unresolved], [unresolved])] # value: [true] ? [__equalizer.optSame(unresolved, Ref.promise()[0])] # value: [null]
Cyclic Selfless objects are the same as each other provided they have the same structure.
? [__equalizer.optSame(def circle := [circle], def loop := [loop])] # value: [true] ? [__equalizer.optSame(def circle := [1, [1, circle]], def loop := [1, loop])] # value: [true]
More Selfless (XXX move these?)
? [__equalizer.optSame('q', 'q')] # value: [true] ? [__equalizer.optSame('q', 'w')] # value: [false] ? "a" + "bc" # value: "abc" ? [__equalizer.optSame("abc", "a" + "bc")] # value: [true]
A String is a kind of list but it isn't the same as a plain ConstList.
? [__equalizer.optSame(['a', 'b', 'c'], "a" + "bc")] # value: [false]
Tests of semitransparency (XXX document this; currently only actually implemented in general in E-on-CL; semitransparency is the general case of what SturdyRef, and now CoercedSlot is):
? [__equalizer.optSame(semiA1, semiA2)] # value: [true] ? [__equalizer.optSame(semiA1, semiB)] # value: [false] ? [__equalizer.optSame(semiA1, semiU)] # value: [null]
This is a test for a former bug in E-on-CL: the sofar list was sometimes being filled with the right-side reference only (broken sort-by-hash swap), so a cycle on the right would be assumed to be a cycle on the left as well. The test is done with two sets of references because whether the swap occurs depends on the hash-values involved.
? def l1 := [[[l1]]] > def c1 := [[[[[['a']]]]]] > def l2 := [[[l2]]] > def c2 := [[[[[['b']]]]]] > [c1 == l1, c1 == l2, c2 == l1, c2 == l2, > l1 == c1, l1 == c2, l2 == c1, l2 == c2] # value: [false, false, false, false, false, false, false, false]
isSettled
? __equalizer.isSettled(semiA1) # value: true ? __equalizer.isSettled(semiU) # value: false
XXX there are other isSettled tests from E-on-CL to be moved here