-
Notifications
You must be signed in to change notification settings - Fork 424
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
First crack at new List API, intended to replace "array-as-vec" operations on arrays #13030
First crack at new List API, intended to replace "array-as-vec" operations on arrays #13030
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.
I think these are all the API questions/suggestions I have
modules/standard/Lists.chpl
Outdated
|
||
:arg other: A List, the elements of which are appended to this List. | ||
*/ | ||
proc extend(other: List(this._etype)) {} |
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.
You might be able to get away with using that method wrapper here as well. If not, we could try using the generic version of List and having checks in the body of extend
to ensure the appropriate behavior is maintained.
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.
That is true, might that be the more appropriate solution here?
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.
Honestly, I'd want to look at the generated documentation with the method call before making a decision
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.
Working on that, waiting on the filesystem...
modules/standard/Lists.chpl
Outdated
Is not currently parallel safe. | ||
|
||
The following operations may trigger a move: | ||
- insert |
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.
It would be nice to link to the definitions of these functions elsewhere in the documentation.
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 don't know if I would repeat the information in the module documentation, but I think it is appropriate here
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.
To be sure, the module documentation is in no way final at this point, and it contains a lot of the ramblings and musings that I put in the OP. I hope to have it sorted out after we get the API and semantics of List finalized.
But yes, that is a really good reminder, thanks!
modules/standard/Lists.chpl
Outdated
/* | ||
Insert an element at a given position in this List, shifting all elements | ||
following that index one to the right. Note that `a.insert(a.size, x)` | ||
is equivalent to `a.append(x)`. |
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.
Append or extend?
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.
Would be good to link to the functions you are mentioning, both here and later
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.
Good point!
:return: An element from this List. | ||
|
||
:throws IllegalArgumentError: If the given index is out of bounds. | ||
*/ |
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.
Have we documented this/these/writeThis functions in other places?
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.
It seems like builtins would be documented in an obvious part of the Chapel Docs (I know we do here https://chapel-lang.org/docs/primers/specialMethods.html, but haven't checked the manual itself).
Additional food for thought: #12411 (comment) Of these options, I'd figure we're best targeting the "most general" List first, but feel free to advocate another option instead. |
|
||
:arg x: The element to remove. | ||
|
||
:throws IllegalArgumentError: If there is no such item. |
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'd probably use a different Error
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.
add a ..note about it invalidating references
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.
The Python API throws a ValueError
, which is consistent with our use of IllegalArgumentError
. Do you have an idea for a different error type?
A Stack could just have a List and offer a restricted set of methods. But I think it's reasonable to proceed with List with parallel-safety warnings on certain operations.
I think
You already have
Sounds good to me.
I don't think we have to decide this right now. |
modules/standard/Lists.chpl
Outdated
well as iterators to List elements produced by tasks before the move | ||
occurred. | ||
*/ | ||
class List { |
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.
It must be a record if you want to overload =
or supply a copy initializer
Should the IE, when I assign L2 to L1, the contents of L1 are now a copy of the elements contained in L2. It seems to me that this would go against the behavior expected by Python users, where lists are assigned by reference and Thoughts? |
Nothing jumps out at me at the moment, either way, but I do have a vague feeling that there might be something in the back of my mind. I'll let you know if anything comes of that :) |
I think it should deep copy, because that's how arrays work in Chapel, and I think we're trying to make something array-like but more flexible (in terms of adding elements etc). |
So it sounds like @bradcray was strongly in favor of making |
I haven't read through all 78 comments to check, but a quick search suggests not: Has anyone asked the question as to whether we'd prefer upper-case vs. lower-case names for these types? ( Lower-case makes it feel a bit more first-class to me and reduces the amount of Shift-Typing required. It would also permit us to call the module (This obviously relates a bit to #6698). |
It seems to me that the type name should be I have no personal preference either way, so I guess this ultimately depends on what is decided on for #6698. |
Other libraries use lowercase, though, don't they? (e.g., C++ STL?). I think there are aspects of libraries that are important and core enough to be as though they are as good as built-in ( |
I think that it ultimately comes down to what the style guide ends up saying about the naming convention for records and classes. I don't envision the As for whether the naming convention for classes and records should be If it's the need for consistency (IE #6698 itself) you are debating, then that's another can of worms. |
The style guide doesn't exist, though, and I don't think we should wait for it to be written. In a sense, we're debating some of the seeds of the style guide here and now... |
If we want to live in a world similar to C++ STL where Maybe I should take a poll? |
I definitely think it's a decision that's bigger than those of us paying attention to this issue, but I didn't mean to imply snake_cast. Rather I was envisioning camelCase. In #6698, I think Michael suggested that a potential deciding point might be that value-based data types could be camelCase and reference-/class-based data types could be PascalCase, and I think that is an intriguing notion that has resonated pretty well with me over the past 12 hours or so. |
Oh. That never (edit, to clarify: the notion of using |
So it seems like most questions/concerns about the
As for the latter, I will proceed with |
We resolved several issues with array-as-vec storing The obvious alternative is to use |
What kind of issues (if you could point me towards a thread) were array-as-vec having that warranted use of the More importantly, why does My worry here is (in addition to not understanding these edge cases that well): what kind of hoops are Chapel users going to have to jump through to write their own containers? Being forced to use a move because nilability checks require you to avoid I'm worried about heading into a world where a user has to use It might be that these are both just temporary workarounds and not intended to be a permanent state of affairs? |
@dlongnecke-cray - we can talk offline about the history of
It does not. It assumes that the LHS and RHS elements are initialized at all. If it does not, when a user writes The overriding concern of the initializers effort is that user code should not have access to un-initialized memory. (With exceptions for certain low-level things, of course).
Container authors have to choose between:
In practice I suspect that once we get
We should talk more about why this seems scary to you but I don't think it's relevant to the topic of this page (the List API). In particular, I think we can and should document somewhere how a user can achieve a "move" and find a way to express it in some reasonable way. However I don't think that part is necessary for progress on this Lastly, please note that this is not a problem unique to Chapel. C++ allows types that have no default initializer. These can still be stored in a std::vector. A C++ vector manages which elements in the buffer are initialized. |
Sure we can talk about why avoiding I don't really have any API related questions left, now. The rest pertain to the implementation, other than use of the You're calling it |
Thanks for all the help, everyone. I'll be closing this now! |
By parallel safety, is it intended to be a non-blocking data structure or a synchronized one? |
Also is there any intention on supporting reductions of lists like this? I think that a naive optionally-synchronized list is fine so long as you can concurrently reduce multiple instances of them.
This would be desirable for bulk insertion, and faster than non-blocking when a lot of data is being merged. |
This PR is intended to propose (and not implement - not quite yet) an API for a new
List
type, modeled in the spirit of the Pythonlist
. It is being written to address the concerns raised in #9452, and will partially resolve #12411 (the other half being the design of aDeque
type).I know that @mppf in particular has raised the idea of limiting the number of List operations that move elements within the list. Moving list elements is a problem because it invalidates any references to List elements held by tasks that were taken before the move occurred.
There are three general safety issues to worry about in the design of this List type that can affect the API (and implementation):
I will leave this PR open after we resolve the questions raised in #12411, and use it after we decide on the direction of the implementation.
Michael proposed a implementation that would avoid invalidating references on resize and maintain O(1) indexing https://github.com/chapel-lang/chapel/pull/12791/files#r275528150.
While I'm planning on using Vass's implementation used in VectorList #12791 to get myself started, it seems like a good idea to adopt a more performant indexing strategy in the long run.
If anyone else has any implementation questions/ideas/concerns, please feel free (I could use the answers as well!).
One avenue of debate is whether List should provide methods such as:
insert
remove
pop
Even
pop
can be considered to invalidate references in a way (what if the element returned is dropped on the floor?). So if we really wanted to limit the API in the name of safety, we could omit thepop
method too.But...how far will we go with this line of reasoning before a
List
object ceases to be useful at all? I feel personally that if we omit the methodsinsert
andremove
, our List ADT is really nothing more than a glorified stack.Just my two cents. Please critique away!