Opened 9 years ago

Closed 9 years ago

# Function changes behaviour, related to polynomial rings

Reported by: Owned by: Martin von Gagern major sage-duplicate/invalid/wontfix algebra Nils Bruin N/A

### Description (last modified by Martin von Gagern)

I've just observed the following strange behaviour in sage 5.12:

```sage: PR1 = PolynomialRing(QQ, ["t" + str(i) for i in range(10)])
sage: t = PR1.gens()
sage: def L(r, j):
...       return (t[r] - t[r + j])/t[r + j]
...
sage: PR2 = PolynomialRing(PR1.fraction_field(), ["p" + str(i) for i in range(5)])
sage: p = PR2.gens()
sage: def D(r):
...       return sum(L(r, j)*p[r-4+j] for j in range(3))
...
sage: D(4)
((t4 - t5)/t5)*p1 + ((t4 - t6)/t6)*p2
sage: myc = list(D(4))    # here the command works all right
sage: D(4)                # reproducing the call still works fine here
((t4 - t5)/t5)*p1 + ((t4 - t6)/t6)*p2
sage: [c for c, p in myc] # THIS LINE APPEARS TO BREAK THINGS!
[(t4 - t5)/t5, (t4 - t6)/t6]
sage: D(4)                # now the result is wrong, no error reported
0
sage: myc = list(D(4))    # and this throws, probably due to the zero result
Traceback (most recent call last):
...
TypeError: 'sage.rings.fraction_field_element.FractionFieldElement' object is not iterable
```

So it seems that repeated execution of the same function can yield different (and sometimes wrong!) results if some result was iterated over in a certain way. No clue why.

### comment:1 Changed 9 years ago by Martin von Gagern

Description: modified (diff)

### comment:2 follow-up:  3 Changed 9 years ago by Nils Bruin

Milestone: sage-5.13 → sage-duplicate/invalid/wontfix new → needs_review

This is not a problem in Sage, but a documented "feature" of Python2. It was realized to be a wart and fixed in Python3. The problem is indeed the line you mark:

```sage: p
(p0, p1, p2, p3, p4)
sage: [c for c, p in myc] # THIS LINE APPEARS TO BREAK THINGS!
[(t4 - t5)/t5, (t4 - t6)/t6]
sage: p
p2
```

List comprehensions leak their variables, so the value of your global variable p (which gets used in your function `D`) gets overwritten. This problem does not with happen if you write

```sage: list(c for c, p in myc)
```

because iterators do not leak their variables. In Python3, list comprehensions share the same semantics as iterators.

It's a wart, but as long as we stick with Python2 we'll have to live with it. Ways to mitigate the problem:

• Don't rely on a global variable such as p inside a function. Derive parents and their generators from your input variables (meaning: D should probably have `PR2` as one of its parameters).
• Use `list(...)` rather than `[...]` if you don't want to leak variables into scope.

Polynomials are indexable and iterable (for better or for worse), but fraction field elements are not. Thus, you have:

```sage: parent(D(4))
Multivariate Polynomial Ring in p0, p1, p2, p3, p4 over Fraction Field of Multivariate Polynomial Ring in t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 over Rational Field
sage: p=PR2.2 #THIS LINE BREAKS THINGS
sage: parent(D(4))
Fraction Field of Multivariate Polynomial Ring in t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 over Rational Field
```

### comment:3 in reply to:  2 Changed 9 years ago by Martin von Gagern

This is not a problem in Sage, but a documented "feature" of Python2. […] List comprehensions leak their variables, so the value of your global variable p […] gets overwritten.

Thanks for clarifying this.

I seem to have a knack for reporting things in the wrong place: I tend to ask questions on Ask Sage which turn out to be bugs, and now I asked here about what felt like a sure bug, and it turns out to be “a feature” or at least not Sage's bug, so it might have been more appropriate to use that Q&A forum instead.

### comment:4 Changed 9 years ago by Jeroen Demeyer

Reviewers: → Nils Bruin needs_review → positive_review

### comment:5 Changed 9 years ago by Jeroen Demeyer

Resolution: → invalid positive_review → closed
Note: See TracTickets for help on using tickets.