lpython icon indicating copy to clipboard operation
lpython copied to clipboard

Shallow copying should work differently with Lpython and Lfortran

Open faze-geek opened this issue 2 years ago • 3 comments

I tried the following python snippet for ( Cpython vs Lpython ) and then it's fortran equivalent for ( Gfortran vs Lfortran )

def g():
    l = [1, 2, 3]
    l2 = l
    l[0] = 4
    print(l2)

g()

Here in my opinion l2 should be modified when l is modified as they point to the same memory address.

(lp) faze-geek@DESKTOP-497JDCU:~/lpython/lpython$ python try.py
[4, 2, 3]
(lp) faze-geek@DESKTOP-497JDCU:~/lpython/lpython$ ./src/bin/lpython try.py
[1, 2, 3]       

Now the equivalent fortran example -

program equivalent
  implicit none
  integer :: l(3), l2(3)
  l = [1, 2, 3]
  l2 = l
  l(1) = 4
  print *, l2
end program equivalent

Here l2 doesn't get modified in both the compilers which makes me question if Lpython handles shallow copying through = operator (or maybe the python copy() function) similarly.

(lf) faze-geek@DESKTOP-497JDCU:~/lfortran/lfortran$ gfortran try.f90  && ./a.out
           1           2           3
(lf) faze-geek@DESKTOP-497JDCU:~/lfortran/lfortran$ ./src/bin/lfortran try.f90
1
2
3

faze-geek avatar Apr 24 '23 17:04 faze-geek

@certik Is this issue valid or is the output expected. I had also mentioned this as a potential issue in my GSOC proposal, but did not expect both fortran compilers to give 1 2 3.

faze-geek avatar Apr 24 '23 17:04 faze-geek

Related: https://github.com/lcompilers/lpython/issues/191, https://github.com/lcompilers/lpython/issues/1263.

I know we discussed this exact issue somewhere, but I can't find it. Essentially:

    l = [1, 2, 3]
    l2 = l
    l[0] = 4
    print(l2)
    print(l)

Cannot be allowed, because it behaves differently in LPython and CPython. This can be allowed:

    l = [1, 2, 3]
    l2 = l
    l[0] = 4
    print(l2)

The frontend would need to rewrite it as:

    l2 = [1, 2, 3]
    l2[0] = 4
    print(l2)

But until then I would not allow it. If you do l2 = l, then you cannot use "l" in any way, since the LPython semantics (copy on assignment, no reference counting) is different. So the compiler must give a compile time error message if you use "l" after it was assigned somewhere.

That will fix this issue.

certik avatar Apr 24 '23 23:04 certik

We can also introduce reference counted pointer (RCP) into ASR, and possibly use that. For speed reasons, most likely one would do it explicitly, something like l2 = rcp(l1). Also the question becomes what type l2 will be, possibly l2: RCP[list] = rcp(l1), etc. I would tackle that later.

certik avatar Jul 19 '24 14:07 certik