-
Notifications
You must be signed in to change notification settings - Fork 195
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
Prevent reassigning and mutating lifted objects #3069
Comments
Prior to this change you where not able to capture any reassignable and mutable instances, this limitation was too restricting Consider the following example where I wanted to have an `onUpdate` `preflight` api that sets a member `onUpdateCallback`. The `onUpdateCallback` should be called in `inflight`. The only way to achieve this is by setting the `onUpdateCallback` on `init`. After this change I should be able to make `onUpdateCallback` reassignable ```ts (wing) bring cloud; class KeyValueStore { bucket: cloud.Bucket; var onUpdateCallback : inflight (str): void; init(store: cloud.Bucket) { this.bucket = store; this.onUpdateCallback = inflight (k: str) => {}; } onUpdate(fn: inflight (str):void){ this.onUpdateCallback = fn; } inflight get(key: str): Json { return this.bucket.getJson(key); } inflight set(key: str, value: Json): void { this.onUpdateCallback(key); this.bucket.putJson(key, value); } } let kv = new KeyValueStore(new cloud.Bucket()); let counter = new cloud.Counter(); kv.onUpdate(inflight (key: str): void => { counter.inc(1, key); }); test "main" { kv.set("k", Json { value: "v" }); kv.get("k"); kv.get("k"); kv.get("k2"); assert(counter.peek("k") == 2); assert(counter.peek("k2") == 1); } ``` ## Leftovers * #3069 ## Checklist - [x] Title matches [Winglang's style guide](https://docs.winglang.io/contributors/pull_requests#how-are-pull-request-titles-formatted) - [x] Description explains motivation and solution - [x] Tests added (always) - [ ] Docs updated (only required for features) - [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing *By submitting this pull request, I confirm that my contribution is made under the terms of the [Monada Contribution License](https://docs.winglang.io/terms-and-policies/contribution-license.html)*.
example 1: Reassignment after a value has been lifted should be a compile time error let var x = 1;
test "increment x" {
x = x + 1;
log("${x}");
} example 2: Performing mutable operations after a value has been lifted should be a compile-time error let arr = MutArray<num>[];
test "push item" {
arr.push(123);
log("${arr.length}");
} example 3: These rules should also apply when operations are applied to members of classes class Person {
var name: str;
pets: MutArray<str>;
init() {
this.name = "Bob";
this.pets = MutArray<str>["whiskers", "fluffy"];
}
inflight changeName() {
this.name = "Alice"; // error
}
inflight addPet(pet: str) {
this.pets.push(pet); // error
}
}
let person = new Person();
test "make changes" {
person.pets.push("fido"); // error
person.name = "Alice"; // error
} |
Hi, This issue hasn't seen activity in 60 days. Therefore, we are marking this issue as stale for now. It will be closed after 7 days. |
Can we implement a mechanism in our type system so that when a mutable type defined in preflight is lifted into inflight, it is converted into its immutable variant? This would capture the idea that when a mutable collection is introduced to inflight, it gets "frozen" according whatever its last state in preflight was. for example: let x = MutArray<str>["hello", "world"];
inflight () => {
let x0 = x.at(0); // "x" is type Array<str> in this context
log(x0);
x.push("!"); // error, since x is Array<str>
}; Inspired by #3174 |
Maybe, if an object has a So now, we can implement shape shifting generically |
Note that inflight reassignment to a preflight variable part of this issue was handled in #3177, so we now have this compiler error:
|
fixes #3069 The type checker will now modify the type of preflight expressions that are being used inflight to a non-mutable version of the same type: `MutArray` -> `Array`, `MutJson` -> `Json`... Note that since we change the type of the expression we don't get descriptive error telling us that we're trying to mutate a lifted mutable object, instead we just get the same error we'd expect if the lifted object was non-mutable to begin with. This isn't ideal but it makes the fix simpler. Let me know what you think... ## Checklist - [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted) - [x] Description explains motivation and solution - [x] Tests added (always) - [x] Docs updated (only required for features) - [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing *By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
Congrats! 🚀 This was released in Wing 0.70.26. |
…tempt (#6303) Fixes #3069 (2nd attempt, instead of #6258) The type checker will now modify the type of preflight expressions that are being used inflight to a non-mutable version of the same type: MutArray -> Array, MutJson -> Json... Note that since we change the type of the expression we don't get descriptive error telling us that we're trying to mutate a lifted mutable object, instead we just get the same error we'd expect if the lifted object was non-mutable to begin with. This isn't ideal but it makes the fix simpler. Let me know what you think... To get this working we needed to do the following changes to how we evaluate the phases of reference expressions: * The phase of phase independent properties inflight will be inflight. This makes sure inflight calls like `preflight_array.copyMut()` will be we evaluated inflight so the side effect of turning the result to immutable won't happen. This is a major change to lifting because inflight calls like `preflight_array.at(0)` will also be executed inflight (no matter what args are passed to the call). * There's a special exception to the above, struct fields: we need to keep them phase independent and not turn them to inflight when accessing them inflight. This is required so we can lift qualify methods called on struct field when those fields are preflight objects. This needs to be addressed in the future, because somehow struct fields being "phase independent" doesn't seem correct. * Index access (`[i]`) phase calculation was wrong and didn't take into account the phase of the index. When the index phase is inflight the expression must be inflight too. When the index phase is independent and the instance is preflight we want to lift the entire expression and not only the instance so it can be correctly lift-qualified. * All this means we don't need the (admittedly beautiful) logic of only turning phase independent method calls to inflight calls when they are passed some inflight state (instance or arg). Now we always treat them as inflight. This cleaned up some code. ## Checklist - [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted) - [x] Description explains motivation and solution - [x] Tests added (always) - [x] Docs updated (only required for features) - [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing *By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
Congrats! 🚀 This was released in Wing 0.72.3. |
Following #3064
It is now possible to capture reassignable/mutable objects
We need to prevent these captured object from being reassigned/modified in inflight
The text was updated successfully, but these errors were encountered: