Created
August 24, 2022 21:43
-
-
Save lydia-duncan/ca4d886b05d950fd8d67e9cc6aedb435 to your computer and use it in GitHub Desktop.
Owned/shared activity notes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------ | |
Helped answer some questions from other team members | |
------ | |
Activity itself: | |
One thing that immediately occurs to me as a source of confusion is if the default management style for variables does not | |
match the default management style for fields. | |
test/classes/delete-free/undecorated-generic/generic-management-field.chpl | |
My instinct is that if this code really was translated to this: | |
```chapel | |
class FieldClass { | |
var x: int; | |
} | |
record storesField { | |
var f: shared FieldClass; | |
} | |
proc main() { | |
var fc1 = new owned FieldClass(3); | |
writeln(fc1); | |
var sf1 = new storesField(fc1); | |
writeln(sf1); | |
} | |
``` | |
Then we will get the error that explicit code generates today: | |
``` | |
generic-management-field.chpl:9: In function 'main': | |
generic-management-field.chpl:13: error: unresolved call 'storesField.init(owned FieldClass)' | |
generic-management-field.chpl:5: note: this candidate did not match: storesField.init(f: shared FieldClass) | |
generic-management-field.chpl:13: note: because actual argument #1 with type 'owned FieldClass' | |
generic-management-field.chpl:6: note: is passed to formal 'in f: shared FieldClass' | |
``` | |
(This is the same error we get if line 24 instead relies on the default management, just for completeness) | |
That's not to say that `shared` on its own is a bad default for fields, just that variable declarations should probably | |
end up with the same default management style as fields if we think it is really important to change the management style | |
for fields from being generic. | |
Alternatively, we could provide initializer overloads that make the translation from owned into shared occur by default, but it | |
might be annoying if a user wants to write their own to now suddenly not be able to support that for their classes. | |
Test of initializer written with default management type: | |
test/classes/delete-free/undecorated-generic/generic-management-field2.chpl | |
Modifying it like this to mock up "shared-as-field-default" gives a warning because we're deprecating the assignment operator | |
between owned and shared: | |
```chapel | |
class FieldClass { | |
var x: int; | |
} | |
record storesField { | |
var f: shared FieldClass; | |
proc init(in field: FieldClass) { | |
f = field; | |
writeln("In the explicit initializer"); | |
} | |
} | |
proc main() { | |
var fc1 = new FieldClass(3); | |
writeln(fc1); | |
var sf1 = new storesField(fc1); | |
writeln(sf1); | |
} | |
``` | |
``` | |
generic-management-field2.chpl:10: In initializer: | |
generic-management-field2.chpl:11: warning: assigning owned class to shared class is deprecated. | |
generic-management-field2.chpl:20: called as storesField.init(field: owned FieldClass) | |
``` | |
I don't think it's wrong to deprecate the assignment in other circumstances, but it seems unfortunate in this one because the | |
user didn't explicit choose to use different management styles for the initializer and the field. To me, that indicates that | |
the generic default for the field is less likely to lead to frustration. | |
> Can anyone show me an example where we are able to take advantage of generic fields | |
They'll certainly result in different patterns if users use the class in different ways. But I'm not seeing anything about | |
them that means we can't use them in a way that's appropriate for each management type. But it's hard to come up with examples | |
on the fly - it seems likely that something that would be useful in an Expression Tree context wouldn't be necessarily as | |
useful in a LinkedList for instance in addition to the shared/owned concerns, but that's not the scope of all problems. It's | |
impossible to prove a negative. | |
Anyways, a couple of the tests I made use the same backbone code but with different management styles. | |
test/classes/delete-free/undecorated-generic/generic-management-field2-unmanaged.chpl | |
test/classes/delete-free/undecorated-generic/generic-management-field2-borrow.chpl | |
And here's a test with all of them in the same one (but it's very much a toy): | |
test/classes/delete-free/undecorated-generic/generic-management-field-multiple.chpl | |
Wrote this code to try and mock up a linked list with a generic field type but using it with shared: | |
```chapel | |
class ListNode { | |
var next: ListNode?; | |
var x: int; | |
proc init(val: int) { | |
next = nil: ListNode?; // RIP | |
x = val; | |
} | |
proc init(node: ListNode, val: int) { | |
next = node; | |
x = val; | |
} | |
proc deinit() { | |
writeln("Cleaning up x=", x); | |
} | |
} | |
class List { | |
var head: ListNode?; | |
proc deinit() { | |
while head != nil { | |
var headTmp = head; | |
head = head.next; | |
headTmp.next = nil; | |
} | |
} | |
} | |
proc main() { | |
var list = new List(new shared ListNode(3)); | |
list.head.next = new shared ListNode(2, new shared ListNode(1)); | |
writeln(list); | |
} | |
``` | |
But encountered this failure: | |
``` | |
linkedListExample.chpl:5: In initializer: | |
linkedListExample.chpl:6: error: cannot default-initialize a variable with generic type | |
linkedListExample.chpl:6: note: '<temporary>' has generic type 'ListNode?' | |
linkedListExample.chpl:6: note: cannot find initialization point to split-init this variable | |
linkedListExample.chpl:6: note: '<temporary>' is used here before it is initialized | |
``` | |
I believe this means that you can't maintain the genericness of the field and give it nil without asking the user to be the | |
one to provide nil. But it doesn't seem like the user can provide it either: | |
```chapel | |
class ListNode { | |
var next: ListNode?; | |
var x: int; | |
proc init(node: ListNode?, val: int) { | |
next = node; | |
x = val; | |
} | |
proc deinit() { | |
writeln("Cleaning up x=", x); | |
} | |
} | |
class List { | |
var head: ListNode?; | |
proc deinit() { | |
while head != nil { | |
var headTmp = head; | |
head = head.next; | |
headTmp.next = nil; | |
} | |
} | |
} | |
proc main() { | |
var list = new List(new shared ListNode(nil: shared ListNode?, 3)); // RIP | |
list.head.next = new shared ListNode(2, new shared ListNode(nil: shared ListNode?, 1)); | |
writeln(list); | |
} | |
``` | |
Here's the failure message: | |
``` | |
linkedListExample.chpl:28: In function 'main': | |
linkedListExample.chpl:29: error: illegal cast from nil to a generic shared type | |
``` | |
I was able to get a version working that explicitly had shared as the type for the field, but it did require adding a few `?`s | |
to the user declarations I was passing in, which was a bit annoying. It lives here: | |
test/classes/delete-free/shared/linkedListExample.chpl | |
Tests are checked in on this branch: | |
https://github.com/chapel-lang/chapel/compare/main...lydia-duncan:hackathonExperiment?expand=1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment