[REBOL] Re: Sameness - a pragmatic approach.
From: joel:neely:fedex at: 12-Feb-2003 6:39
Hi, Ladislav,
Sorry! Didn't mean to ignore it! I distinguish between equality
testing in general and equality over object methods (though they
are certainly functions) because context makes a difference.
Fundamentally we have to "shoehorn" three-valued logic into the
REBOL two-valued LOGIC! type...
Ladislav Mecir wrote:
> BTW, you didn't answer my question about equality of functions.
> (I am not sure my question was understandable.) Have you got
> any opinion?
>
Me? Have opinions? ;-)
Let me bound the answer with two assertions, and then try to
narrow the gap.
1) I would not expect REBOL to determine general functional
equivalence, that e.g.
fun0: func [a [number!]] [a + 2]
and
fun1: func [a [number!]] [2 + a]
are (intended to be) equivalent, much less
fun2: func [a [number!]] [return 1 + a + 1]
or
fun2: func [a [number!]] [1 + a + 3 + a / 2]
2) My original question was in reference to the example of
foo: make object! [a: 1 b: "Hi!"]
baz: make object! [a: 1 b: "Hi!"]
equal? foo baz
where functions were not involved. It seems to me that this
is not significantly harder to solve than
fooblk: ["a" 1 "b" "Hi!"]
bazblk: ["a" 1 "b" "Hi!"]
without functions in the picture.
With "elementary" types, EQUAL? is strictly two-valued: we can
state with total confidence that two values are or are not
equal. Aristotle would have been proud.
There are really three possible answers for EQUAL? over function
values: we know they are equal (probably SAME?), we know they
are not equal (e.g. different argument signatures), or we simply
can't tell (given a specific set of criteria). Of course EQUAL?
must return a boolean value by definition, so we fold the "can't
tell" case into FALSE (properly IMHO).
Let me interrupt myself to assert the view that enhanced
equality testing for objects should be concerned with
correspondance of the attributes and content, without regard
for ordering, so that
altfoo: make object! [a: 1 b: "Hi!" c: false d: 3.14]
would be considered equal to
altbaz: make object! [d: 3.14 a: 1 c: false b: "Hi!"]
because the *sets* of local words can be placed into 1-to-1
correspondance with equal names and values. Now back to our
regularly scheduled program...
So this leaves open a number of possibilities for object equality
testing:
0) Give up unless the two objects are SAME? This is the present
behavior AFAIK.
1) Define equality of objects without trying to analyze inner
functions. This would allow equality testing over objects
that are used as structured data containers, as in the
common REBOL idiom:
make object! decode-cgi system/options/cgi/query-string
or the FOO and BAZ pairs above. Synonymous object attributes
that are set to FUNCTION! values would be compared with EQUAL?
which would still "do the right thing" for such cases as
newfoo: make object! [a: 1 b: "Hi!" say: :print]
newbaz: make object! [a: 1 b: "Hi!" say: :print]
where the words referred to the same external/nonmethod func.
This case would treat normal methods as "don't know" = FALSE .
2) Use a smarter "method-aware" equality test for the specific
case of functions being compared as values of object-local
words: two methods would be considered equal if corresponding
arguments and refinements had the same names and types, their
locals had the same names, and their bodies were the same
except for the appearance of corresponding argument, local,
refinment, and parent-object words, which would have to match
in the obvious way. Thus we would get TRUE for EQUAL? over
foofun: make object! [
a: 1
b: "Hi!"
say: func [n [number!]] [
loop n [
print ["a" a tab "b" b]
]
]
]
and
bazfun: make foo [] ;; OK, I'm lazy... ;-)
because of the following analysis:
foofun type bazfun
---------------------- ----------------------
a: corr. a:
1 equal 1
b: corr. b:
"Hi!" equal "Hi!"
say: corr. say:
func [ equal func [
n corr. n
[number!]] [ loop equal [number!]] [ loop
n corr. n
[ print [ "a" equal [ print [ "a"
a corr. a
tab "b" equal tab "b"
b corr. b
] ] ] ] equal ] ] ] ]
(where I'm crowding as much "equality" as possible into one
line for the sake of brevity).
In all of these alternatives, there will still be "don't know"
cases that become FALSE (i.e. our heuristics can't prove they
are equal) but I see some virtue in pushing the envelope. My
(uninformed) guess is that option (1) wouldn't be very costly
to add, as we already have an equality test for functions:
>> stampa: :print
>> equal? :print :stampa
== true
We certainly don't want to wait for the interpreter to solve
the Halting Problem, however! ;-)
-jn-