Skip to content
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

Merged
merged 1 commit into from
Dec 5, 2024

Conversation

BCSharp
Copy link
Member

@BCSharp BCSharp commented Dec 4, 2024

Generally, the repr string in Python can be evaluated by eval, 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.

Copy link
Contributor

@slozier slozier left a 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)
Copy link
Contributor

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?

Copy link
Member Author

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).

Copy link
Contributor

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.

@BCSharp
Copy link
Member Author

BCSharp commented Dec 5, 2024

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.

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.

@slozier slozier merged commit 84de081 into IronLanguages:main Dec 5, 2024
8 checks passed
@slozier
Copy link
Contributor

slozier commented Dec 5, 2024

I'm assuming Multiply and Add are also on your radar?

@BCSharp
Copy link
Member Author

BCSharp commented Dec 6, 2024

I'm assuming Multiply and Add are also on your radar?

Yes, but for a different reason than support of non-0-bases. I'll open a separate issue about it, for a dedicated discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants