open-papyrus / papyrus-compiler

Open-source compiler for the Papyrus scripting language of Bethesda games.
https://open-papyrus.github.io/docs/papyrus-compiler/Introduction.html
MIT License
25 stars 3 forks source link

Const arrays/improve read only arrays #54

Closed Scrabx3 closed 1 year ago

Scrabx3 commented 1 year ago

Currently, the following papyrus code would be accepted:

; Script A
int[] _arr
int[] Property arr
  int[] Function Get()
    return _arr
  EndFunction
EndProperty

; Script B
Function fun()
  A.arr = new int[3] ; <- This fails because the array is read only
  A.arr[0] = 0              ; <- This however would be accepted
EndFunction

I believe that A.arr[0] here would edit _arr in its first position and set 0 there, since arrays are handled by reference. Wouldn't bet on it, but either way, what's the point of a read-only array if I can still edit its values?

If a caller would want a copy of the requested array to edit from here on out, it should be explicitly stated so.

erri120 commented 1 year ago

Only the property A.arr is “read-only” (it only has a getter) however the backing field is not read-only because there is such thing as read-only variables in Papyrus. This is not unique to Papyrus either:

https://sharplab.io/#v2:C4LgTgrgdgNAJiA1AHwAICYCMBYAUH1AZgAINiBBYgbz2LuIAcwBLANwENgBTYsL9uAHsoAGwCexZlGABtALrEA+uzBhiAXmJQuAd0nT5VAAwxMMdDEIwALDACsAXwDcteq7pF9sheVXV39HQA5lzAGgB8SipgLriBDngJ+LieZABC/nH0qdbEAMqCALahABZSQQAUUmHMAJSZgYEcauwaWroUFbWxjdmYAJwVACQARDJUzA4KmlTsAHS+YDLMcg4j3QGB84vL08RGPb2kA8NjE1Ntswuqu2sbWXRJSQToJDQPpOjoDUfNxABGbW0ejSXUOvX+cwKxWAZSglUw93iiTwQA==

using System;

public class A {
    private readonly int[] _arr = new int[]{0,1,2,3,4,5};

    public int[] Arr {
        get => _arr;
    }
}

public class B {
    public void Something(int i) {
        var a = new A();
        Console.WriteLine($"[{i}] = {a.Arr[i]}");
        a.Arr[i] = 0;
        Console.WriteLine($"[{i}] = {a.Arr[i]}");
    }
}

public static class Program {
    public static void Main() {
        var b = new B();
        b.Something(1);
    }
}

Output:

[1] = 1
[1] = 0

Arrays by design are just continuous regions in memory, even if read-only variables existed, an index-based assignment would still go through. The only way to avoid this is by not exposing the array at all and creating a function that will return the value at the index instead of the whole array.