From 8bdf70abf0876256a832dab7dd1a74b20d0c1bbb Mon Sep 17 00:00:00 2001 From: law Date: Tue, 18 Apr 2023 17:28:51 +0300 Subject: [PATCH 01/13] add partial_types --- text/0000-partial_types.md | 660 +++++++++++++++++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100644 text/0000-partial_types.md diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md new file mode 100644 index 00000000000..4339445a55e --- /dev/null +++ b/text/0000-partial_types.md @@ -0,0 +1,660 @@ +- Feature Name: `partial_types` +- Start Date: 2023-04-18 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + + +# Summary +[summary]: #summary + +Partial types proposal is a generalization on "partial borrowing"-like proposals (more correct name is "partial not borrowing" or "qualified borrowing" since Rust allows partial borrowing already). + +This proposal is a roadmap "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. + +Partial Types is a **minimal** and full extension to the Rust Type System, which allows to safe control easily partial parameters and all kinds of partial not consumption. + +Advantages: maximum type safety, maximum type control guarantee, no ambiguities, flexibility, usability and universality. + + +# Motivation +[motivation]: #motivation + +Safe, Flexible controllable partial parameters for functions and partial not consumption (including partial not borrowing) are highly needed and this feature unlock huge amount of possibilities. + +Partial borrowing is already possible in Rust, as partial referencing and partial moves. + +But partial parameters are forbidden now, as qualified consumption: partial not borrowing, partial not referencing, partial not moving and partial initializing. + + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +_**Note**: I didn't comment type explanations (as is needed for compiler) for colorizing purposes only._ + +_**Note**: I use symbol `~` in code as a synonym of "equivalent" word only. It is not a Rust operator!_ + + +## Partial types by type Integrity + +```rust +// case (A1) +let foo : i16 = 0; +``` + +What is a **full type** of `foo`? Is it the `i16`? No, the `i16` is a sub-full_type in Rust type-system. +```rust +// case (A2) + : ; + : ; + : <'lifetime> ; +``` + +If we explicitly write **full type** (using _unused_ Rust names) we get: +```rust +// case (A3) +// FROM case (A1) +foo : value 'static const i16; +``` + +That mean, that variable `foo` has the `i16` (sub-)type with next type-clarification: `const`(not `mut`) mutability, `value`(not `&`) sharing and `'static` lifetime. + +I propose to extend type system by adding type integrity to clarification sub-type. So, our variable will have next full type: +```rust +// case (A4) + : <'lifetime> <%integrity> ; + +// case (A5) +// FROM case (A1) +foo : value 'b const %a i16; +foo : value 'static const %full i16; +foo : %full i16; +foo : i16; +``` + +Lifetime variants are `'static` (for static lifetime), `'_`(don't care lifetime) and any other `'b`(some "b" lifetime). + +By the same analogy, integrity has similar names and meanings: `%full`(full integrity, soft keyword), `%_`(don't care how partial integrity is, soft keyword), `%empty` or `%!` (no integrity, soft keyword) and any other `%a`(some "a" integrity). + +Symbol `%` percent mean percent or part of the whole thing (variable in our case). + +_Note_: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type integrity. + + +## Traits with Integrity variants + +We could already write Traits with **safe** virtual functions, that consumes virtual partial types having only variants of type integrity in Trait declaration +```rust +// case (B1) +pub trait Upd { + type UpdType; + + fn summarize<%a>(&self: & %a Self) -> String; + + fn update_value<%a>(&mut self : &mut %a Self, newvalue: UpdType); + + fn update_sametype<%a, %b>(&mut self : &mut %a Self, &another: & %b Self); +} +``` + +Unfortunately, having variants of type integrity is not enough to write **safe** implementations or other non-virtual function declarations. + + +## Detailed Integrity + +We need detailed integrity to write non-virtual specific typed parameters in function, including trait implementation. + +An abstractions is added for integrity detailing, we assume that **every** variable is a `struct`-like objects (even if it is not). + +We need for this some new quasi-fields and some field integrity (which should be soft keywords). + +_Note_: I do not comment types (as is needed for compiler) for colorizing purposes. + +_Note_: I use symbol `~` as synonym of "equivalent" word only. It is not a Rust operator. +```rust +// case (C1) +let foo = 0i16; + foo : i16 ~ %full i16; + foo : %full i16 ~ %{self.*} i16; + foo : %{self.*} i16 ~ %{self.self} i16; +``` + +Where : + - `self` is an "access" to variable itself + - `.*` is an "every field" quasi-field + - `.self` quasi-field for primitive types, since `i16` is not a `struct` type + +What's about structures? Almost the same: +```rust +struct Point { + x: f64, + y: f64, + z: f64, + t: f64, + w: f64, +} + +// case (C2) +let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + p1 : &mut Point ~ &mut %full Point; + p1 : &mut %{self.*} Point; + p1 : &mut %{self.x, self.y, self.z, self.t, self.w} Point; + p1 : &mut %{self.{x, y, z, w}} Point; +``` + +Where : + - `.{, , }` is an field-set quasi-field + +We assume, that each field could be in one of 2 specific field-integrity - `%fit` and `%deny`. + +We also must reserve as a keyword a `%miss` field-integrity for future Reintegrated Partial Types, which allows to create **safe** self-referential types. + +`%fit` is default field-integrity and it means we nave an access to this field and could use it as we wish. But if we try to access `%deny` field it cause a compiler error. + +```rust +// case (C3) +let foo = 0i16; + foo : %{self.*} i16 ~ %{self.self} i16; + foo : %{%fit self.*} i16 ~ %{%fit self.self} i16; + foo : %{%fit self.*, %deny self._} i16; + + +// case (C4) +// FROM case (C2) +let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + p1 : &mut %{%fit self.*} Point ~ &mut %{%fit self.*, %deny self._}; + p1 : &mut %{%fit self.{x, y, z, w}} Point; +``` + +Where : + - `%fit` integrity + - `%deny` integrity + - `._` is a "rest of fields" quasi-field + +As we see, + - `%empty : %{%deny self.*}` or `%empty : %{}` integrity + - `%full : %{%fit self.*}` or `%full : %{self.*}` integrity + + +## Partial parameters + +We add enough integrity, and could write partial parameters for non-virtual function declarations: +```rust +// case (D1) +fn re_ref_t (& p : & %{self.t, %ignore self._} Point) -> &f64 { + &p.t +} + +// case (D2) +fn refmut_w (&mut p : &mut %{self.w, %ignore self._} Point) -> &mut f64 { + &mut p.w +} +``` + +Where : + - `%ignore` is a "don't care which exactly" quasi filed-integrity (`%_` is a whole type integrity and it is unclear if we could use it in both contents) + +But `%ignore self._` quasi-filed-integrity of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore self._`. + +```rust +// case (D3) +// FROM case (D1) +fn re_ref_t (& p : & %{self.t, %any} Point) -> &f64 { + &p.t +} + +// case (D4) +// FROM case (D2) +fn refmut_w (&mut p : &mut %{self.w, %any} Point) -> &mut f64 { + &mut p.w +} + +// case (D5) +struct PointExtra { + x: f64, + y: f64, + saved_x: f64, + saved_y: f64, +} + +fn x_store(&mut p1 : &mut %{self.saved_x, %any} PointExtra, & p2 : &mut %{self.x, %any} PointExtra) { + *p1.saved_x = *p2.x +} + +fn x_restore(&mut p1 : &mut %{self.x, %any} PointExtra, & p2 : &mut %{self.saved_x, %any} PointExtra) { + *p1.x = *p2.saved_x; +} +``` + +or use `where` clause if integrity is extra verbose: +```rust +// case (D6) +// FROM case (D5) + +fn x_store(&mut p1 : &mut %fit_sv_x PointExtra, & p2 : &mut %fit_x PointExtra) + where %fit_sv_x : %{self.saved_x, %any}, + %fit_x : %{self.x, %any} +{ + *p1.saved_x = *p2.x +} + +fn x_restore(&mut p1 : &mut %fit_x PointExtra, & p2 : &mut %fit_sv_x PointExtra) + where %fit_sv_x : %{self.saved_x, %any}, + %fit_x : %{self.x, %any} +{ + *p1.x = *p2.saved_x; +} +``` + +Implementation parameters are mostly same: +```rust +// case (D7) +impl Point { + pub fn x_refmut(&mut self : &mut %{self.x, %any} Self) -> &mut f64 { + &mut self.x + } + + pub fn y_refmut(&mut self : &mut %{self.y, %any} Self) -> &mut f64 { + &mut self.y + } +} +``` + +We could also use multiple sub-parameters of same parameter +```rust +// case (D8) + pub fn xy_swich(&mut self : &mut %{self.{x, y}, %any} Self) { + let tmp = *self.x; + *self.x = *self.y; + *self.y = tmp; + } +``` + +Now type integrity guarantee to compiler, that only some fields has an access inside function, but not the rest of them. +So, no extra lock on `self` is needed, only for `%fit` fields. + +Now compiler can catch "out of scope parameter" errors +```rust +// case (D9) + pub fn xt_refmut(&self : &mut %{self.xt, %any} Self) -> &mut f64 { + // ^~~~~~ + // error: no field 'self.xt' on type `self` + &mut self.xt + } +``` + +Since using `%ignore` filed is **unsafe**, trying to use ignoring field is a compile error: +```rust +// case (D10) + pub fn t_refmut(&self : &mut %{self.t, %any} Self) -> &mut f64 { + &mut self.x + // ^~~~~~ + // error: cannot find value 'self.x' in this scope + } +``` + +Compile could catch more dead code warnings +```rust +// case (D11) + pub fn x_refmut(&self : &mut %{self.x, self.y, %any} Self) -> &mut f64 { + // ^~~~~~ + // warning: '#[warn(dead_code)]' field is never read: `self.y` + &mut self.x + } +``` + +## Several selfs + +If we want to include `x_store` and `x_restore` from case (D5) for implementation we find something weird: we need **several** selfs! + +Sure, they must be a keywords. It could be either `self1, self2, ..` or `self-1, self-2, ..` or `self#1, self#2` or `self_ref, self_refmut` or any other. + +```rust +// case (E1) +trait St { + + fn x_store<%a, %b>(&mut self1: &mut %a Self, &self2: & %b Self); + + fn x_restore<%a, %b>(&mut self1: &mut %a Self, &self2: & %b Self); +} + +// case (E2) + pub fn x_store(&mut self1 : &mut %{self.x, %any} Self, &self2 : & %{self.saved_x, %any} Self) + { + *self1.saved_x = *self2.x + } + + pub fn x_restore(&mut self1 : &mut %{self.saved_x, %any} Self, &self2 : & %{self.x, %any} Self) { + *self1.x = *self2.saved_x; + } +``` + +Sure, if we use several `self`s, their fit fileds integrity cannot overlap! + +```rust +// case (E3) + pub fn x2_store(&mut self1 : &mut %{self.x, %any} Self, &self2 : & %{self.x, %any} Self) { + // ^~~~~~ ^~~~~ + // error: cannot overlap fit-field 'self.x' on self1 and self2 + *self1.x = *self2.x; + } +``` + +Fortunately, these additions is enough to write **any safe** function declarations. + + +## Partial not consumption + +We wrote function declaration. Could we already partially not consume variables in arguments? + +Fortunately, we could qualified consume implicit `self` arguments. + +Unfortunately, implicit `self` argument is the only qualified consumed argument. + +Exists 5 "pseudo-function" consumption for variables in expressions: + - `&mut` - (mutable-)borrowing consumption + - `&` - referential (immutable borrowing) consumption + - `<_nothing>` - move consumption + - `` initialized consumption + - `.` access to the filed + +Partial access to the field is already granted (exept arrays). + +Rust consumer use same names for action and for type clarifications, so we follow this style. + +We need to add integrity filter to them, ignoring it mean `%full` filter (Ok, it is a bit unclear which is a default filter - `%full` or `%max`)! + +`%full` means consumer consume all fields. + +```rust +struct A { f1: String, f2: String, f3: String } +let mut x: A; + +// case (F1) +let a: &mut String = &mut x.f1; // x.f1 borrowed mutably +let b: &String = &x.f2; // x.f2 borrowed immutably +let c: &String = &x.f2; +// error:Can borrow again +let d: String = x.f3; // Move out of x.f3 + +// case (F2) +// FROM case (F1) +let a: &mut String = &mut %full x.f1; +let b: &String = & %full x.f2; +let d: String = %full x.f3; +``` + +Trying to consume `%deny` field is a compile error! The consumer DO NOT consume `%deny` EVER. + +Resulted field integrity is the following: + +| ↓filter / →integrity | `%fit` | `%deny` | `%hidden` | +|----------------------|---------|-----------|-----------| +| `%fit` | `%fit` | !ERROR | !ERROR | +| `%deny` | `%deny` | `%deny` | !ERROR | +| `%hidden` | !ERROR | !ERROR | `%hidden` | + +```rust +struct S5 { f1: String, f2: String, f3: String, f4: String, f5: String } +let mut x: S5; + +// case (F3) +let ref1: &mut String = &mut x.f1; +// +let ref_x23 = & %{self.f2, self.f3, %deny self._} x; + // + ref_x23 : & %{%fit self.{f2, f3}, %deny self.{f1, f4, f5}} S5; + // +let move_x45 = %{self.{f4, f5}, %cut} x; + // + move_x45 : %{%fit self.{f4, f5}, %deny self.{f1, f2, f3}} S5; +``` + +But `%deny self._` quasi-filed-integrity of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny self._`. + +What to do if we wish to create a reference to `ref_x23`. Do we need to write explicitly an integrity or exists implicit way? + +No, we could use `%max`(or `%id`) - qualified safe filter with maximum fit-fields, but technically is an `id` filter to variable integrity: + +| var integrity | `%max` | +|-----------------|----------| +| `%fit` | `%fit` | +| `%deny` | `%deny` | +| `%hidden` | `%hidden`| + +Having this we could write next implicitly +```rust +// FROM case (F1) + ref_x23: & %{%fit self.{f2, f3}, %deny self.{f1, f4, f5}} S5; + +// case (F4) +let refref_x23 = & %max ref_x23; +// + refref_x23: && %{%fit self.{f2, f3}, %deny self.{f1, f4, f5}} S5; +``` + +For function argument we add another filter `%min` - qualified safe filter with minimum fit-fields, but it refers not to variable integrity, but to parameter integrity, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! + +| param integrity | `%min` | +|------------------|----------| +| `%fit` | `%fit` | +| `%deny` | `%deny` | +| `%ignore` | `%deny` | +| `%hidden` | `%hidden`| + +Implementations always consumes `self` by `%min` filter! + +```rust +// FROM case (D3) +fn re_ref_t (& p : & %{self.t, %any} Point) -> &f64 { + &p.t +} +let mut p1 : mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + +// case (F5) +let reft = re_ref_t(& %min p1); + + +// case (F6) + fn update_sametype<%a, %b>(&mut self : &mut %a Self, & another: & %b Self); +// +p1.update_sametype(& %min p2); + + +// case (F7) + fn update_another<%a, %b>(& self : & %a Self, & mut another: & %b Self); +p3.update_sametype(&mut %min p2); +``` + + +## Partially Initialized Variables + +We must have an ability to create partially initilized variables. So we need to add a filter-integrity to a constructor + +```rust +struct Point { + x: f64, + y: f64, + z: f64, + t: f64, + w: f64, +} + +// case (G1) +let p1_full = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + // + p1_full : Point ~ %full Point; + +// case (G2) +let p_x = %{self.x, %cut} Point {x:1.0}; + // + p_x : %{%fit self.x, %deny self._} Point; + // + +let p_yz = %{self.{y,z}, %cut} Point {y:1.0, z: 2.0}; + // + p_yz : %{%fit self.{y,z}, %deny self._} Point; + // +``` + +Also it could be nice if constructor allows several filler variables (which do not overlap fit-fields) +```rust +// case (G3) +let p_xyz = %max Point {..p_x, ..p_yz}; + // + p_xyz : %{%fit self.{x,y,z}, %deny self.{t,w}}; + +// case (G4) +let p2_full = Point {t:1.0, w:2.0, ..p_xyz}; + // + p1_full : Point ~ %full Point; + // +``` + +A bit unclear how to fill unused fields, so we write unused values to a fill the type for tuple constructor + +```rust +// case (G5) +let t4_02 = %{self.{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); + // + t4_02 : %{%fit self.{0,2}, %deny self.{1,3}} (&str, i32, &u16, f32); +``` + +## Private fields + +And finally, what to do with private fields? + +If variable has private field, it is an always `%hidden self.private` quasi-field. +```rust +pub struct HiddenPoint { + pub x: f64, + pub y: f64, + z: f64, + t: f64, + w: f64, +} + +// case (H1) +let p1 : HiddenPoint; + p1 : %full HiddenPoint; + p1 : %{%fit self.pub, %private} HiddenPoint; + p1 : %{%fit self.{x, y}, %private} HiddenPoint; + p1 : %{%fit self.{x, y}, %hidden<%full> self.private} HiddenPoint; +``` + +Where : + - `.pub` is a "all public fields" quasi-field + - `.private` is a "all private fields" quasi-field + - `%hidden<%a>` - it is some specific `%a` quasi field integrity, but we have no access to specify it + - `%private` is a shortcut for `%hidden<%full> self.private` + +So, more fully we could write for struct witj private fields: + - `%empty : %{%deny self.pub, %hidden<%empty> self.private}` integrity + - `%full : %{%fit self.pub, %hidden<%full> self.private}` integrity + + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + + +# Drawbacks +[drawbacks]: #drawbacks + +- it is definitely not a minor change +- type system became much more complicated + + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +(A) A lot of proposals that are alternatives to Partial Types in a whole: + - Partial borrowing [issue#1215](https://github.com/rust-lang/rfcs/issues/1215) + - View patterns [internals#16879](https://internals.rust-lang.org/t/view-types-based-on-pattern-matching/16879) + - Permissions [#3380](https://github.com/rust-lang/rfcs/pull/3380) + - Field projection [#3318](https://github.com/rust-lang/rfcs/pull/3318) + - Fields in Traits [#1546](https://github.com/rust-lang/rfcs/pull/1546) + - ImplFields [issue#3269](https://github.com/rust-lang/rfcs/issues/3269) + +(B) Alternative for another names or corrections for Partial Types. + - `%empty` or `%!` name + - `self1, self2, ..` or `self-1, self-2, ..` or `self#1, self#2`. Or add only 2 specific selfs: `self_ref, self_refmut` + + +# Prior art +[prior-art]: #prior-art + +Most languages don't have such strict rules for references and links as Rust, so this feature is almost unnecessary for them. + + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +Default qualified consumption is `%full` on Stage 1. It fully backward compatible and allow to switch cost-less to `%max` default! +But maybe it is not a good choice. As default argument consumption is `%full`, but not `%min`. + +# Future possibilities +[future-possibilities]: #future-possibilities + +We could add additional ReExtendeded Partial Types for **safe** Self-Referential Types. + +Theory of types do not forbid extension of Partial Type, but internal Rust representation of variables gives significant limitations on such action. + +It is need the `%miss`(aka `%deny` but extendible) field integrity to initialized constructor consumption only. And additional "extender" `%%=`. + +Pertly self-referential types example: +```rust +struct SR { + val : T, + lnk : & T, // reference to self.val +} + +// case (FP1) +let x = %{%miss self.lnk, %fit self._} SR {val : 5i32 }; + // + x : %{%miss self.lnk, %fit self.val} SR + // +x.lnk %%= & x.val; + // + x : SR ~ %full SR +``` +And even AlmostFully self-referential types: + +```rust +struct FSR { + val : T, + lnk : & %{%deny self.lnk, %fit self.val} FSR, + // reference to almost self! +} + +// case (FP2) +let x = %{%miss self.lnk, %fit self.val} FSR {val : 5i32 }; + // + x : %{%miss self.lnk, %fit self.val} FSR + // +x.lnk %%= & %max x; + // + x : FSR ~ %full FSR +``` + +First difficulty - `%max` is no longer `id`, `%max(on %miss) ~ %deny`. Both `filter-%fit on %miss` and `filter-%ignore on %miss` must cause a compiler error for 3 main consumers. + +Second and most difficult, that `return` consumption (yes, 6th type of consumers) from function could preserve `%miss`, so also we need filter `%max_miss`, where `%max_miss(on %miss) ~ %miss`! + +And another shortcut `%unfill : %miss self._` + +```rust +// case (FP3) +// FROM case (FP2) +fn create_var()-> %{%miss self.lnk, %fit self._} FSR { + let x = %{self.val, %unfill} FSR {val : 5i32 }; + // + x : %{%miss self.lnk, %fit self.val} FSR + // + %max_miss return x; + // filter integrity before 'return' to not to confused with `move` consumer! +} + +let y = create_var(); +y.lnk %%= & %max y; + // + y : FSR ~ %full FSR +``` From d882f0ad0ee7c9acc490ef20834514bfd284a1dc Mon Sep 17 00:00:00 2001 From: law Date: Tue, 18 Apr 2023 18:36:11 +0300 Subject: [PATCH 02/13] minor grammar --- text/0000-partial_types.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 4339445a55e..204e67d8786 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -107,9 +107,9 @@ An abstractions is added for integrity detailing, we assume that **every** varia We need for this some new quasi-fields and some field integrity (which should be soft keywords). -_Note_: I do not comment types (as is needed for compiler) for colorizing purposes. +_Note: I do not comment types (as is needed for compiler) for colorizing purposes._ -_Note_: I use symbol `~` as synonym of "equivalent" word only. It is not a Rust operator. +_Note: I use symbol `~` as a synonym of "equivalent" word only. It is not a Rust operator._ ```rust // case (C1) let foo = 0i16; @@ -146,9 +146,9 @@ Where : We assume, that each field could be in one of 2 specific field-integrity - `%fit` and `%deny`. -We also must reserve as a keyword a `%miss` field-integrity for future Reintegrated Partial Types, which allows to create **safe** self-referential types. +We also must reserve as a keyword a `%miss` field-integrity for future ReExtendeded Partial Types, which allows to create **safe** self-referential types. -`%fit` is default field-integrity and it means we nave an access to this field and could use it as we wish. But if we try to access `%deny` field it cause a compiler error. +`%fit` is default field-integrity and it means we have an access to this field and could use it as we wish. But if we try to access `%deny` field it cause a compiler error. ```rust // case (C3) @@ -216,11 +216,11 @@ struct PointExtra { saved_y: f64, } -fn x_store(&mut p1 : &mut %{self.saved_x, %any} PointExtra, & p2 : &mut %{self.x, %any} PointExtra) { +fn x_store(&mut p1 : &mut %{self.saved_x, %any} PointExtra, & p2 : & %{self.x, %any} PointExtra) { *p1.saved_x = *p2.x } -fn x_restore(&mut p1 : &mut %{self.x, %any} PointExtra, & p2 : &mut %{self.saved_x, %any} PointExtra) { +fn x_restore(&mut p1 : &mut %{self.x, %any} PointExtra, & p2 : & %{self.saved_x, %any} PointExtra) { *p1.x = *p2.saved_x; } ``` @@ -230,14 +230,14 @@ or use `where` clause if integrity is extra verbose: // case (D6) // FROM case (D5) -fn x_store(&mut p1 : &mut %fit_sv_x PointExtra, & p2 : &mut %fit_x PointExtra) +fn x_store(&mut p1 : &mut %fit_sv_x PointExtra, & p2 : & %fit_x PointExtra) where %fit_sv_x : %{self.saved_x, %any}, %fit_x : %{self.x, %any} { *p1.saved_x = *p2.x } -fn x_restore(&mut p1 : &mut %fit_x PointExtra, & p2 : &mut %fit_sv_x PointExtra) +fn x_restore(&mut p1 : &mut %fit_x PointExtra, & p2 : & %fit_sv_x PointExtra) where %fit_sv_x : %{self.saved_x, %any}, %fit_x : %{self.x, %any} { @@ -617,6 +617,7 @@ x.lnk %%= & x.val; x : SR ~ %full SR ``` And even AlmostFully self-referential types: +And another shortcut `%unfill : %miss self._` ```rust struct FSR { @@ -626,7 +627,7 @@ struct FSR { } // case (FP2) -let x = %{%miss self.lnk, %fit self.val} FSR {val : 5i32 }; +let x = %{self.val, %unfill} FSR {val : 5i32 }; // x : %{%miss self.lnk, %fit self.val} FSR // @@ -639,7 +640,6 @@ First difficulty - `%max` is no longer `id`, `%max(on %miss) ~ %deny`. Both `fi Second and most difficult, that `return` consumption (yes, 6th type of consumers) from function could preserve `%miss`, so also we need filter `%max_miss`, where `%max_miss(on %miss) ~ %miss`! -And another shortcut `%unfill : %miss self._` ```rust // case (FP3) From 29b35d28e5d3b4b9195f689816b8cc6c255fe961 Mon Sep 17 00:00:00 2001 From: law Date: Tue, 18 Apr 2023 19:15:21 +0300 Subject: [PATCH 03/13] add deconstruct example --- text/0000-partial_types.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 204e67d8786..c1a639691b8 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -9,7 +9,7 @@ Partial types proposal is a generalization on "partial borrowing"-like proposals (more correct name is "partial not borrowing" or "qualified borrowing" since Rust allows partial borrowing already). -This proposal is a roadmap "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. +This proposal is a universal roadmap "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. Partial Types is a **minimal** and full extension to the Rust Type System, which allows to safe control easily partial parameters and all kinds of partial not consumption. @@ -519,6 +519,17 @@ let t4_02 = %{self.{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); t4_02 : %{%fit self.{0,2}, %deny self.{1,3}} (&str, i32, &u16, f32); ``` +Integrity filter could help to deconstruct types for matching: + +```rust +// case (G6) +let opt_t4_1 = Some (%{self.1, %cut} ("str", 1i32, &0u16, 0.0f32)); + // + opt_t4_1 : Option<%{%fit self.{1}, %deny self.{1,3}} (&str, i32, &u16, f32)>; + // + let Some (%{self.1, %cut} (_, ref y, _, _)) = opt_t4_1; +``` + ## Private fields And finally, what to do with private fields? From 8ee53f425cefe555b91a373504caf9baf592233d Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Tue, 18 Apr 2023 20:07:56 +0300 Subject: [PATCH 04/13] type integrity belongs to sub-type --- text/0000-partial_types.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index c1a639691b8..9d718cdec11 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -58,9 +58,10 @@ foo : value 'static const i16; That mean, that variable `foo` has the `i16` (sub-)type with next type-clarification: `const`(not `mut`) mutability, `value`(not `&`) sharing and `'static` lifetime. -I propose to extend type system by adding type integrity to clarification sub-type. So, our variable will have next full type: +I propose to extend type system by adding type integrity to sub-type. So, our variable will have next full type: ```rust // case (A4) + : <%integrity> ; : <'lifetime> <%integrity> ; // case (A5) From 3e9aa80618fd003e7880da4aeb64e11679f0c3ce Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Wed, 19 Apr 2023 02:38:31 +0300 Subject: [PATCH 05/13] integrity 2 access, fit 2 permit, self. 2 Self::, more examples --- text/0000-partial_types.md | 377 +++++++++++++++++++++---------------- 1 file changed, 214 insertions(+), 163 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 9d718cdec11..cd4eaa596b6 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -9,7 +9,7 @@ Partial types proposal is a generalization on "partial borrowing"-like proposals (more correct name is "partial not borrowing" or "qualified borrowing" since Rust allows partial borrowing already). -This proposal is a universal roadmap "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. +This proposal is a universal road-map "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. Partial Types is a **minimal** and full extension to the Rust Type System, which allows to safe control easily partial parameters and all kinds of partial not consumption. @@ -25,16 +25,20 @@ Partial borrowing is already possible in Rust, as partial referencing and partia But partial parameters are forbidden now, as qualified consumption: partial not borrowing, partial not referencing, partial not moving and partial initializing. +This proposal +1) It is full backward-compatible. +2) It adds some **safe** flexibility to **safe** code by **safe** methods. +3) It has simplicity in binary - Type access just say by type to compiler, that some fields are forbidden to use _for everyone ever_. And that allows to use ordinary references as "partial" and ordinal variables as "partial". No extra actions with variables or pointers are needed. +4) Any type error is a compiler error, all types are erased after type-check, so no extra-cost in binary is needed. +5) It has universal rule - that mean minimal special cases on implementation. +6) It is minimal universal-extension - all other proposals propose less than this with more or same cost # Guide-level explanation [guide-level-explanation]: #guide-level-explanation _**Note**: I didn't comment type explanations (as is needed for compiler) for colorizing purposes only._ -_**Note**: I use symbol `~` in code as a synonym of "equivalent" word only. It is not a Rust operator!_ - - -## Partial types by type Integrity +## Partial types by type access ```rust // case (A1) @@ -49,41 +53,31 @@ What is a **full type** of `foo`? Is it the `i16`? No, the `i16` is a sub-full_t : <'lifetime> ; ``` -If we explicitly write **full type** (using _unused_ Rust names) we get: -```rust -// case (A3) -// FROM case (A1) -foo : value 'static const i16; -``` - -That mean, that variable `foo` has the `i16` (sub-)type with next type-clarification: `const`(not `mut`) mutability, `value`(not `&`) sharing and `'static` lifetime. +I propose to extend type system by adding type access to sub-type. So, our variable will have next full type: -I propose to extend type system by adding type integrity to sub-type. So, our variable will have next full type: ```rust // case (A4) - : <%integrity> ; - : <'lifetime> <%integrity> ; + : <%access> ; + : <'lifetime> <%access> ; // case (A5) // FROM case (A1) -foo : value 'b const %a i16; -foo : value 'static const %full i16; foo : %full i16; foo : i16; ``` Lifetime variants are `'static` (for static lifetime), `'_`(don't care lifetime) and any other `'b`(some "b" lifetime). -By the same analogy, integrity has similar names and meanings: `%full`(full integrity, soft keyword), `%_`(don't care how partial integrity is, soft keyword), `%empty` or `%!` (no integrity, soft keyword) and any other `%a`(some "a" integrity). +By the same analogy, access has similar names and meanings: `%full`(full access, soft keyword), `%_`(don't care how partial access is, soft keyword), `%empty` or `%!` (no access, soft keyword) and any other `%a`(some "a" access). Symbol `%` percent mean percent or part of the whole thing (variable in our case). -_Note_: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type integrity. +_Note: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type access._ -## Traits with Integrity variants +## Traits with access variants -We could already write Traits with **safe** virtual functions, that consumes virtual partial types having only variants of type integrity in Trait declaration +We could already write Traits with **safe** abstract functions (with no body), that consumes partial types having only variants of type access in Trait declaration ```rust // case (B1) pub trait Upd { @@ -97,34 +91,18 @@ pub trait Upd { } ``` -Unfortunately, having variants of type integrity is not enough to write **safe** implementations or other non-virtual function declarations. - +Unfortunately, having variants of type access is not enough to write **safe** implementations or other non-abstract function declarations. -## Detailed Integrity +## Detailed access +We need detailed access to write non-abstract specific typed parameters in function, including trait implementation. -We need detailed integrity to write non-virtual specific typed parameters in function, including trait implementation. - -An abstractions is added for integrity detailing, we assume that **every** variable is a `struct`-like objects (even if it is not). - -We need for this some new quasi-fields and some field integrity (which should be soft keywords). +We need for this some new quasi-fields and some field access (which should be soft keywords). _Note: I do not comment types (as is needed for compiler) for colorizing purposes._ -_Note: I use symbol `~` as a synonym of "equivalent" word only. It is not a Rust operator._ -```rust -// case (C1) -let foo = 0i16; - foo : i16 ~ %full i16; - foo : %full i16 ~ %{self.*} i16; - foo : %{self.*} i16 ~ %{self.self} i16; -``` +### Detailed Struct Type -Where : - - `self` is an "access" to variable itself - - `.*` is an "every field" quasi-field - - `.self` quasi-field for primitive types, since `i16` is not a `struct` type - -What's about structures? Almost the same: +What's about structures? ```rust struct Point { x: f64, @@ -134,78 +112,149 @@ struct Point { w: f64, } +// case (C1) +let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; + // + p1 : &mut Point; + p1 : &mut %full Point; + p1 : &mut %{Self::*} Point; + p1 : &mut %{Self::x, Self::y, Self::z, Self::t, Self::w} Point; + p1 : &mut %{Self::{x, y, z, w}} Point; +``` + +Where : + - `Self` is an "link" to variable type itself + - `::*` is an "every field" quasi-field + - `::{, , }` is an field-set quasi-field + +We assume, that each field could be in one of two specific field-accesss - `%permit` and `%deny`. + +We also must reserve as a keyword a `%miss` field-access for future ReExtendeded Partial Types, which allows to create **safe** self-referential types. + +`%permit` is default field-access and it means we have an access to this field and could use it as we wish. But if we try to access to `%deny` field it cause a compiler error. + +```rust // case (C2) +// FROM case (C1) let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; - p1 : &mut Point ~ &mut %full Point; - p1 : &mut %{self.*} Point; - p1 : &mut %{self.x, self.y, self.z, self.t, self.w} Point; - p1 : &mut %{self.{x, y, z, w}} Point; + // + p1 : &mut %{%permit Self::*} Point; + p1 : &mut %{%permit Self::*, %deny Self::_}; + p1 : &mut %{%permit Self::{x, y, z, w}} Point; ``` Where : - - `.{, , }` is an field-set quasi-field + - `%permit` access + - `%deny` access + - `::_` is a "rest of fields" quasi-field + +As we see, + - `%empty : %{%deny Self::*}` or `%empty : %{}` access + - `%full : %{%permit Self::*}` or `%full : %{Self::*}` access -We assume, that each field could be in one of 2 specific field-integrity - `%fit` and `%deny`. +### Detailed Primitive Types -We also must reserve as a keyword a `%miss` field-integrity for future ReExtendeded Partial Types, which allows to create **safe** self-referential types. +Primitive types (numbers, units) do not have internal structures. Their access is always `%full` -`%fit` is default field-integrity and it means we have an access to this field and could use it as we wish. But if we try to access `%deny` field it cause a compiler error. +For Primitive Partial Types we assume that **every** variable is a `struct`-like objects (even if it is not) and has a single quasi-field - `::self`. + +It is a compile error if we try to `%deny` a `::self` field! ```rust // case (C3) let foo = 0i16; - foo : %{self.*} i16 ~ %{self.self} i16; - foo : %{%fit self.*} i16 ~ %{%fit self.self} i16; - foo : %{%fit self.*, %deny self._} i16; + // + foo : i16 + foo : %full i16; + foo : %{Self::*} i16; + foo : %{Self::self} i16; + foo : %{%permit Self::self} i16; +``` +### Detailed Tuples +For Tuples we assume that **every** variable is a `struct`-like objects (even if it is not) and has unnamed numbered fields. + +It is a compile error if we try to `%deny` a `::self` field! + +```rust // case (C4) -// FROM case (C2) -let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; - p1 : &mut %{%fit self.*} Point ~ &mut %{%fit self.*, %deny self._}; - p1 : &mut %{%fit self.{x, y, z, w}} Point; +let bar = (0i16, &5i32, "some_string"); + // + bar : (i16, &i32, &str); + bar : %full (i16, &i32, &str); + bar : %{Self::*} (i16, &i32, &str); + bar : %{%permit Self::{0,1,2}} (i16, &i32, &str); ``` -Where : - - `%fit` integrity - - `%deny` integrity - - `._` is a "rest of fields" quasi-field +### Detailed Arrays -As we see, - - `%empty : %{%deny self.*}` or `%empty : %{}` integrity - - `%full : %{%fit self.*}` or `%full : %{self.*}` integrity +For Arrays we assume that **every** variable is a `tuple`-like objects (even if it is not) and has unnamed numbered fields. + +Unfortunately, Arrays are a bit magical, so it is _unclear_ if we could represent it access like a tuple access. + +### Detailed Enum Type +What's about Enums? + +It is more complicated, then `struct` types, because we grant some **type** access, not **value** access! + +So, all possible constructors are permitted! But, we could deny sub-fields! +```rust +enum WebEvent { + PageLoad, + PageUnload, + + KeyPress(char), + Paste(String), + + Click { x: i64, y: i64 }, +} +// case (C5) +let a = WebEvent::PageLoad; + // + a : WebEvent; + a : %full WebEvent; + a : %{Self::*::*} WebEvent; + a : %{%permit Self::{PageLoad, PageUnload}::self, %permit Self::{KeyPress, Paste}::0, %permit Self::Click::{x, y}} WebEvent; +``` +where + - `::self` quasi-field for unit types, since `PageLoad`/`PageUnload` is not a `struct` + - `::0` is like mono-tuple field for `KeyPress(char)` and `Paste(String)` + + It is a compile error if we try to `%deny` a `::self` field! + ## Partial parameters -We add enough integrity, and could write partial parameters for non-virtual function declarations: +We add enough access, and could write partial parameters for non-abstract function declarations: ```rust // case (D1) -fn re_ref_t (& p : & %{self.t, %ignore self._} Point) -> &f64 { +fn re_ref_t (& p : & %{Self::t, %ignore Self::_} Point) -> &f64 { &p.t } // case (D2) -fn refmut_w (&mut p : &mut %{self.w, %ignore self._} Point) -> &mut f64 { +fn refmut_w (&mut p : &mut %{Self::w, %ignore Self::_} Point) -> &mut f64 { &mut p.w } ``` Where : - - `%ignore` is a "don't care which exactly" quasi filed-integrity (`%_` is a whole type integrity and it is unclear if we could use it in both contents) + - `%ignore` is a "don't care which exactly" quasi filed-access (`%_` is a whole type access and it is unclear if we could use it in both contents) -But `%ignore self._` quasi-filed-integrity of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore self._`. +But `%ignore Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore Self::_`. ```rust // case (D3) // FROM case (D1) -fn re_ref_t (& p : & %{self.t, %any} Point) -> &f64 { +fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { &p.t } // case (D4) // FROM case (D2) -fn refmut_w (&mut p : &mut %{self.w, %any} Point) -> &mut f64 { +fn refmut_w (&mut p : &mut %{Self::w, %any} Point) -> &mut f64 { &mut p.w } @@ -217,30 +266,30 @@ struct PointExtra { saved_y: f64, } -fn x_store(&mut p1 : &mut %{self.saved_x, %any} PointExtra, & p2 : & %{self.x, %any} PointExtra) { +fn x_store(&mut p1 : &mut %{Self::saved_x, %any} PointExtra, & p2 : & %{Self::x, %any} PointExtra) { *p1.saved_x = *p2.x } -fn x_restore(&mut p1 : &mut %{self.x, %any} PointExtra, & p2 : & %{self.saved_x, %any} PointExtra) { +fn x_restore(&mut p1 : &mut %{Self::x, %any} PointExtra, & p2 : & %{Self::saved_x, %any} PointExtra) { *p1.x = *p2.saved_x; } ``` -or use `where` clause if integrity is extra verbose: +or use `where` clause if access is extra verbose: ```rust // case (D6) // FROM case (D5) -fn x_store(&mut p1 : &mut %fit_sv_x PointExtra, & p2 : & %fit_x PointExtra) - where %fit_sv_x : %{self.saved_x, %any}, - %fit_x : %{self.x, %any} +fn x_store(&mut p1 : &mut %permit_sv_x PointExtra, & p2 : & %permit_x PointExtra) + where %permit_sv_x : %{Self::saved_x, %any}, + %permit_x : %{Self::x, %any} { *p1.saved_x = *p2.x } -fn x_restore(&mut p1 : &mut %fit_x PointExtra, & p2 : & %fit_sv_x PointExtra) - where %fit_sv_x : %{self.saved_x, %any}, - %fit_x : %{self.x, %any} +fn x_restore(&mut p1 : &mut %permit_x PointExtra, & p2 : & %permit_sv_x PointExtra) + where %permit_sv_x : %{Self::saved_x, %any}, + %permit_x : %{Self::x, %any} { *p1.x = *p2.saved_x; } @@ -250,11 +299,11 @@ Implementation parameters are mostly same: ```rust // case (D7) impl Point { - pub fn x_refmut(&mut self : &mut %{self.x, %any} Self) -> &mut f64 { + pub fn x_refmut(&mut self : &mut %{Self::x, %any} Self) -> &mut f64 { &mut self.x } - pub fn y_refmut(&mut self : &mut %{self.y, %any} Self) -> &mut f64 { + pub fn y_refmut(&mut self : &mut %{Self::y, %any} Self) -> &mut f64 { &mut self.y } } @@ -263,42 +312,42 @@ impl Point { We could also use multiple sub-parameters of same parameter ```rust // case (D8) - pub fn xy_swich(&mut self : &mut %{self.{x, y}, %any} Self) { + pub fn xy_swich(&mut self : &mut %{Self::{x, y}, %any} Self) { let tmp = *self.x; *self.x = *self.y; *self.y = tmp; } ``` -Now type integrity guarantee to compiler, that only some fields has an access inside function, but not the rest of them. -So, no extra lock on `self` is needed, only for `%fit` fields. +Now type access guarantee to compiler, that only some fields has an access inside function, but not the rest of them. +So, no extra lock on `self` is needed, only for `%permit` fields. Now compiler can catch "out of scope parameter" errors ```rust // case (D9) - pub fn xt_refmut(&self : &mut %{self.xt, %any} Self) -> &mut f64 { + pub fn xt_refmut(&self : &mut %{Self::xt, %any} Self) -> &mut f64 { // ^~~~~~ - // error: no field 'self.xt' on type `self` + // error: no field 'Self::xt' on type `Self` &mut self.xt } ``` -Since using `%ignore` filed is **unsafe**, trying to use ignoring field is a compile error: +Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error: ```rust // case (D10) - pub fn t_refmut(&self : &mut %{self.t, %any} Self) -> &mut f64 { + pub fn t_refmut(&self : &mut %{Self::t, %any} Self) -> &mut f64 { &mut self.x // ^~~~~~ - // error: cannot find value 'self.x' in this scope + // error: cannot find value 'Self::x' in this scope } ``` Compile could catch more dead code warnings ```rust // case (D11) - pub fn x_refmut(&self : &mut %{self.x, self.y, %any} Self) -> &mut f64 { + pub fn x_refmut(&self : &mut %{Self::x, Self::y, %any} Self) -> &mut f64 { // ^~~~~~ - // warning: '#[warn(dead_code)]' field is never read: `self.y` + // warning: '#[warn(dead_code)]' field is never read: `Self::y` &mut self.x } ``` @@ -319,23 +368,23 @@ trait St { } // case (E2) - pub fn x_store(&mut self1 : &mut %{self.x, %any} Self, &self2 : & %{self.saved_x, %any} Self) + pub fn x_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::saved_x, %any} Self) { *self1.saved_x = *self2.x } - pub fn x_restore(&mut self1 : &mut %{self.saved_x, %any} Self, &self2 : & %{self.x, %any} Self) { + pub fn x_restore(&mut self1 : &mut %{Self::saved_x, %any} Self, &self2 : & %{Self::x, %any} Self) { *self1.x = *self2.saved_x; } ``` -Sure, if we use several `self`s, their fit fileds integrity cannot overlap! +Sure, if we use several `self`s, their fit fileds access cannot overlap! ```rust // case (E3) - pub fn x2_store(&mut self1 : &mut %{self.x, %any} Self, &self2 : & %{self.x, %any} Self) { + pub fn x2_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::x, %any} Self) { // ^~~~~~ ^~~~~ - // error: cannot overlap fit-field 'self.x' on self1 and self2 + // error: cannot overlap fit-field 'Self::x' on self1 and self2 *self1.x = *self2.x; } ``` @@ -362,7 +411,7 @@ Partial access to the field is already granted (exept arrays). Rust consumer use same names for action and for type clarifications, so we follow this style. -We need to add integrity filter to them, ignoring it mean `%full` filter (Ok, it is a bit unclear which is a default filter - `%full` or `%max`)! +We need to add access filter to them, ignoring it mean `%full` filter (Ok, it is a bit unclear which is a default filter - `%full` or `%max`)! `%full` means consumer consume all fields. @@ -386,13 +435,13 @@ let d: String = %full x.f3; Trying to consume `%deny` field is a compile error! The consumer DO NOT consume `%deny` EVER. -Resulted field integrity is the following: +Resulted field access is the following: -| ↓filter / →integrity | `%fit` | `%deny` | `%hidden` | -|----------------------|---------|-----------|-----------| -| `%fit` | `%fit` | !ERROR | !ERROR | -| `%deny` | `%deny` | `%deny` | !ERROR | -| `%hidden` | !ERROR | !ERROR | `%hidden` | +| ↓filter / →access | `%permit` | `%deny` | `%hidden` | +|-------------------|-----------|-----------|-----------| +| `%permit` | `%permit` | !ERROR | !ERROR | +| `%deny` | `%deny` | `%deny` | !ERROR | +| `%hidden` | !ERROR | !ERROR | `%hidden` | ```rust struct S5 { f1: String, f2: String, f3: String, f4: String, f5: String } @@ -401,52 +450,52 @@ let mut x: S5; // case (F3) let ref1: &mut String = &mut x.f1; // -let ref_x23 = & %{self.f2, self.f3, %deny self._} x; +let ref_x23 = & %{Self::f2, Self::f3, %deny Self::_} x; // - ref_x23 : & %{%fit self.{f2, f3}, %deny self.{f1, f4, f5}} S5; + ref_x23 : & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; // -let move_x45 = %{self.{f4, f5}, %cut} x; +let move_x45 = %{Self::{f4, f5}, %cut} x; // - move_x45 : %{%fit self.{f4, f5}, %deny self.{f1, f2, f3}} S5; + move_x45 : %{%permit Self::{f4, f5}, %deny Self::{f1, f2, f3}} S5; ``` -But `%deny self._` quasi-filed-integrity of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny self._`. +But `%deny Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny Self::_`. -What to do if we wish to create a reference to `ref_x23`. Do we need to write explicitly an integrity or exists implicit way? +What to do if we wish to create a reference to `ref_x23`. Do we need to write explicitly an access or exists implicit way? -No, we could use `%max`(or `%id`) - qualified safe filter with maximum fit-fields, but technically is an `id` filter to variable integrity: +No, we could use `%max`(or `%id`) - qualified safe filter with maximum profit-fields, but technically is an `id` filter to variable access: -| var integrity | `%max` | -|-----------------|----------| -| `%fit` | `%fit` | -| `%deny` | `%deny` | -| `%hidden` | `%hidden`| +| var access | `%max` | +|--------------|-----------| +| `%permit` | `%permit` | +| `%deny` | `%deny` | +| `%hidden` | `%hidden` | Having this we could write next implicitly ```rust // FROM case (F1) - ref_x23: & %{%fit self.{f2, f3}, %deny self.{f1, f4, f5}} S5; + ref_x23: & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; // case (F4) let refref_x23 = & %max ref_x23; // - refref_x23: && %{%fit self.{f2, f3}, %deny self.{f1, f4, f5}} S5; + refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; ``` -For function argument we add another filter `%min` - qualified safe filter with minimum fit-fields, but it refers not to variable integrity, but to parameter integrity, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! +For function argument we add another filter `%min` - qualified safe filter with minimum profit-fields, but it refers not to variable access, but to parameter access, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! -| param integrity | `%min` | -|------------------|----------| -| `%fit` | `%fit` | -| `%deny` | `%deny` | -| `%ignore` | `%deny` | -| `%hidden` | `%hidden`| +| param access | `%min` | +|---------------|-----------| +| `%permit` | `%permit` | +| `%deny` | `%deny` | +| `%ignore` | `%deny` | +| `%hidden` | `%hidden` | Implementations always consumes `self` by `%min` filter! ```rust // FROM case (D3) -fn re_ref_t (& p : & %{self.t, %any} Point) -> &f64 { +fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { &p.t } let mut p1 : mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; @@ -469,7 +518,7 @@ p3.update_sametype(&mut %min p2); ## Partially Initialized Variables -We must have an ability to create partially initilized variables. So we need to add a filter-integrity to a constructor +We must have an ability to create partially initilized variables. So we need to add a filter-access to a constructor ```rust struct Point { @@ -486,14 +535,14 @@ let p1_full = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; p1_full : Point ~ %full Point; // case (G2) -let p_x = %{self.x, %cut} Point {x:1.0}; +let p_x = %{Self::x, %cut} Point {x:1.0}; // - p_x : %{%fit self.x, %deny self._} Point; + p_x : %{%permit Self::x, %deny Self::_} Point; // -let p_yz = %{self.{y,z}, %cut} Point {y:1.0, z: 2.0}; +let p_yz = %{Self::{y,z}, %cut} Point {y:1.0, z: 2.0}; // - p_yz : %{%fit self.{y,z}, %deny self._} Point; + p_yz : %{%permit Self::{y,z}, %deny Self::_} Point; // ``` @@ -502,7 +551,7 @@ Also it could be nice if constructor allows several filler variables (which do n // case (G3) let p_xyz = %max Point {..p_x, ..p_yz}; // - p_xyz : %{%fit self.{x,y,z}, %deny self.{t,w}}; + p_xyz : %{%permit Self::{x,y,z}, %deny Self::{t,w}}; // case (G4) let p2_full = Point {t:1.0, w:2.0, ..p_xyz}; @@ -515,27 +564,27 @@ A bit unclear how to fill unused fields, so we write unused values to a fill the ```rust // case (G5) -let t4_02 = %{self.{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); +let t4_02 = %{Self::{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); // - t4_02 : %{%fit self.{0,2}, %deny self.{1,3}} (&str, i32, &u16, f32); + t4_02 : %{%permit Self::{0,2}, %deny Self::{1,3}} (&str, i32, &u16, f32); ``` -Integrity filter could help to deconstruct types for matching: +access filter could help to deconstruct types for matching: ```rust // case (G6) -let opt_t4_1 = Some (%{self.1, %cut} ("str", 1i32, &0u16, 0.0f32)); +let opt_t4_1 = Some (%{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); // - opt_t4_1 : Option<%{%fit self.{1}, %deny self.{1,3}} (&str, i32, &u16, f32)>; + opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; // - let Some (%{self.1, %cut} (_, ref y, _, _)) = opt_t4_1; + let Some (%{Self::1, %cut} (_, ref y, _, _)) = opt_t4_1; ``` ## Private fields And finally, what to do with private fields? -If variable has private field, it is an always `%hidden self.private` quasi-field. +If variable has private field, it is an always `%hidden Self::private` quasi-field. ```rust pub struct HiddenPoint { pub x: f64, @@ -548,20 +597,20 @@ pub struct HiddenPoint { // case (H1) let p1 : HiddenPoint; p1 : %full HiddenPoint; - p1 : %{%fit self.pub, %private} HiddenPoint; - p1 : %{%fit self.{x, y}, %private} HiddenPoint; - p1 : %{%fit self.{x, y}, %hidden<%full> self.private} HiddenPoint; + p1 : %{%permit Self::pub, %private} HiddenPoint; + p1 : %{%permit Self::{x, y}, %private} HiddenPoint; + p1 : %{%permit Self::{x, y}, %hidden<%full> Self::private} HiddenPoint; ``` Where : - `.pub` is a "all public fields" quasi-field - `.private` is a "all private fields" quasi-field - - `%hidden<%a>` - it is some specific `%a` quasi field integrity, but we have no access to specify it - - `%private` is a shortcut for `%hidden<%full> self.private` + - `%hidden<%a>` - it is some specific `%a` quasi field access, but we have no access to specify it + - `%private` is a shortcut for `%hidden<%full> Self::private` So, more fully we could write for struct witj private fields: - - `%empty : %{%deny self.pub, %hidden<%empty> self.private}` integrity - - `%full : %{%fit self.pub, %hidden<%full> self.private}` integrity + - `%empty : %{%deny Self::pub, %hidden<%empty> Self::private}` access + - `%full : %{%permit Self::pub, %hidden<%full> Self::private}` access # Reference-level explanation @@ -606,63 +655,64 @@ But maybe it is not a good choice. As default argument consumption is `%full`, b # Future possibilities [future-possibilities]: #future-possibilities +## ReExtendeded Partial Types + We could add additional ReExtendeded Partial Types for **safe** Self-Referential Types. Theory of types do not forbid extension of Partial Type, but internal Rust representation of variables gives significant limitations on such action. -It is need the `%miss`(aka `%deny` but extendible) field integrity to initialized constructor consumption only. And additional "extender" `%%=`. +It is need the `%miss`(aka `%deny` but extendible) field access to initialized constructor consumption only. And additional "extender" `%%=`. -Pertly self-referential types example: +Partly self-referential types example: ```rust struct SR { val : T, - lnk : & T, // reference to self.val + lnk : & T, // reference to Self::val } // case (FP1) -let x = %{%miss self.lnk, %fit self._} SR {val : 5i32 }; +let x = %{%miss Self::lnk, %permit Self::_} SR {val : 5i32 }; // - x : %{%miss self.lnk, %fit self.val} SR + x : %{%miss Self::lnk, %permit Self::val} SR // x.lnk %%= & x.val; // x : SR ~ %full SR ``` And even AlmostFully self-referential types: -And another shortcut `%unfill : %miss self._` +And another shortcut `%unfill : %miss Self::_` ```rust struct FSR { val : T, - lnk : & %{%deny self.lnk, %fit self.val} FSR, + lnk : & %{%deny Self::lnk, %permit Self::val} FSR, // reference to almost self! } // case (FP2) -let x = %{self.val, %unfill} FSR {val : 5i32 }; +let x = %{Self::val, %unfill} FSR {val : 5i32 }; // - x : %{%miss self.lnk, %fit self.val} FSR + x : %{%miss Self::lnk, %permit Self::val} FSR // x.lnk %%= & %max x; // x : FSR ~ %full FSR ``` -First difficulty - `%max` is no longer `id`, `%max(on %miss) ~ %deny`. Both `filter-%fit on %miss` and `filter-%ignore on %miss` must cause a compiler error for 3 main consumers. +First difficulty - `%max` is no longer `id`, `%max(on %miss) ~ %deny`. Both `filter-%permit on %miss` and `filter-%ignore on %miss` must cause a compiler error for 3 main consumers. Second and most difficult, that `return` consumption (yes, 6th type of consumers) from function could preserve `%miss`, so also we need filter `%max_miss`, where `%max_miss(on %miss) ~ %miss`! - ```rust // case (FP3) // FROM case (FP2) -fn create_var()-> %{%miss self.lnk, %fit self._} FSR { - let x = %{self.val, %unfill} FSR {val : 5i32 }; +fn create_var()-> %{%miss Self::lnk, %permit Self::_} FSR { + let x = %{Self::val, %unfill} FSR {val : 5i32 }; // - x : %{%miss self.lnk, %fit self.val} FSR + x : %{%miss Self::lnk, %permit Self::val} FSR // %max_miss return x; - // filter integrity before 'return' to not to confused with `move` consumer! + // filter access before 'return' to not to confused with `move` consumer! } let y = create_var(); @@ -670,3 +720,4 @@ y.lnk %%= & %max y; // y : FSR ~ %full FSR ``` + From 8bf07e5c5cc8651e972d2b1314568872ab077076 Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Wed, 19 Apr 2023 02:53:00 +0300 Subject: [PATCH 06/13] comment type explanations --- text/0000-partial_types.md | 102 ++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index cd4eaa596b6..f16ff0a0bbf 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -36,8 +36,6 @@ This proposal # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -_**Note**: I didn't comment type explanations (as is needed for compiler) for colorizing purposes only._ - ## Partial types by type access ```rust @@ -62,8 +60,8 @@ I propose to extend type system by adding type access to sub-type. So, our varia // case (A5) // FROM case (A1) -foo : %full i16; -foo : i16; +// foo : %full i16; +// foo : i16; ``` Lifetime variants are `'static` (for static lifetime), `'_`(don't care lifetime) and any other `'b`(some "b" lifetime). @@ -98,8 +96,6 @@ We need detailed access to write non-abstract specific typed parameters in funct We need for this some new quasi-fields and some field access (which should be soft keywords). -_Note: I do not comment types (as is needed for compiler) for colorizing purposes._ - ### Detailed Struct Type What's about structures? @@ -115,11 +111,11 @@ struct Point { // case (C1) let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; // - p1 : &mut Point; - p1 : &mut %full Point; - p1 : &mut %{Self::*} Point; - p1 : &mut %{Self::x, Self::y, Self::z, Self::t, Self::w} Point; - p1 : &mut %{Self::{x, y, z, w}} Point; + // p1 : &mut Point; + // p1 : &mut %full Point; + // p1 : &mut %{Self::*} Point; + // p1 : &mut %{Self::x, Self::y, Self::z, Self::t, Self::w} Point; + // p1 : &mut %{Self::{x, y, z, w}} Point; ``` Where : @@ -138,9 +134,9 @@ We also must reserve as a keyword a `%miss` field-access for future ReExtendeded // FROM case (C1) let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; // - p1 : &mut %{%permit Self::*} Point; - p1 : &mut %{%permit Self::*, %deny Self::_}; - p1 : &mut %{%permit Self::{x, y, z, w}} Point; + // p1 : &mut %{%permit Self::*} Point; + // p1 : &mut %{%permit Self::*, %deny Self::_}; + // p1 : &mut %{%permit Self::{x, y, z, w}} Point; ``` Where : @@ -164,11 +160,11 @@ It is a compile error if we try to `%deny` a `::self` field! // case (C3) let foo = 0i16; // - foo : i16 - foo : %full i16; - foo : %{Self::*} i16; - foo : %{Self::self} i16; - foo : %{%permit Self::self} i16; + // foo : i16 + // foo : %full i16; + // foo : %{Self::*} i16; + // foo : %{Self::self} i16; + // foo : %{%permit Self::self} i16; ``` ### Detailed Tuples @@ -181,10 +177,10 @@ It is a compile error if we try to `%deny` a `::self` field! // case (C4) let bar = (0i16, &5i32, "some_string"); // - bar : (i16, &i32, &str); - bar : %full (i16, &i32, &str); - bar : %{Self::*} (i16, &i32, &str); - bar : %{%permit Self::{0,1,2}} (i16, &i32, &str); + // bar : (i16, &i32, &str); + // bar : %full (i16, &i32, &str); + // bar : %{Self::*} (i16, &i32, &str); + // bar : %{%permit Self::{0,1,2}} (i16, &i32, &str); ``` ### Detailed Arrays @@ -214,10 +210,10 @@ enum WebEvent { // case (C5) let a = WebEvent::PageLoad; // - a : WebEvent; - a : %full WebEvent; - a : %{Self::*::*} WebEvent; - a : %{%permit Self::{PageLoad, PageUnload}::self, %permit Self::{KeyPress, Paste}::0, %permit Self::Click::{x, y}} WebEvent; + // a : WebEvent; + // a : %full WebEvent; + // a : %{Self::*::*} WebEvent; + // a : %{%permit Self::{PageLoad, PageUnload}::self, %permit Self::{KeyPress, Paste}::0, %permit Self::Click::{x, y}} WebEvent; ``` where - `::self` quasi-field for unit types, since `PageLoad`/`PageUnload` is not a `struct` @@ -452,11 +448,11 @@ let ref1: &mut String = &mut x.f1; // let ref_x23 = & %{Self::f2, Self::f3, %deny Self::_} x; // - ref_x23 : & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // ref_x23 : & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; // let move_x45 = %{Self::{f4, f5}, %cut} x; // - move_x45 : %{%permit Self::{f4, f5}, %deny Self::{f1, f2, f3}} S5; + // move_x45 : %{%permit Self::{f4, f5}, %deny Self::{f1, f2, f3}} S5; ``` But `%deny Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny Self::_`. @@ -474,12 +470,12 @@ No, we could use `%max`(or `%id`) - qualified safe filter with maximum profit-fi Having this we could write next implicitly ```rust // FROM case (F1) - ref_x23: & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // ref_x23: & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; // case (F4) let refref_x23 = & %max ref_x23; // - refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; ``` For function argument we add another filter `%min` - qualified safe filter with minimum profit-fields, but it refers not to variable access, but to parameter access, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! @@ -532,17 +528,18 @@ struct Point { // case (G1) let p1_full = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; // - p1_full : Point ~ %full Point; + // p1_full : Point; + // p1_full : %full Point; // case (G2) let p_x = %{Self::x, %cut} Point {x:1.0}; // - p_x : %{%permit Self::x, %deny Self::_} Point; + // p_x : %{%permit Self::x, %deny Self::_} Point; // let p_yz = %{Self::{y,z}, %cut} Point {y:1.0, z: 2.0}; // - p_yz : %{%permit Self::{y,z}, %deny Self::_} Point; + // p_yz : %{%permit Self::{y,z}, %deny Self::_} Point; // ``` @@ -551,13 +548,13 @@ Also it could be nice if constructor allows several filler variables (which do n // case (G3) let p_xyz = %max Point {..p_x, ..p_yz}; // - p_xyz : %{%permit Self::{x,y,z}, %deny Self::{t,w}}; + // p_xyz : %{%permit Self::{x,y,z}, %deny Self::{t,w}}; // case (G4) let p2_full = Point {t:1.0, w:2.0, ..p_xyz}; // - p1_full : Point ~ %full Point; - // + // p2_full : Point; + // p2_fill : %full Point; ``` A bit unclear how to fill unused fields, so we write unused values to a fill the type for tuple constructor @@ -566,7 +563,7 @@ A bit unclear how to fill unused fields, so we write unused values to a fill the // case (G5) let t4_02 = %{Self::{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); // - t4_02 : %{%permit Self::{0,2}, %deny Self::{1,3}} (&str, i32, &u16, f32); + // t4_02 : %{%permit Self::{0,2}, %deny Self::{1,3}} (&str, i32, &u16, f32); ``` access filter could help to deconstruct types for matching: @@ -575,7 +572,7 @@ access filter could help to deconstruct types for matching: // case (G6) let opt_t4_1 = Some (%{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); // - opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; + // opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; // let Some (%{Self::1, %cut} (_, ref y, _, _)) = opt_t4_1; ``` @@ -596,15 +593,15 @@ pub struct HiddenPoint { // case (H1) let p1 : HiddenPoint; - p1 : %full HiddenPoint; - p1 : %{%permit Self::pub, %private} HiddenPoint; - p1 : %{%permit Self::{x, y}, %private} HiddenPoint; - p1 : %{%permit Self::{x, y}, %hidden<%full> Self::private} HiddenPoint; + // p1 : %full HiddenPoint; + // p1 : %{%permit Self::pub, %private} HiddenPoint; + // p1 : %{%permit Self::{x, y}, %private} HiddenPoint; + // p1 : %{%permit Self::{x, y}, %hidden<%full> Self::private} HiddenPoint; ``` Where : - - `.pub` is a "all public fields" quasi-field - - `.private` is a "all private fields" quasi-field + - `::pub` is a "all public fields" quasi-field + - `::private` is a "all private fields" quasi-field - `%hidden<%a>` - it is some specific `%a` quasi field access, but we have no access to specify it - `%private` is a shortcut for `%hidden<%full> Self::private` @@ -673,11 +670,12 @@ struct SR { // case (FP1) let x = %{%miss Self::lnk, %permit Self::_} SR {val : 5i32 }; // - x : %{%miss Self::lnk, %permit Self::val} SR + // x : %{%miss Self::lnk, %permit Self::val} SR // x.lnk %%= & x.val; // - x : SR ~ %full SR + // x : SR; + // x : %full SR; ``` And even AlmostFully self-referential types: And another shortcut `%unfill : %miss Self::_` @@ -692,11 +690,12 @@ struct FSR { // case (FP2) let x = %{Self::val, %unfill} FSR {val : 5i32 }; // - x : %{%miss Self::lnk, %permit Self::val} FSR + // x : %{%miss Self::lnk, %permit Self::val} FSR; // x.lnk %%= & %max x; // - x : FSR ~ %full FSR + // x : FSR; + // x : %full FSR; ``` First difficulty - `%max` is no longer `id`, `%max(on %miss) ~ %deny`. Both `filter-%permit on %miss` and `filter-%ignore on %miss` must cause a compiler error for 3 main consumers. @@ -709,7 +708,7 @@ Second and most difficult, that `return` consumption (yes, 6th type of consumers fn create_var()-> %{%miss Self::lnk, %permit Self::_} FSR { let x = %{Self::val, %unfill} FSR {val : 5i32 }; // - x : %{%miss Self::lnk, %permit Self::val} FSR + // x : %{%miss Self::lnk, %permit Self::val} FSR // %max_miss return x; // filter access before 'return' to not to confused with `move` consumer! @@ -718,6 +717,7 @@ fn create_var()-> %{%miss Self::lnk, %permit Self::_} FSR { let y = create_var(); y.lnk %%= & %max y; // - y : FSR ~ %full FSR + // y : FSR; + // y : %full FSR; ``` From 7f4ceb274cc3c87426f94d59f6d39ba8a97fda11 Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Wed, 19 Apr 2023 03:33:32 +0300 Subject: [PATCH 07/13] add type PointSaveX example --- text/0000-partial_types.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index f16ff0a0bbf..fb1f639a58c 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -291,9 +291,27 @@ fn x_restore(&mut p1 : &mut %permit_x PointExtra, & p2 : & %permit_sv_x PointExt } ``` -Implementation parameters are mostly same: +or add `type` ```rust // case (D7) +// FROM case (D5) + +type PointSaveX = %{Self::saved_x, %any} PointExtra; +type PointX = %{Self::x, %any} PointExtra; + + +fn x_store(&mut p1 : &mut PointSaveX, & p2 : & PointX) { + *p1.saved_x = *p2.x +} + +fn x_restore(&mut p1 : &mut PointX, & p2 : & PointSaveX) { + *p1.x = *p2.saved_x; +} +``` + +Implementation parameters are mostly same: +```rust +// case (D8) impl Point { pub fn x_refmut(&mut self : &mut %{Self::x, %any} Self) -> &mut f64 { &mut self.x @@ -307,7 +325,7 @@ impl Point { We could also use multiple sub-parameters of same parameter ```rust -// case (D8) +// case (D9) pub fn xy_swich(&mut self : &mut %{Self::{x, y}, %any} Self) { let tmp = *self.x; *self.x = *self.y; @@ -320,7 +338,7 @@ So, no extra lock on `self` is needed, only for `%permit` fields. Now compiler can catch "out of scope parameter" errors ```rust -// case (D9) +// case (D10) pub fn xt_refmut(&self : &mut %{Self::xt, %any} Self) -> &mut f64 { // ^~~~~~ // error: no field 'Self::xt' on type `Self` @@ -330,7 +348,7 @@ Now compiler can catch "out of scope parameter" errors Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error: ```rust -// case (D10) +// case (D11) pub fn t_refmut(&self : &mut %{Self::t, %any} Self) -> &mut f64 { &mut self.x // ^~~~~~ @@ -340,7 +358,7 @@ Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that so Compile could catch more dead code warnings ```rust -// case (D11) +// case (D12) pub fn x_refmut(&self : &mut %{Self::x, Self::y, %any} Self) -> &mut f64 { // ^~~~~~ // warning: '#[warn(dead_code)]' field is never read: `Self::y` From 0232aa24c5d5152e7e65cc5384b33d3072187172 Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Wed, 19 Apr 2023 06:01:15 +0300 Subject: [PATCH 08/13] add contents --- text/0000-partial_types.md | 137 ++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 57 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index fb1f639a58c..3d0cf74ea2e 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -36,6 +36,25 @@ This proposal # Guide-level explanation [guide-level-explanation]: #guide-level-explanation + - [Partial types by type access] + - [Access variants and parameters in Trait] + - [Detailed access] + - [Detailed Struct Type] + - [Detailed Primitive Types] + - [Detailed Tuples] + - [Detailed Arrays] + - [Detailed Enum Type] + - [Partial parameters] + - [Partial parameter styles] + - [Partial parameters on implementations] + - [Several selfs] + - [Partial parameter errors] + - [Partial not consumption] + - [Max access filter] + - [Min access filter] + - [Partially Initialized Variables] + - [Private fields] + ## Partial types by type access ```rust @@ -73,9 +92,9 @@ Symbol `%` percent mean percent or part of the whole thing (variable in our case _Note: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type access._ -## Traits with access variants +## Access variants and parameters in Trait -We could already write Traits with **safe** abstract functions (with no body), that consumes partial types having only variants of type access in Trait declaration +We could already write Traits with **safe** abstract functions (with no body), which consumes partial access type having only variants of type access. ```rust // case (B1) pub trait Upd { @@ -92,13 +111,13 @@ pub trait Upd { Unfortunately, having variants of type access is not enough to write **safe** implementations or other non-abstract function declarations. ## Detailed access -We need detailed access to write non-abstract specific typed parameters in function, including trait implementation. - -We need for this some new quasi-fields and some field access (which should be soft keywords). +We need to have detailed access to write non-abstract specific type parameters in function, including trait implementation. ### Detailed Struct Type What's about structures? + +We need for this some new quasi-fields and some field access (which should be soft keywords). ```rust struct Point { x: f64, @@ -150,9 +169,9 @@ As we see, ### Detailed Primitive Types -Primitive types (numbers, units) do not have internal structures. Their access is always `%full` +Primitive types (numbers, units) and not-detailed yet types do not have internal structure. Their access is always `%full` -For Primitive Partial Types we assume that **every** variable is a `struct`-like objects (even if it is not) and has a single quasi-field - `::self`. +For them we assume that **every** variable is a `struct`-like objects (even if it is not) and has a single quasi-field - `::self`. It is a compile error if we try to `%deny` a `::self` field! @@ -171,8 +190,6 @@ let foo = 0i16; For Tuples we assume that **every** variable is a `struct`-like objects (even if it is not) and has unnamed numbered fields. -It is a compile error if we try to `%deny` a `::self` field! - ```rust // case (C4) let bar = (0i16, &5i32, "some_string"); @@ -185,7 +202,7 @@ let bar = (0i16, &5i32, "some_string"); ### Detailed Arrays -For Arrays we assume that **every** variable is a `tuple`-like objects (even if it is not) and has unnamed numbered fields. +For Arrays we wish to assume that **every** variable is a `tuple`-like objects (even if it is not) and has unnamed numbered fields. Unfortunately, Arrays are a bit magical, so it is _unclear_ if we could represent it access like a tuple access. @@ -231,7 +248,7 @@ fn re_ref_t (& p : & %{Self::t, %ignore Self::_} Point) -> &f64 { } // case (D2) -fn refmut_w (&mut p : &mut %{Self::w, %ignore Self::_} Point) -> &mut f64 { +fn refmut_w (&mut p : &mut %{Self::w, %any} Point) -> &mut f64 { &mut p.w } ``` @@ -241,6 +258,10 @@ Where : But `%ignore Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore Self::_`. +### Partial parameter styles + +We could write partial parameters using different style. Ordinary one: + ```rust // case (D3) // FROM case (D1) @@ -248,12 +269,6 @@ fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { &p.t } -// case (D4) -// FROM case (D2) -fn refmut_w (&mut p : &mut %{Self::w, %any} Point) -> &mut f64 { - &mut p.w -} - // case (D5) struct PointExtra { x: f64, @@ -263,7 +278,7 @@ struct PointExtra { } fn x_store(&mut p1 : &mut %{Self::saved_x, %any} PointExtra, & p2 : & %{Self::x, %any} PointExtra) { - *p1.saved_x = *p2.x + *p1.saved_x = *p2.x; } fn x_restore(&mut p1 : &mut %{Self::x, %any} PointExtra, & p2 : & %{Self::saved_x, %any} PointExtra) { @@ -271,7 +286,7 @@ fn x_restore(&mut p1 : &mut %{Self::x, %any} PointExtra, & p2 : & %{Self::saved_ } ``` -or use `where` clause if access is extra verbose: +or use `where` clauses if access is extra verbose: ```rust // case (D6) // FROM case (D5) @@ -280,7 +295,7 @@ fn x_store(&mut p1 : &mut %permit_sv_x PointExtra, & p2 : & %permit_x PointExtra where %permit_sv_x : %{Self::saved_x, %any}, %permit_x : %{Self::x, %any} { - *p1.saved_x = *p2.x + *p1.saved_x = *p2.x; } fn x_restore(&mut p1 : &mut %permit_x PointExtra, & p2 : & %permit_sv_x PointExtra) @@ -291,7 +306,7 @@ fn x_restore(&mut p1 : &mut %permit_x PointExtra, & p2 : & %permit_sv_x PointExt } ``` -or add `type` +or add `type` synonym ```rust // case (D7) // FROM case (D5) @@ -301,7 +316,7 @@ type PointX = %{Self::x, %any} PointExtra; fn x_store(&mut p1 : &mut PointSaveX, & p2 : & PointX) { - *p1.saved_x = *p2.x + *p1.saved_x = *p2.x; } fn x_restore(&mut p1 : &mut PointX, & p2 : & PointSaveX) { @@ -309,7 +324,9 @@ fn x_restore(&mut p1 : &mut PointX, & p2 : & PointSaveX) { } ``` -Implementation parameters are mostly same: +### Partial parameters on implementations + +Implementation parameters are mostly same, but we use Self as "outer Self" type: ```rust // case (D8) impl Point { @@ -333,39 +350,6 @@ We could also use multiple sub-parameters of same parameter } ``` -Now type access guarantee to compiler, that only some fields has an access inside function, but not the rest of them. -So, no extra lock on `self` is needed, only for `%permit` fields. - -Now compiler can catch "out of scope parameter" errors -```rust -// case (D10) - pub fn xt_refmut(&self : &mut %{Self::xt, %any} Self) -> &mut f64 { - // ^~~~~~ - // error: no field 'Self::xt' on type `Self` - &mut self.xt - } -``` - -Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error: -```rust -// case (D11) - pub fn t_refmut(&self : &mut %{Self::t, %any} Self) -> &mut f64 { - &mut self.x - // ^~~~~~ - // error: cannot find value 'Self::x' in this scope - } -``` - -Compile could catch more dead code warnings -```rust -// case (D12) - pub fn x_refmut(&self : &mut %{Self::x, Self::y, %any} Self) -> &mut f64 { - // ^~~~~~ - // warning: '#[warn(dead_code)]' field is never read: `Self::y` - &mut self.x - } -``` - ## Several selfs If we want to include `x_store` and `x_restore` from case (D5) for implementation we find something weird: we need **several** selfs! @@ -403,6 +387,41 @@ Sure, if we use several `self`s, their fit fileds access cannot overlap! } ``` +### Partial parameter errors + +Now type access guarantee to compiler, that only some fields has an access inside function, but not the rest of them. +So, no extra lock on `self` is needed, only for `%permit` fields. + +Now compiler can catch "out of scope parameter" errors +```rust +// case (D10) + pub fn xt_refmut(&self : &mut %{Self::xt, %any} Self) -> &mut f64 { + // ^~~~~~ + // error: no field 'Self::xt' on type `Self` + &mut self.xt + } +``` + +Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error: +```rust +// case (D11) + pub fn t_refmut(&self : &mut %{Self::t, %any} Self) -> &mut f64 { + &mut self.x + // ^~~~~~ + // error: cannot find value 'Self::x' in this scope + } +``` + +Compile could catch more dead code warnings +```rust +// case (D12) + pub fn x_refmut(&self : &mut %{Self::x, Self::y, %any} Self) -> &mut f64 { + // ^~~~~~ + // warning: '#[warn(dead_code)]' field is never read: `Self::y` + &mut self.x + } +``` + Fortunately, these additions is enough to write **any safe** function declarations. @@ -475,6 +494,8 @@ let move_x45 = %{Self::{f4, f5}, %cut} x; But `%deny Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny Self::_`. +### Max access filter + What to do if we wish to create a reference to `ref_x23`. Do we need to write explicitly an access or exists implicit way? No, we could use `%max`(or `%id`) - qualified safe filter with maximum profit-fields, but technically is an `id` filter to variable access: @@ -496,6 +517,8 @@ let refref_x23 = & %max ref_x23; // refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; ``` +### Min access filter + For function argument we add another filter `%min` - qualified safe filter with minimum profit-fields, but it refers not to variable access, but to parameter access, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! | param access | `%min` | @@ -530,7 +553,7 @@ p3.update_sametype(&mut %min p2); ``` -## Partially Initialized Variables +### Partially Initialized Variables We must have an ability to create partially initilized variables. So we need to add a filter-access to a constructor From 61334788f1a01b8ec10840ea49336cf59464e040 Mon Sep 17 00:00:00 2001 From: law Date: Wed, 19 Apr 2023 14:10:13 +0300 Subject: [PATCH 09/13] upd Enum --- text/0000-partial_types.md | 118 ++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 66 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 3d0cf74ea2e..0bde4070554 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -37,7 +37,6 @@ This proposal [guide-level-explanation]: #guide-level-explanation - [Partial types by type access] - - [Access variants and parameters in Trait] - [Detailed access] - [Detailed Struct Type] - [Detailed Primitive Types] @@ -48,6 +47,7 @@ This proposal - [Partial parameter styles] - [Partial parameters on implementations] - [Several selfs] + - [Partial parameters via Access variants] - [Partial parameter errors] - [Partial not consumption] - [Max access filter] @@ -59,10 +59,10 @@ This proposal ```rust // case (A1) -let foo : i16 = 0; +let mut foo : mut i16 = 0; ``` -What is a **full type** of `foo`? Is it the `i16`? No, the `i16` is a sub-full_type in Rust type-system. +The **full type** in Rust is next: ```rust // case (A2) : ; @@ -79,39 +79,25 @@ I propose to extend type system by adding type access to sub-type. So, our varia // case (A5) // FROM case (A1) -// foo : %full i16; -// foo : i16; +// foo : mut %full i16; +// foo : mut i16; ``` Lifetime variants are `'static` (for static lifetime), `'_`(don't care lifetime) and any other `'b`(some "b" lifetime). By the same analogy, access has similar names and meanings: `%full`(full access, soft keyword), `%_`(don't care how partial access is, soft keyword), `%empty` or `%!` (no access, soft keyword) and any other `%a`(some "a" access). -Symbol `%` percent mean percent or part of the whole thing (variable in our case). - -_Note: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type access._ - - -## Access variants and parameters in Trait - -We could already write Traits with **safe** abstract functions (with no body), which consumes partial access type having only variants of type access. -```rust -// case (B1) -pub trait Upd { - type UpdType; +If we omit to write type access, it means `%full` access. - fn summarize<%a>(&self: & %a Self) -> String; +Symbol `%` percent mean percent or part of the whole thing (variable in our case). - fn update_value<%a>(&mut self : &mut %a Self, newvalue: UpdType); +_Note: It is highly recommended to deprecate operator `%` as a remainder function (it is still no ambiguities to write "`\s+%\s+`"), and replace it with another operator (for example: `%mod` / `%rem` / `mod` / `rem`) to not to be confused by type access. But it is not a mandatory._ - fn update_sametype<%a, %b>(&mut self : &mut %a Self, &another: & %b Self); -} -``` +## Detailed access Unfortunately, having variants of type access is not enough to write **safe** implementations or other non-abstract function declarations. -## Detailed access -We need to have detailed access to write non-abstract specific type parameters in function, including trait implementation. +We need to have more specific access by detailed access. ### Detailed Struct Type @@ -142,11 +128,11 @@ Where : - `::*` is an "every field" quasi-field - `::{, , }` is an field-set quasi-field -We assume, that each field could be in one of two specific field-accesss - `%permit` and `%deny`. +We assume, that each field could be in one of two specific field-access - `%permit` and `%deny`. We also must reserve as a keyword a `%miss` field-access for future ReExtendeded Partial Types, which allows to create **safe** self-referential types. -`%permit` is default field-access and it means we have an access to this field and could use it as we wish. But if we try to access to `%deny` field it cause a compiler error. +`%permit` is default field-access (if we omit to write specific field-access) and it means we have an access to this field and could use it as we wish. But if we try to access to `%deny` field it cause a compiler error. ```rust // case (C2) @@ -210,37 +196,15 @@ Unfortunately, Arrays are a bit magical, so it is _unclear_ if we could represen What's about Enums? -It is more complicated, then `struct` types, because we grant some **type** access, not **value** access! +It is more complicated then `struct` types, because we grant some **type** access, not a **value** access! -So, all possible constructors are permitted! But, we could deny sub-fields! -```rust -enum WebEvent { - PageLoad, - PageUnload, - - KeyPress(char), - Paste(String), - - Click { x: i64, y: i64 }, -} +Enum is not a "Product" Type, but a "Sum" Type. -// case (C5) -let a = WebEvent::PageLoad; - // - // a : WebEvent; - // a : %full WebEvent; - // a : %{Self::*::*} WebEvent; - // a : %{%permit Self::{PageLoad, PageUnload}::self, %permit Self::{KeyPress, Paste}::0, %permit Self::Click::{x, y}} WebEvent; -``` -where - - `::self` quasi-field for unit types, since `PageLoad`/`PageUnload` is not a `struct` - - `::0` is like mono-tuple field for `KeyPress(char)` and `Paste(String)` - - It is a compile error if we try to `%deny` a `::self` field! +So, all possible constructors are permitted! ## Partial parameters -We add enough access, and could write partial parameters for non-abstract function declarations: +We add enough access, and could write partial parameters for function declarations: ```rust // case (D1) fn re_ref_t (& p : & %{Self::t, %ignore Self::_} Point) -> &f64 { @@ -258,9 +222,16 @@ Where : But `%ignore Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore Self::_`. +Since using `%ignore` filed in the function body is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error. + +Now type access guarantee to compiler, that only some fields has an access inside function, but not the rest of them. +So, no extra lock on `self` is needed, only for `%permit` fields. + ### Partial parameter styles -We could write partial parameters using different style. Ordinary one: +We could write partial parameters using different styles. + +Default one: ```rust // case (D3) @@ -326,7 +297,7 @@ fn x_restore(&mut p1 : &mut PointX, & p2 : & PointSaveX) { ### Partial parameters on implementations -Implementation parameters are mostly same, but we use Self as "outer Self" type: +Writing Implementation parameters is mostly the same, but we use Self type as "outer Self" type: ```rust // case (D8) impl Point { @@ -376,21 +347,34 @@ trait St { } ``` -Sure, if we use several `self`s, their fit fileds access cannot overlap! +Sure, if we use several `self`s, their permit fileds access cannot overlap! ```rust // case (E3) pub fn x2_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::x, %any} Self) { // ^~~~~~ ^~~~~ - // error: cannot overlap fit-field 'Self::x' on self1 and self2 + // error: cannot overlap permit-field 'Self::x' on self1 and self2 *self1.x = *self2.x; } ``` -### Partial parameter errors +### Partial parameters via Access variants -Now type access guarantee to compiler, that only some fields has an access inside function, but not the rest of them. -So, no extra lock on `self` is needed, only for `%permit` fields. +We could write Traits with **safe** abstract functions (with no body), which consumes partial access type having only variants of type access. +```rust +// case (B1) +pub trait Upd { + type UpdType; + + fn summarize<%a>(&self: & %a Self) -> String; + + fn update_value<%a>(&mut self : &mut %a Self, newvalue: UpdType); + + fn update_sametype<%a, %b>(&mut self : &mut %a Self, &another: & %b Self); +} +``` + +### Partial parameter errors Now compiler can catch "out of scope parameter" errors ```rust @@ -498,7 +482,7 @@ But `%deny Self::_` quasi-filed-access of quasi-field looks annoying, so we simp What to do if we wish to create a reference to `ref_x23`. Do we need to write explicitly an access or exists implicit way? -No, we could use `%max`(or `%id`) - qualified safe filter with maximum profit-fields, but technically is an `id` filter to variable access: +No, we could use `%max`(or `%id`) - qualified safe filter with maximum permit-fields, but technically is an `id` filter to variable access: | var access | `%max` | |--------------|-----------| @@ -519,7 +503,7 @@ let refref_x23 = & %max ref_x23; ### Min access filter -For function argument we add another filter `%min` - qualified safe filter with minimum profit-fields, but it refers not to variable access, but to parameter access, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! +For function argument we add another filter `%min` - qualified safe filter with minimum permit-fields, but it refers not to variable access, but to parameter access, so we could use it in arguments consumption only! It is an compile error if `%min` is written outside of contents! | param access | `%min` | |---------------|-----------| @@ -555,7 +539,7 @@ p3.update_sametype(&mut %min p2); ### Partially Initialized Variables -We must have an ability to create partially initilized variables. So we need to add a filter-access to a constructor +We must have an ability to create partially initialized variables. So we need to add a filter-access to a constructor ```rust struct Point { @@ -584,7 +568,7 @@ let p_yz = %{Self::{y,z}, %cut} Point {y:1.0, z: 2.0}; // ``` -Also it could be nice if constructor allows several filler variables (which do not overlap fit-fields) +Also it would be nice if constructor allows several filler variables (which do not overlap permit-fields) ```rust // case (G3) let p_xyz = %max Point {..p_x, ..p_yz}; @@ -611,18 +595,20 @@ access filter could help to deconstruct types for matching: ```rust // case (G6) -let opt_t4_1 = Some (%{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); +let opt_t4_1 = Some ( %{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); // // opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; // let Some (%{Self::1, %cut} (_, ref y, _, _)) = opt_t4_1; ``` +If we try to write not "`_`" on deny accessed fields, but a variable - it is a compile error. + ## Private fields And finally, what to do with private fields? -If variable has private field, it is an always `%hidden Self::private` quasi-field. +If variable has private fields, it has always at access `%hidden Self::private` quasi-field. ```rust pub struct HiddenPoint { pub x: f64, @@ -646,7 +632,7 @@ Where : - `%hidden<%a>` - it is some specific `%a` quasi field access, but we have no access to specify it - `%private` is a shortcut for `%hidden<%full> Self::private` -So, more fully we could write for struct witj private fields: +So, more fully we could write for struct with private fields: - `%empty : %{%deny Self::pub, %hidden<%empty> Self::private}` access - `%full : %{%permit Self::pub, %hidden<%full> Self::private}` access From d68339a8507bcfe0e54b813cae4d3a81ae05d94b Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Fri, 21 Apr 2023 03:53:52 +0300 Subject: [PATCH 10/13] add user-friendly Guide-level explanation --- text/0000-partial_types.md | 158 +++++++++++++++++++++++-------------- 1 file changed, 100 insertions(+), 58 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 0bde4070554..0ff13952314 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -11,8 +11,6 @@ Partial types proposal is a generalization on "partial borrowing"-like proposals This proposal is a universal road-map "how to do partial not consumption (including partial not borrowing) right", and not under the hood of the Rust compiler. -Partial Types is a **minimal** and full extension to the Rust Type System, which allows to safe control easily partial parameters and all kinds of partial not consumption. - Advantages: maximum type safety, maximum type control guarantee, no ambiguities, flexibility, usability and universality. @@ -21,21 +19,80 @@ Advantages: maximum type safety, maximum type control guarantee, no ambiguities, Safe, Flexible controllable partial parameters for functions and partial not consumption (including partial not borrowing) are highly needed and this feature unlock huge amount of possibilities. -Partial borrowing is already possible in Rust, as partial referencing and partial moves. - But partial parameters are forbidden now, as qualified consumption: partial not borrowing, partial not referencing, partial not moving and partial initializing. -This proposal -1) It is full backward-compatible. -2) It adds some **safe** flexibility to **safe** code by **safe** methods. -3) It has simplicity in binary - Type access just say by type to compiler, that some fields are forbidden to use _for everyone ever_. And that allows to use ordinary references as "partial" and ordinal variables as "partial". No extra actions with variables or pointers are needed. -4) Any type error is a compiler error, all types are erased after type-check, so no extra-cost in binary is needed. -5) It has universal rule - that mean minimal special cases on implementation. -6) It is minimal universal-extension - all other proposals propose less than this with more or same cost +Partial Types extension gives to type-checker a **mathematical guarantee** that using simultaneously partial typed variable, it multiple references and borrowing is as **safe** as using them at a sequence. + +And since it is guarantee by **type**, not by **values**, it has _zero cost_ in binary. + +Any type error is a compiler error, so no errors in runtime. + +We could apply _theoretically_ this extension to all Product Types (`PT = T1 and T2 and T3 and ...`). + +So, most promised candidates are Structs and Tuples. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation +Let we have a structure: +```rust +struct Point { + x: f64, + y: f64, + was_x: f64, + was_y: f64 +} +let mut pfull = Point {x: 1.0, y: 2.0, was_x: 4.0, was_y: 5.0}; +``` + +If we need to write a function, that use partial parameters we write: +```rust +// partial parameters +type PointJustX = %{Self::x, %any} Point; +type PointJustWasX = %{Self::was_x, %any} Point; + +fn x_restore(&mut p1 : &mut PointJustWasX, & p2 : & PointJustX) { + *p1.x = *p2.was_x; +} +``` +Which mean that `p1` parameters could use variables with any partial type of `Point`, which has permit access to field `was_x` and we don't care of rest fields. And `p2` parameters could use variables with any partial type of `Point`, which has permit access to field `x` and we don't care of rest fields. + +If we try to use same variable simultaneously for that, we must insert arguments partially - we cut type by `%min` access-filter: +```rust +x_restore(&mut %min pfull, & %min pfull); +``` +If we wish to write same function via implementation, we need several selves! +```rust +impl Point { + pub fn x_restore(&mut self1 : &mut %{Self::saved_x, %any} Self, &self2 : & %{Self::x, %any} Self) { + *self1.x = *self2.saved_x; + } +``` +Why it is useful? If we need several functions which read common field, but mutually write different fields we could use them together! +```rust +pub fn mf1_rfc(&mut self1 : &mut %{Self::fld1, %any} Self, &self2 : & %{Self::common, %any} Self) +{ /* ... */ } + +pub fn mf2_rfc(&mut self1 : &mut %{Self::fld2, %any} Self, &self2 : & %{Self::common, %any} Self) +{ /* ... */ } +``` + +And Partial Types have more. They are not limited to parameters/arguments only. + +```rust +let ref_was = & %{Self::was_x, Self::was_y, %cut} pfull; + +let brwd_now = &mut %{Self::x, Self::y, %cut} pfull; + +let refref_was = & %max ref_was; +``` +So we have a read-only reference to "was"-fields and mutable "now"-fields. + +It is easy, useful and universal! + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + - [Partial types by type access] - [Detailed access] - [Detailed Struct Type] @@ -55,32 +112,26 @@ This proposal - [Partially Initialized Variables] - [Private fields] + ## Partial types by type access ```rust +struct PointXY { + x: f64, + y: f64, +} // case (A1) -let mut foo : mut i16 = 0; +let mut foo : mut PointXY = PointXY {x:11.0, y:2.0}; ``` -The **full type** in Rust is next: -```rust -// case (A2) - : ; - : ; - : <'lifetime> ; -``` - -I propose to extend type system by adding type access to sub-type. So, our variable will have next full type: +I propose to extend type system by adding type access to sub-type. So, our variable will have next type: ```rust -// case (A4) - : <%access> ; - : <'lifetime> <%access> ; - -// case (A5) +// case (A2) // FROM case (A1) -// foo : mut %full i16; -// foo : mut i16; +// foo : mut PointXY; +// foo : mut %a PointXY; +// foo : mut %full PointXY; ``` Lifetime variants are `'static` (for static lifetime), `'_`(don't care lifetime) and any other `'b`(some "b" lifetime). @@ -100,8 +151,7 @@ Unfortunately, having variants of type access is not enough to write **safe** im We need to have more specific access by detailed access. ### Detailed Struct Type - -What's about structures? +Let's try simple uninhabited type We need for this some new quasi-fields and some field access (which should be soft keywords). ```rust @@ -128,9 +178,26 @@ Where : - `::*` is an "every field" quasi-field - `::{, , }` is an field-set quasi-field +```rust +// case (B1) +struct Nothing {} + +let mut bar : mut Nothing = Nothing {}; + // + // bar : Nothing + // bar : %full Nothing; + // bar : %{Self::*} Nothing; + // bar : %{Self::self} Nothing; + // bar : %{%permit Self::self} Nothing; +``` +Where : + - `::self` a single quasi-field for uninhabited structs + +It is a compile error if we try to %deny a ::self field! + We assume, that each field could be in one of two specific field-access - `%permit` and `%deny`. -We also must reserve as a keyword a `%miss` field-access for future ReExtendeded Partial Types, which allows to create **safe** self-referential types. +_We also must reserve as a keyword a `%miss` field-access for future ReExtendeded Partial Types, which allows to create **safe** self-referential types._ `%permit` is default field-access (if we omit to write specific field-access) and it means we have an access to this field and could use it as we wish. But if we try to access to `%deny` field it cause a compiler error. @@ -153,25 +220,6 @@ As we see, - `%empty : %{%deny Self::*}` or `%empty : %{}` access - `%full : %{%permit Self::*}` or `%full : %{Self::*}` access -### Detailed Primitive Types - -Primitive types (numbers, units) and not-detailed yet types do not have internal structure. Their access is always `%full` - -For them we assume that **every** variable is a `struct`-like objects (even if it is not) and has a single quasi-field - `::self`. - -It is a compile error if we try to `%deny` a `::self` field! - -```rust -// case (C3) -let foo = 0i16; - // - // foo : i16 - // foo : %full i16; - // foo : %{Self::*} i16; - // foo : %{Self::self} i16; - // foo : %{%permit Self::self} i16; -``` - ### Detailed Tuples For Tuples we assume that **every** variable is a `struct`-like objects (even if it is not) and has unnamed numbered fields. @@ -194,11 +242,9 @@ Unfortunately, Arrays are a bit magical, so it is _unclear_ if we could represen ### Detailed Enum Type -What's about Enums? - -It is more complicated then `struct` types, because we grant some **type** access, not a **value** access! +What's about Enums? Enum is not a "Product" Type, but a "Sum" Type (`ST = T1 or T2 or T3 or ..`). -Enum is not a "Product" Type, but a "Sum" Type. +But this proposal grant some **type** access, not a **value** access! So, all possible constructors are permitted! @@ -637,10 +683,6 @@ So, more fully we could write for struct with private fields: - `%full : %{%permit Self::pub, %hidden<%full> Self::private}` access -# Reference-level explanation -[reference-level-explanation]: #reference-level-explanation - - # Drawbacks [drawbacks]: #drawbacks From d5fe5145bb2a35b28ac044566e44d84aa73cb357 Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Fri, 21 Apr 2023 04:09:59 +0300 Subject: [PATCH 11/13] minor --- text/0000-partial_types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 0ff13952314..0d3e074bf9a 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -45,7 +45,7 @@ struct Point { let mut pfull = Point {x: 1.0, y: 2.0, was_x: 4.0, was_y: 5.0}; ``` -If we need to write a function, that use partial parameters we write: +If we need to write a function, which use partial parameters: ```rust // partial parameters type PointJustX = %{Self::x, %any} Point; From 15d378db8f06b29f8a7be741dc4e4e3ba169a7bd Mon Sep 17 00:00:00 2001 From: VitWW <130038091+VitWW@users.noreply.github.com> Date: Fri, 21 Apr 2023 05:42:45 +0300 Subject: [PATCH 12/13] set %max as omitted filter to consumers, not %full --- text/0000-partial_types.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 0d3e074bf9a..09b6dd14ec9 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -84,7 +84,7 @@ let ref_was = & %{Self::was_x, Self::was_y, %cut} pfull; let brwd_now = &mut %{Self::x, Self::y, %cut} pfull; -let refref_was = & %max ref_was; +let refref_was = & ref_was; ``` So we have a read-only reference to "was"-fields and mutable "now"-fields. @@ -474,9 +474,9 @@ Partial access to the field is already granted (exept arrays). Rust consumer use same names for action and for type clarifications, so we follow this style. -We need to add access filter to them, ignoring it mean `%full` filter (Ok, it is a bit unclear which is a default filter - `%full` or `%max`)! +We need to add access filter to them, omiting it mean `%max` filter. Since it is not possibe to consume more than `%max`, it has no sence to use `%full` instead! -`%full` means consumer consume all fields. +`%full` means consumer consume all fields, `%max` consume all permited fields. ```rust struct A { f1: String, f2: String, f3: String } @@ -542,7 +542,8 @@ Having this we could write next implicitly // ref_x23: & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; // case (F4) -let refref_x23 = & %max ref_x23; +let refref_x23 = & ref_x23; +// it mean '& %max ref_x23', not '& %full ref_x23' // // refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; ``` @@ -585,7 +586,8 @@ p3.update_sametype(&mut %min p2); ### Partially Initialized Variables -We must have an ability to create partially initialized variables. So we need to add a filter-access to a constructor +We must have an ability to create partially initialized variables. So we need to add a filter-access to a constructor. +Default access-fiter to constructor is `%full`, not `%max`. ```rust struct Point { @@ -645,7 +647,8 @@ let opt_t4_1 = Some ( %{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); // // opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; // - let Some (%{Self::1, %cut} (_, ref y, _, _)) = opt_t4_1; + let Some (%max (_, ref y, _, _)) = opt_t4_1; + // ^~~~~~~~~~^~~^~~~ if we writee variables here, it cause an error ``` If we try to write not "`_`" on deny accessed fields, but a variable - it is a compile error. @@ -715,8 +718,7 @@ Most languages don't have such strict rules for references and links as Rust, so # Unresolved questions [unresolved-questions]: #unresolved-questions -Default qualified consumption is `%full` on Stage 1. It fully backward compatible and allow to switch cost-less to `%max` default! -But maybe it is not a good choice. As default argument consumption is `%full`, but not `%min`. +None known. # Future possibilities [future-possibilities]: #future-possibilities From 4f343c336b0032751047a4326d51fa05f070e8a2 Mon Sep 17 00:00:00 2001 From: law Date: Fri, 21 Apr 2023 18:29:36 +0300 Subject: [PATCH 13/13] remove Self:: --- text/0000-partial_types.md | 197 +++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 105 deletions(-) diff --git a/text/0000-partial_types.md b/text/0000-partial_types.md index 09b6dd14ec9..057e8e479ec 100644 --- a/text/0000-partial_types.md +++ b/text/0000-partial_types.md @@ -48,8 +48,8 @@ let mut pfull = Point {x: 1.0, y: 2.0, was_x: 4.0, was_y: 5.0}; If we need to write a function, which use partial parameters: ```rust // partial parameters -type PointJustX = %{Self::x, %any} Point; -type PointJustWasX = %{Self::was_x, %any} Point; +type PointJustX = %{x, %any} Point; +type PointJustWasX = %{was_x, %any} Point; fn x_restore(&mut p1 : &mut PointJustWasX, & p2 : & PointJustX) { *p1.x = *p2.was_x; @@ -64,25 +64,25 @@ x_restore(&mut %min pfull, & %min pfull); If we wish to write same function via implementation, we need several selves! ```rust impl Point { - pub fn x_restore(&mut self1 : &mut %{Self::saved_x, %any} Self, &self2 : & %{Self::x, %any} Self) { + pub fn x_restore(&mut self1 : &mut %{saved_x, %any} Self, &self2 : & %{x, %any} Self) { *self1.x = *self2.saved_x; } ``` Why it is useful? If we need several functions which read common field, but mutually write different fields we could use them together! ```rust -pub fn mf1_rfc(&mut self1 : &mut %{Self::fld1, %any} Self, &self2 : & %{Self::common, %any} Self) +pub fn mf1_rfc(&mut self1 : &mut %{fld1, %any} Self, &self2 : & %{common, %any} Self) { /* ... */ } -pub fn mf2_rfc(&mut self1 : &mut %{Self::fld2, %any} Self, &self2 : & %{Self::common, %any} Self) +pub fn mf2_rfc(&mut self1 : &mut %{fld2, %any} Self, &self2 : & %{common, %any} Self) { /* ... */ } ``` And Partial Types have more. They are not limited to parameters/arguments only. ```rust -let ref_was = & %{Self::was_x, Self::was_y, %cut} pfull; +let ref_was = & %{was_x, was_y, %cut} pfull; -let brwd_now = &mut %{Self::x, Self::y, %cut} pfull; +let brwd_now = &mut %{x, y, %cut} pfull; let refref_was = & ref_was; ``` @@ -168,15 +168,12 @@ let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; // // p1 : &mut Point; // p1 : &mut %full Point; - // p1 : &mut %{Self::*} Point; - // p1 : &mut %{Self::x, Self::y, Self::z, Self::t, Self::w} Point; - // p1 : &mut %{Self::{x, y, z, w}} Point; + // p1 : &mut %{*} Point; + // p1 : &mut %{x, y, z, t, w} Point; ``` Where : - - `Self` is an "link" to variable type itself - - `::*` is an "every field" quasi-field - - `::{, , }` is an field-set quasi-field + - `*` is an "every field" quasi-field ```rust // case (B1) @@ -186,12 +183,12 @@ let mut bar : mut Nothing = Nothing {}; // // bar : Nothing // bar : %full Nothing; - // bar : %{Self::*} Nothing; - // bar : %{Self::self} Nothing; - // bar : %{%permit Self::self} Nothing; + // bar : %{*} Nothing; + // bar : %{self} Nothing; + // bar : %{%permit self} Nothing; ``` Where : - - `::self` a single quasi-field for uninhabited structs + - `self` a single quasi-field for uninhabited structs It is a compile error if we try to %deny a ::self field! @@ -206,19 +203,20 @@ _We also must reserve as a keyword a `%miss` field-access for future ReExtendede // FROM case (C1) let &mut p1 : &mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; // - // p1 : &mut %{%permit Self::*} Point; - // p1 : &mut %{%permit Self::*, %deny Self::_}; - // p1 : &mut %{%permit Self::{x, y, z, w}} Point; + // p1 : &mut %{%permit *} Point; + // p1 : &mut %{%permit *, %deny _}; + // p1 : &mut %{%permit {x, y, z, w}} Point; ``` Where : - `%permit` access - `%deny` access - - `::_` is a "rest of fields" quasi-field + - `{, , }` is an field-set quasi-field + - `_` is a "rest of fields" quasi-field As we see, - - `%empty : %{%deny Self::*}` or `%empty : %{}` access - - `%full : %{%permit Self::*}` or `%full : %{Self::*}` access + - `%empty : %{%deny *}` or `%empty : %{}` access + - `%full : %{%permit *}` or `%full : %{*}` access ### Detailed Tuples @@ -230,8 +228,8 @@ let bar = (0i16, &5i32, "some_string"); // // bar : (i16, &i32, &str); // bar : %full (i16, &i32, &str); - // bar : %{Self::*} (i16, &i32, &str); - // bar : %{%permit Self::{0,1,2}} (i16, &i32, &str); + // bar : %{*} (i16, &i32, &str); + // bar : %{%permit {0,1,2}} (i16, &i32, &str); ``` ### Detailed Arrays @@ -253,12 +251,12 @@ So, all possible constructors are permitted! We add enough access, and could write partial parameters for function declarations: ```rust // case (D1) -fn re_ref_t (& p : & %{Self::t, %ignore Self::_} Point) -> &f64 { +fn re_ref_t (& p : & %{t, %ignore _} Point) -> &f64 { &p.t } // case (D2) -fn refmut_w (&mut p : &mut %{Self::w, %any} Point) -> &mut f64 { +fn refmut_w (&mut p : &mut %{w, %any} Point) -> &mut f64 { &mut p.w } ``` @@ -266,7 +264,7 @@ fn refmut_w (&mut p : &mut %{Self::w, %any} Point) -> &mut f64 { Where : - `%ignore` is a "don't care which exactly" quasi filed-access (`%_` is a whole type access and it is unclear if we could use it in both contents) -But `%ignore Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore Self::_`. +But `%ignore _` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%any : %ignore _`. Since using `%ignore` filed in the function body is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error. @@ -282,7 +280,7 @@ Default one: ```rust // case (D3) // FROM case (D1) -fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { +fn re_ref_t (& p : & %{t, %any} Point) -> &f64 { &p.t } @@ -294,11 +292,11 @@ struct PointExtra { saved_y: f64, } -fn x_store(&mut p1 : &mut %{Self::saved_x, %any} PointExtra, & p2 : & %{Self::x, %any} PointExtra) { +fn x_store(&mut p1 : &mut %{saved_x, %any} PointExtra, & p2 : & %{x, %any} PointExtra) { *p1.saved_x = *p2.x; } -fn x_restore(&mut p1 : &mut %{Self::x, %any} PointExtra, & p2 : & %{Self::saved_x, %any} PointExtra) { +fn x_restore(&mut p1 : &mut %{x, %any} PointExtra, & p2 : & %{saved_x, %any} PointExtra) { *p1.x = *p2.saved_x; } ``` @@ -309,15 +307,15 @@ or use `where` clauses if access is extra verbose: // FROM case (D5) fn x_store(&mut p1 : &mut %permit_sv_x PointExtra, & p2 : & %permit_x PointExtra) - where %permit_sv_x : %{Self::saved_x, %any}, - %permit_x : %{Self::x, %any} + where %permit_sv_x : %{saved_x, %any}, + %permit_x : %{x, %any} { *p1.saved_x = *p2.x; } fn x_restore(&mut p1 : &mut %permit_x PointExtra, & p2 : & %permit_sv_x PointExtra) - where %permit_sv_x : %{Self::saved_x, %any}, - %permit_x : %{Self::x, %any} + where %permit_sv_x : %{saved_x, %any}, + %permit_x : %{x, %any} { *p1.x = *p2.saved_x; } @@ -328,8 +326,8 @@ or add `type` synonym // case (D7) // FROM case (D5) -type PointSaveX = %{Self::saved_x, %any} PointExtra; -type PointX = %{Self::x, %any} PointExtra; +type PointSaveX = %{saved_x, %any} PointExtra; +type PointX = %{x, %any} PointExtra; fn x_store(&mut p1 : &mut PointSaveX, & p2 : & PointX) { @@ -347,11 +345,11 @@ Writing Implementation parameters is mostly the same, but we use Self type as "o ```rust // case (D8) impl Point { - pub fn x_refmut(&mut self : &mut %{Self::x, %any} Self) -> &mut f64 { + pub fn x_refmut(&mut self : &mut %{x, %any} Self) -> &mut f64 { &mut self.x } - pub fn y_refmut(&mut self : &mut %{Self::y, %any} Self) -> &mut f64 { + pub fn y_refmut(&mut self : &mut %{y, %any} Self) -> &mut f64 { &mut self.y } } @@ -360,7 +358,7 @@ impl Point { We could also use multiple sub-parameters of same parameter ```rust // case (D9) - pub fn xy_swich(&mut self : &mut %{Self::{x, y}, %any} Self) { + pub fn xy_swich(&mut self : &mut %{{x, y}, %any} Self) { let tmp = *self.x; *self.x = *self.y; *self.y = tmp; @@ -383,12 +381,12 @@ trait St { } // case (E2) - pub fn x_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::saved_x, %any} Self) + pub fn x_store(&mut self1 : &mut %{x, %any} Self, &self2 : & %{saved_x, %any} Self) { *self1.saved_x = *self2.x } - pub fn x_restore(&mut self1 : &mut %{Self::saved_x, %any} Self, &self2 : & %{Self::x, %any} Self) { + pub fn x_restore(&mut self1 : &mut %{saved_x, %any} Self, &self2 : & %{x, %any} Self) { *self1.x = *self2.saved_x; } ``` @@ -397,9 +395,9 @@ Sure, if we use several `self`s, their permit fileds access cannot overlap! ```rust // case (E3) - pub fn x2_store(&mut self1 : &mut %{Self::x, %any} Self, &self2 : & %{Self::x, %any} Self) { + pub fn x2_store(&mut self1 : &mut %{x, %any} Self, &self2 : & %{x, %any} Self) { // ^~~~~~ ^~~~~ - // error: cannot overlap permit-field 'Self::x' on self1 and self2 + // error: cannot overlap permit-field 'x' on self1 and self2 *self1.x = *self2.x; } ``` @@ -425,9 +423,9 @@ pub trait Upd { Now compiler can catch "out of scope parameter" errors ```rust // case (D10) - pub fn xt_refmut(&self : &mut %{Self::xt, %any} Self) -> &mut f64 { + pub fn xt_refmut(&self : &mut %{xt, %any} Self) -> &mut f64 { // ^~~~~~ - // error: no field 'Self::xt' on type `Self` + // error: no field 'xt' on type `Self` &mut self.xt } ``` @@ -435,19 +433,19 @@ Now compiler can catch "out of scope parameter" errors Since using `%ignore` filed is **unsafe by type** (we have no guarantee, that some field is permitted), trying to use ignoring field is a compile error: ```rust // case (D11) - pub fn t_refmut(&self : &mut %{Self::t, %any} Self) -> &mut f64 { + pub fn t_refmut(&self : &mut %{t, %any} Self) -> &mut f64 { &mut self.x // ^~~~~~ - // error: cannot find value 'Self::x' in this scope + // error: cannot find value 'x' in this scope } ``` Compile could catch more dead code warnings ```rust // case (D12) - pub fn x_refmut(&self : &mut %{Self::x, Self::y, %any} Self) -> &mut f64 { + pub fn x_refmut(&self : &mut %{x, y, %any} Self) -> &mut f64 { // ^~~~~~ - // warning: '#[warn(dead_code)]' field is never read: `Self::y` + // warning: '#[warn(dead_code)]' field is never read: `y` &mut self.x } ``` @@ -500,11 +498,11 @@ Trying to consume `%deny` field is a compile error! The consumer DO NOT consume Resulted field access is the following: -| ↓filter / →access | `%permit` | `%deny` | `%hidden` | -|-------------------|-----------|-----------|-----------| -| `%permit` | `%permit` | !ERROR | !ERROR | -| `%deny` | `%deny` | `%deny` | !ERROR | -| `%hidden` | !ERROR | !ERROR | `%hidden` | +| ↓filter / →access | `%permit` | `%deny` | +|-------------------|-----------|-----------| +| `%permit` | `%permit` | !ERROR | +| `%deny` | `%deny` | `%deny` | + ```rust struct S5 { f1: String, f2: String, f3: String, f4: String, f5: String } @@ -513,16 +511,16 @@ let mut x: S5; // case (F3) let ref1: &mut String = &mut x.f1; // -let ref_x23 = & %{Self::f2, Self::f3, %deny Self::_} x; +let ref_x23 = & %{f2, f3, %deny _} x; // - // ref_x23 : & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // ref_x23 : & %{%permit {f2, f3}, %deny {f1, f4, f5}} S5; // -let move_x45 = %{Self::{f4, f5}, %cut} x; +let move_x45 = %{{f4, f5}, %cut} x; // - // move_x45 : %{%permit Self::{f4, f5}, %deny Self::{f1, f2, f3}} S5; + // move_x45 : %{%permit {f4, f5}, %deny {f1, f2, f3}} S5; ``` -But `%deny Self::_` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny Self::_`. +But `%deny _` quasi-filed-access of quasi-field looks annoying, so we simplify a bit adding `%cut : %deny _`. ### Max access filter @@ -534,18 +532,17 @@ No, we could use `%max`(or `%id`) - qualified safe filter with maximum permit-fi |--------------|-----------| | `%permit` | `%permit` | | `%deny` | `%deny` | -| `%hidden` | `%hidden` | Having this we could write next implicitly ```rust // FROM case (F1) - // ref_x23: & %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // ref_x23: & %{%permit {f2, f3}, %deny {f1, f4, f5}} S5; // case (F4) let refref_x23 = & ref_x23; // it mean '& %max ref_x23', not '& %full ref_x23' // - // refref_x23: && %{%permit Self::{f2, f3}, %deny Self::{f1, f4, f5}} S5; + // refref_x23: && %{%permit {f2, f3}, %deny {f1, f4, f5}} S5; ``` ### Min access filter @@ -557,13 +554,12 @@ For function argument we add another filter `%min` - qualified safe filter with | `%permit` | `%permit` | | `%deny` | `%deny` | | `%ignore` | `%deny` | -| `%hidden` | `%hidden` | Implementations always consumes `self` by `%min` filter! ```rust // FROM case (D3) -fn re_ref_t (& p : & %{Self::t, %any} Point) -> &f64 { +fn re_ref_t (& p : & %{t, %any} Point) -> &f64 { &p.t } let mut p1 : mut Point = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; @@ -605,14 +601,14 @@ let p1_full = Point {x:1.0, y:2.0, z:3.0, t:4.0, w:5.0}; // p1_full : %full Point; // case (G2) -let p_x = %{Self::x, %cut} Point {x:1.0}; +let p_x = %{x, %cut} Point {x:1.0}; // - // p_x : %{%permit Self::x, %deny Self::_} Point; + // p_x : %{%permit x, %deny _} Point; // -let p_yz = %{Self::{y,z}, %cut} Point {y:1.0, z: 2.0}; +let p_yz = %{{y,z}, %cut} Point {y:1.0, z: 2.0}; // - // p_yz : %{%permit Self::{y,z}, %deny Self::_} Point; + // p_yz : %{%permit {y,z}, %deny _} Point; // ``` @@ -621,7 +617,7 @@ Also it would be nice if constructor allows several filler variables (which do n // case (G3) let p_xyz = %max Point {..p_x, ..p_yz}; // - // p_xyz : %{%permit Self::{x,y,z}, %deny Self::{t,w}}; + // p_xyz : %{%permit {x,y,z}, %deny {t,w}}; // case (G4) let p2_full = Point {t:1.0, w:2.0, ..p_xyz}; @@ -634,18 +630,18 @@ A bit unclear how to fill unused fields, so we write unused values to a fill the ```rust // case (G5) -let t4_02 = %{Self::{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); +let t4_02 = %{{0,2}, %cut} ("str", 1i32, &0u16, 0.0f32); // - // t4_02 : %{%permit Self::{0,2}, %deny Self::{1,3}} (&str, i32, &u16, f32); + // t4_02 : %{%permit {0,2}, %deny {1,3}} (&str, i32, &u16, f32); ``` access filter could help to deconstruct types for matching: ```rust // case (G6) -let opt_t4_1 = Some ( %{Self::1, %cut} ("str", 1i32, &0u16, 0.0f32)); +let opt_t4_1 = Some ( %{1, %cut} ("str", 1i32, &0u16, 0.0f32)); // - // opt_t4_1 : Option<%{%permit Self::{1}, %deny Self::{1,3}} (&str, i32, &u16, f32)>; + // opt_t4_1 : Option<%{%permit {1}, %deny {1,3}} (&str, i32, &u16, f32)>; // let Some (%max (_, ref y, _, _)) = opt_t4_1; // ^~~~~~~~~~^~~^~~~ if we writee variables here, it cause an error @@ -657,35 +653,26 @@ If we try to write not "`_`" on deny accessed fields, but a variable - it is a c And finally, what to do with private fields? -If variable has private fields, it has always at access `%hidden Self::private` quasi-field. +If variable has private fields, it has always at access `%hidden private` quasi-field. ```rust -pub struct HiddenPoint { - pub x: f64, - pub y: f64, - z: f64, - t: f64, - w: f64, +mod hp { + pub struct HiddenPoint { + pub x: f64, + pub y: f64, + z: f64, + t: f64, + w: f64, + } } +use hp::HiddenPoint; + // case (H1) let p1 : HiddenPoint; // p1 : %full HiddenPoint; - // p1 : %{%permit Self::pub, %private} HiddenPoint; - // p1 : %{%permit Self::{x, y}, %private} HiddenPoint; - // p1 : %{%permit Self::{x, y}, %hidden<%full> Self::private} HiddenPoint; + // p1 : %{%permit *} HiddenPoint; ``` -Where : - - `::pub` is a "all public fields" quasi-field - - `::private` is a "all private fields" quasi-field - - `%hidden<%a>` - it is some specific `%a` quasi field access, but we have no access to specify it - - `%private` is a shortcut for `%hidden<%full> Self::private` - -So, more fully we could write for struct with private fields: - - `%empty : %{%deny Self::pub, %hidden<%empty> Self::private}` access - - `%full : %{%permit Self::pub, %hidden<%full> Self::private}` access - - # Drawbacks [drawbacks]: #drawbacks @@ -735,13 +722,13 @@ Partly self-referential types example: ```rust struct SR { val : T, - lnk : & T, // reference to Self::val + lnk : & T, // reference to val } // case (FP1) -let x = %{%miss Self::lnk, %permit Self::_} SR {val : 5i32 }; +let x = %{%miss lnk, %permit _} SR {val : 5i32 }; // - // x : %{%miss Self::lnk, %permit Self::val} SR + // x : %{%miss lnk, %permit val} SR // x.lnk %%= & x.val; // @@ -749,19 +736,19 @@ x.lnk %%= & x.val; // x : %full SR; ``` And even AlmostFully self-referential types: -And another shortcut `%unfill : %miss Self::_` +And another shortcut `%unfill : %miss _` ```rust struct FSR { val : T, - lnk : & %{%deny Self::lnk, %permit Self::val} FSR, + lnk : & %{%deny lnk, %permit val} FSR, // reference to almost self! } // case (FP2) -let x = %{Self::val, %unfill} FSR {val : 5i32 }; +let x = %{val, %unfill} FSR {val : 5i32 }; // - // x : %{%miss Self::lnk, %permit Self::val} FSR; + // x : %{%miss lnk, %permit val} FSR; // x.lnk %%= & %max x; // @@ -776,10 +763,10 @@ Second and most difficult, that `return` consumption (yes, 6th type of consumers ```rust // case (FP3) // FROM case (FP2) -fn create_var()-> %{%miss Self::lnk, %permit Self::_} FSR { - let x = %{Self::val, %unfill} FSR {val : 5i32 }; +fn create_var()-> %{%miss lnk, %permit _} FSR { + let x = %{val, %unfill} FSR {val : 5i32 }; // - // x : %{%miss Self::lnk, %permit Self::val} FSR + // x : %{%miss lnk, %permit val} FSR // %max_miss return x; // filter access before 'return' to not to confused with `move` consumer!