digitalmars.D - Thoughts on safe GC-less slices
- Ben Jones (56/56) Nov 16 2021 After being inspired by some good ideas in a few of the other
- Paul Backus (7/19) Nov 16 2021 This is basically the same lowering already provided by
- Ben Jones (4/10) Nov 16 2021 Good point, although `let` would allow you to do arbitrary
- Paul Backus (16/29) Nov 16 2021 You misunderstand. All the compiler does when you implement
- Ben Jones (6/10) Nov 16 2021 Ah, gotcha.
After being inspired by some good ideas in a few of the other threads I distilled some of my thoughts on some ideas about how to get safe slices without GC. I think it's kind of moon-shot-y and will probably not be backwards compatible, but wanted to share. Currently slices conflate 2 different ideas: a view of a range of memory, and ownership of a range of memory. I'd say it's sort of analogous to both std::vector and a pair of iterators in C++. I'm not sure there's a good way to do both things safely with a single type without GC due since the iterators can become unknowingly invalidated. An analogous situation in D is objects vs `ref`s. D avoids the "iterator invalidation" problem by not allowing ref variables, only ref parameters. Because of that, the lifetime of the object is guaranteed to outlive the `ref` to that object. So, one way to potentially have a GC-less dynamic array would be to define 2 different types: an owning slice and a borrowing slice. You can store values of an owning slice, but borrowing slices can only be passed to functions. That's sort of the solution that I think Paul Backus proposed where instead of returning a slice, the RCSlice type (or whatever it was) took a delegate to operate on the slice, which enforced that lifetime constraint. His idea is what prompted me to write this. The syntax for that is obviously not great, but we might be able to do better by stealing from functional languages. Perhaps something like this: ``` let (borrowedSlice; owningSlice) in { //code } ``` mean essentially the same as ``` owningSlice.apply( (borrowedSlice) => { //code} ); ``` One way to implement this is to have owningSlice implement opLet (this is similar to (I think?) Andrei's opFunctionCall idea) The safety provided here seems to align pretty well with what's in the live implementation as it's mostly about passing `scope` stuff to functions. Can it be implemented without horrendous breakage? Probably not. Ideally the existing `[]` could be used for both types of slice depending on context. Some thoughts on how to transition: * All slice variables become owning slices * Owning slice should have to be assigned from unique rvalues like from `.dup` or `new` * It's OK to shrink a borrowed slice, but attempting to grow one would make a new owning slice or nor be allowed, I think I originally thought this might be related to/helpful for an RC slice, but that's not really the same thing. In that case, I think you'd have multiple "owningslice-like" objects that are related and you'd still use opLet to work with them as necessary. Any ideas here worth exploring further? Feel free to discuss [on github](https://gist.github.com/benjones/fa015904eba3e2a7ce1a75b3f6506cc7) if you prefer.
Nov 16 2021
On Tuesday, 16 November 2021 at 23:31:47 UTC, Ben Jones wrote:The syntax for that is obviously not great, but we might be able to do better by stealing from functional languages. Perhaps something like this: ``` let (borrowedSlice; owningSlice) in { //code } ``` mean essentially the same as ``` owningSlice.apply( (borrowedSlice) => { //code} ); ```This is basically the same lowering already provided by [`opApply`][1]. The only differences are - `opApply` returns an integer code (used for control flow) rather than the return value of the callback. - `opApply` uses the `foreach` keyword instead of `let`. [1]: https://dlang.org/spec/statement.html#foreach-statement
Nov 16 2021
On Wednesday, 17 November 2021 at 01:33:46 UTC, Paul Backus wrote:This is basically the same lowering already provided by [`opApply`][1]. The only differences are - `opApply` returns an integer code (used for control flow) rather than the return value of the callback. - `opApply` uses the `foreach` keyword instead of `let`. [1]: https://dlang.org/spec/statement.html#foreach-statementGood point, although `let` would allow you to do arbitrary indexing and sub-slicing with the borrowed as opposed to looping through the whole slice in order.
Nov 16 2021
On Wednesday, 17 November 2021 at 02:08:44 UTC, Ben Jones wrote:On Wednesday, 17 November 2021 at 01:33:46 UTC, Paul Backus wrote:You misunderstand. All the compiler does when you implement `opApply` is transform code that looks like this: ```d foreach (a; b) { /* stuff */ } ``` ...into code that looks like this: ```d b.opApply((a) { /* stuff */ }) ``` It is entirely possible to write an `opApply` method that does not do any looping, and only calls its delegate argument once--just like your proposed `opLet` would. Of course, you wouldn't normally do this, because it would be very surprising to use the `foreach` keyword for something other than iteration. But there is no *technical* reason you couldn't.This is basically the same lowering already provided by [`opApply`][1]. The only differences are - `opApply` returns an integer code (used for control flow) rather than the return value of the callback. - `opApply` uses the `foreach` keyword instead of `let`. [1]: https://dlang.org/spec/statement.html#foreach-statementGood point, although `let` would allow you to do arbitrary indexing and sub-slicing with the borrowed as opposed to looping through the whole slice in order.
Nov 16 2021
On Wednesday, 17 November 2021 at 03:45:03 UTC, Paul Backus wrote:Of course, you wouldn't normally do this, because it would be very surprising to use the `foreach` keyword for something other than iteration. But there is no *technical* reason you couldn't.Ah, gotcha. I guess the more interesting question is how much breakage there would be if borrowedSlice variables were disallowed, and if distinguishing between owning and borrowed slices is possible without changing existing syntax too much.
Nov 16 2021