-
Notifications
You must be signed in to change notification settings - Fork 426
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
array of owned class cannot have its domain resized smaller #14362
Comments
This issue is becoming my brainteaser of the week. I've got a simple patch that avoids sticking the Maybe collections of non-nilable like this one should give the appearance of storing non-nilable values, but should actually store nilable and then just assert non-nil at any interface boundaries that return the value back to the user? Bryant, in filing this do you have a different/better solution in mind? |
For this issue where the domain is removing an element, one approach is to have an unsafe nilability-ignoring function such as A better solution would be some variation of #14273 where an annotated "unsafe" block can temporarily treat the object as nilable to do whatever, so long as the end result when closing the block keeps the non-nilable invariant. It's on the user to make sure the invariant holds, so the compiler can continue to make optimizing assumptions. Maybe this is too laborious, but it's certainly easier to debug / blame when you know the full scope of when nilable behaviors can happen to non-nilable types. class MyVector {
type eltType; // where isClass(eltType)
var buffer: /* some non-nilable 0-based array treated as raw memory */;
var size: uint = 0; // current size of this vector.
/* Resize this container to smaller than its current size, otherwise nop. */
proc truncate(newSmallerSize: uint) {
if newSmallerSize < this.size {
AssumeAsNilable(buffer) {
// ^^^^^^^^^^^^^^^^^^^^^^^
if isUnamangedClassType(eltType) {
/* explicitly delete instead of implicitly dropping it */
} else {
buffer[newSmallerSize..(this.size - 1)] = nil;
}
}
this.size = newSmallerSize;
}
}
// The rest of the methods in this container
// don't need to assume any nil objects because
// there aren't any in the buffer up to this.size.
} Somewhat a contrived example, but it shows that this approach allows a user to manually manage an array with all the dangers that come with it (the user manages their own invariants). |
I don't think I understand this description. Is your thought that the owned object would have its ownership transferred and dropped on the floor (de-initing the object), but that the object pointer that is stored in memory would continue to point to the stale object rather than being reassigned to
To me, this feels equivalent to having the collection store the nilable variant of the user-visible type and then to ensure that only non-nilable values are returned at the public interfaces. Specifically, I'm noting that your proposal still uses Your comment, The rest of the methods in this container don't need to assume any nil objects because Do you see any major difference between the two? Note that in the case of the OP (an associative array), the default implementation today is for Chapel to use an open-addressing hash table in which empty ( |
My thought is that, today,
Agreed.
Yeah, I admit it was a contrived example. For low-level data structures with only a single container, it is reasonable to use a nilable container to represent the non-nilable interface. For higher-level data structures where some construction using multiple, dependent arrays is required, this gets trickier. I know this issue is for destruction, but if there's a simpler way to do construction than via an annotated code block, I haven't thought of one. Expecting the user to wrap all their complicated cases into nilable arrays and present a non-nilable interface is likely too much work, especially if after construction, the array is non-nilable for the rest of its (long) life.
This trickiness is why many of Rust's low-level data structures are implemented using Chapel certainly shouldn't go to this extreme conclusion if it doesn't have to, but there's a tradeoff between performance and safety [[1]]. The most type-safe thing to do is to force users to define a default value for their type and do the construction/destruction by creating this default value and swapping it into the effected value. If creating this default value is non-trivial work, there could be a huge performance penalty. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Control ddata initialization via a param [reviewed by @mppf and @dlongnecke-cray] At present, we always know at compile-time whether or not a ddata wants to be initialized or not, so change the flag that indicates this into a param such that the compiler will fold out the initialization code. Failure to do so causes a problem when trying to create a ddata of types that don't have an initial value, like non-nilable classes. Add a test to lock this behavior in based on the case in #14362 (comment) which inspired this fix. In the future, if/when we have a case that needs this not to be a param, we can presumably add a non-param overload and have the list continue to use the param overload as it is today (?).
When I run the example from the top of the issue today, I get:
It's possible to disable that error but we still have problems with the pattern
because the Edit: #15703 also proposes that such a |
A challenge to generalizing this idea is that it'd need to be a varargs routine to take any non-default-initable arrays defined over |
Related #14361, #14273
Bug. Nilability. Resizing to a smaller domain when an associated array is of managed non-nilable class type will attempt to default-assign
nil
to the disappearing elements.The text was updated successfully, but these errors were encountered: