-
Notifications
You must be signed in to change notification settings - Fork 293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement System.Array constructor with base arg #1828
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated to this PR, but noticed a slight asymmetry in FixSlice
where it does ostart < lb
vs ostop < 0
. Don't think it hurts anything but seemed odd.
arr1 = System.Array.CreateInstance(int, (3,), (-1,)) | ||
for i in range(-1, 2): | ||
arr1[i] = i | ||
arr1 = System.Array[int]((-1, 0, 1), base=-1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Negative bases! Should have paid more attention in the previous PR. I assume negative indices are not "from the end" in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume negative indices are not "from the end" in this case?
Yes. Negative bases caught me by surprise too, I discovered them just a few days ago. I always somehow assumed that bases are zero or positive (to support 1-based arrays). Just to be sure, I wrote a test for negative bases and voilà, they work! This got me thinking about how integer indices are treated in .NET and Python. The overview is in the summary table, but here are some background thoughts.
- Python indices are always relative. Non-negative indices are relative from the beginning, negative indices are relative from the end. The fact that indices are always relative is a direct consequence of lack of the concept of a base. Without a base, everything is relative.
- .NET integer indices are always absolute. This is a direct consequence of having a base in the first place. The base determines at which (absolute) index the array actually begins.
- Since
Int32
is an absolute index in .NET, there is a special type to represent a relative index:System.Index
. It is only supported on 1D arrays. IronPython does not support it yet (at least not on arrays). - In IronPython, we want to support both the Python philosophy and the .NET philosophy seamlessly, so the question is: how should integer indices be treated that is consistent with both .NET and Python? Relative or absolute?
- Luckilly, for 0-based arrays the answer is straightforward:
- For non-negative indices, relative == absolute (because absolute == relative + base, and base == 0)
- For negative indices, well, .NET does not support them, since absolute negative indices are always outside of array bounds for base ==0. So IronPython can adopt the Python convention without creating inconsistencies with .NET.
- Now, in case of base != 0, relative != absolute. So which convention to adopt? Since Python does not know of bases, and non-zero bases imply absolute indexing, the indexing in IronPython in such case has to be absolute too, and it will not conflict with Python. However:
- If base > 0, negative indices, if treated as absolute, will always be out-of-bounds. So, for convenience, IronPython treats them as relative, just as in the case of base == 0. In both cases (base == 0 and base > 0), it is an extension to .NET (i.e. Python convention).
- If base < 0, negative indices cannot be interpreted as relative, because they are used to address some elements in the address space between the base and 0. There is no way around it. So there is a conceptual inconsistency between negative indices with a negative base (absolute, dictated by .NET) and negative indices and 0 base (relative, dictated by Python).
- The only freedom of choice IronPython has, is how to treat negative indices for base > 0? The .NET convention would always throw, the Python convention would make those arrays behave as 0-based arrays. I chose the latter as more practical, but whatever the choice, it will not remove the inconsistency from the previous point. In practice (if there is any), I expect to see 1-based arrays more than any other base (e.g. for a 3-element array, indices 1 ,2 ,3 are then the same as -3, -2, -1).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation. Makes sense.
It is odd and it does hurt... >>> from System import *
>>> arr = Array.CreateInstance(Int32, (3,), (2,))
>>> arr[-1:-5:-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: Index was outside the bounds of the array. Thanks for the catch. This one fell through the cracks. I will issue a separate fix PR. |
I'm assuming |
Yes, but for a different reason than support of non-0-bases. I'll open a separate issue about it, for a dedicated discussion. |
Generally, the
repr
string in Python can be evaluated byeval
, providing a round-trip-complete string representation of an object. There are exceptions, like deeply nested or circular structures, or nondescript "object type at memory address".For CLI arrays, representations of 1D arrays are descriptive, while higher dim are not. This PR adds a constructor that is able to handle the representation for 1D arrays with a non-zero base. I'd make the extra parameter keyword-only, but the DLR doesn't support it yet.