Skip to content

Commit

Permalink
Fix up is vs == to match Python3 semantics
Browse files Browse the repository at this point in the history
The python3 compiler does constant folding so that when it sees the
same constant in source code. This confused me when I was doing some
simple tests with the REPL where

	>>> (1,2) is (1,2)
	True

but

	>>> a = (1,2)
	>>> b = (1,2)
	>>> a is b
	False

Stick the latter in a file and it *also* gets True as the compiler
does whole-file constant folding.

So, here's my understanding of 'is' vs '==':

is:

 Tuples and lists: object comparison, not contents
 Strings: content comparisons

==

 Content comparisons, using == on each element of the list/tuple, so
 it recurses down the data structure.

I've fixed the test to force Python3 to generate unique tuples even
when compiled from a single file so that the results match snek, which
doesn't manage to share tuples.

Signed-off-by: Keith Packard <keithp@keithp.com>
  • Loading branch information
keith-packard committed Feb 7, 2019
1 parent 6de3d64 commit c03d6bb
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 20 deletions.
6 changes: 2 additions & 4 deletions snek-list.c
Expand Up @@ -145,18 +145,16 @@ snek_list_get(snek_list_t *list, snek_soffset_t o, bool report_error)
}

bool
snek_list_equal(snek_list_t *a, snek_list_t *b, bool is)
snek_list_equal(snek_list_t *a, snek_list_t *b)
{
if (snek_list_readonly(a) != snek_list_readonly(b))
return false;
if (is && !snek_list_readonly(a))
return false;
if (a->size != b->size)
return false;
snek_poly_t *adata = snek_pool_ref(a->data);
snek_poly_t *bdata = snek_pool_ref(b->data);
for (snek_offset_t o = 0; o < a->size; o++)
if (!snek_poly_equal(adata[o], bdata[o], is))
if (!snek_poly_equal(adata[o], bdata[o], false))
return false;
return true;
}
Expand Down
7 changes: 5 additions & 2 deletions snek-poly.c
Expand Up @@ -68,10 +68,13 @@ snek_poly_equal(snek_poly_t a, snek_poly_t b, bool is)
case snek_string:
return !strcmp(snek_poly_to_string(a), snek_poly_to_string(b));
case snek_list:
return snek_list_equal(snek_poly_to_list(a), snek_poly_to_list(b), is);
if (!is)
return snek_list_equal(snek_poly_to_list(a), snek_poly_to_list(b));
break;
default:
return false;
break;
}
return false;
}

bool
Expand Down
2 changes: 1 addition & 1 deletion snek.h
Expand Up @@ -530,7 +530,7 @@ snek_poly_t
snek_list_get(snek_list_t *list, snek_soffset_t i, bool report_error);

bool
snek_list_equal(snek_list_t *a, snek_list_t *b, bool is);
snek_list_equal(snek_list_t *a, snek_list_t *b);

snek_poly_t
snek_list_imm(snek_offset_t size, bool readonly);
Expand Down
47 changes: 34 additions & 13 deletions test/equal_is.py
Expand Up @@ -12,21 +12,42 @@
# General Public License for more details.
#

# == tests elements of both lists and tuples
if not ([1,2] == [1,2]): exit (1)
if not ((1,2) == (1,2)): exit (1)
# Foil the python3 compiler into creating separate tuples
def twople(a,b):
return (a,b)

if not ([[1,2],[3,4]] == [[1,2],[3,4]]): exit (1)
if not (((1,2),(3,4)) == ((1,2),(3,4))): exit (1)
al = [1,2]
adl = [[1,2],[3,4]]
bl = [1,2]
bdl = [[1,2],[3,4]]
at = twople(1,2)
adt = (twople(1,2),twople(3,4))
bt = twople(1,2)
bdt = (twople(1,2),twople(3,4))
astr = "hello"
bstr = "hello"

# is tests elements of tuples but only container of lists
if ([1,2] is [1,2]): exit (1)
if not ((1,2) is (1,2)): exit (1)
def fail(which):
print("fail %s" % which)
exit(1)

if ([[1,2],[3,4]] is [[1,2],[3,4]]): exit (1)
if not (((1,2),(3,4)) is ((1,2),(3,4))): exit (1)
# == tests elements of lists and tuples and strings
if not (al == bl): fail("al == bl")
if not (adl == bdl): fail("adl == bdl")
if not (at == bt): fail("at == bt")
if not (adt == bdt): fail("adt == bdt")
if not (astr == bstr): fail("astr == bstr")

# in tests using == not is
# is tests for same lists/tuples, but matching string contents
if (al is bl): fail("al is bl")
if (adl is bdl): fail("adl is bdl")
if (at is bt): fail("at is bt")
if (adt is bdt): fail("adt is bdt")
if not (astr is bstr): fail("astr is bstr")

if not ([1,2] in [[1,2],[3,4]]): exit(1)
if not ((1,2) in ((1,2),(3,4))): exit(1)
# in uses ==, not is

if not (al in adl): exit (1)
if not (bl in bdl): exit (1)
if not (at in adt): exit (1)
if not (bt in bdt): exit (1)

0 comments on commit c03d6bb

Please sign in to comment.