digitalmars.D.learn - array inside a class + alias this + filter -> clears the array.
- realhet (43/43) Jul 07 2021 Hi,
- Paul Backus (22/34) Jul 07 2021 In general, it is not a good idea to have your container class
- realhet (19/21) Jul 07 2021 Thx, I didn't know about this type of opSlice override. It works
Hi, I wanted to make a container class that exposes its elements using a simple "alias this", but getting weird errors: I test with the std.algorithm.filter template function. 1. when I use "alias this" on a function that returns a slice, making the internal array unreachable, filter just can't compile. 2. when I expose the array as it is, filter deletes the array after it returns. My goal is to make a class, which acts like an array, but also having member functions to add/remove/find its items. On top of that this class has an owner (a database table thing) too. Example use-cases: table.rows.add(...) table.rows[4] table.rows.filter!(...).map!(...) ``` import std.stdio, std.range, std.algorithm, std.uni, std.utf, std.conv, std.typecons, std.array, std.traits, std.exception, std.format, std.random, std.math; class C{ //must be a class, not a struct int[] array; static if(0){ //BAD: filter cannot deduce from an aliased function // that returns a nonref array auto getArray(){ return array; } alias getArray this; }else{ alias array this; //this works } } void main(){ auto c = new C; c.array = [1, 2]; void wl(){ writeln("len=", c.length); } //filtering the array explicitly: GOOD c.array.filter!"true".each!writeln; wl; //filtering the slice of the alias: GOOD c.array.filter!"true".each!writeln; wl; //filtering the alias: BAD -> erases the array c.filter!"true".each!writeln; wl; } ``` Thanks in advance.
Jul 07 2021
On Wednesday, 7 July 2021 at 16:20:29 UTC, realhet wrote:Hi, I wanted to make a container class that exposes its elements using a simple "alias this", but getting weird errors: I test with the std.algorithm.filter template function. 1. when I use "alias this" on a function that returns a slice, making the internal array unreachable, filter just can't compile. 2. when I expose the array as it is, filter deletes the array after it returns. My goal is to make a class, which acts like an array, but also having member functions to add/remove/find its items. On top of that this class has an owner (a database table thing) too.In general, it is not a good idea to have your container class also function as a range, for exactly this reason. Instead, your container class should have a method that returns a range over its elements, with the range being a separate object. The conventional way to do this is to overload `opIndex`: ```d class C { private int[] array; this(int[] array) { this.array = array; } int[] opIndex() { return array; } // etc. } void main() { import std.algorithm; auto c = new C([1, 2, 3]); c[].filter!"true".each!writeln; assert(c[].length == 3); } ```
Jul 07 2021
On Wednesday, 7 July 2021 at 17:10:01 UTC, Paul Backus wrote:On Wednesday, 7 July 2021 at 16:20:29 UTC, realhet wrote:int[] opIndex() { return array; }Thx, I didn't know about this type of opSlice override. It works nicely. Now I have these choices: - write [] everywhere to access the containers. - write nothing extra to access the containers but put the container operations one level higher and select the container for those based on a dummy struct. Like going from: ``` db.entities.add("Entity01"); to db.add(entity("Entity01")); //struct entity{ string name; } ``` Currently I have both ways plus your solution for the range access. Gotta experience with it to choose. Thanks again! I will remember that common container rule from now on.
Jul 07 2021