September 29, 2016 Qualifier parameters (inout on steroids) | ||||
---|---|---|---|---|
| ||||
`inout` is a useful feature, but it's nearly impossible to actually use it. Suppose I have struct MyTable { @property items() inout { return Range(&this); } static struct Range { MyTable* table; // can't be inout } } I want my items-range to be const if `this` is const or modifiable if `this` is modifiable. I ended up with @property items() { return Range!false(&this); } @property items() const { return Range!true(&this); } static struct Range(bool isConst) { static if (isConst) { const(MyTable)* table; } else { MyTable* table; } } Also, I can't define the struct inside the `items` method since it's used in two other methods (`keys` and `values`), only they hold a different `front` It would be really nice if I could "capture" the qualifiers and be parameterized on them as well. For example, int opApply(qual Q)(scope int delegate(int x) Q dg) Q; Meaning, my opApply is Q if dg is Q. In other words, I'm `nothrow` if dg is `nothrow`, I'm `@nogc` if dg is `@nogc`, I'm `pure` if dg is `pure`, etc. Inout is just a special case of this feature, e.g. int opApply(qual Q)(scope int delegate(Q int x) dg) Q; E.g., I'm const if dg takes a const first parameter. So using my first example, @property items(qual Q)() Q { return Range!Q(&this); } static struct Range(qual Q) { Q(MyTable)* table; } Much more elegant and concise. It needn't generate different object code for instantiations of course, it only needs to be respected by the frontend and thrown away later. -tomer |
September 29, 2016 Re: Qualifier parameters (inout on steroids) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tomer Filiba | On 9/29/16 8:53 AM, Tomer Filiba wrote: > `inout` is a useful feature, but it's nearly impossible to actually use > it. Suppose I have > > struct MyTable { > @property items() inout { > return Range(&this); > } > > static struct Range { > MyTable* table; // can't be inout > } > } > > I want my items-range to be const if `this` is const or modifiable if > `this` is modifiable. Yes, this is a problem -- but not with inout. This is a problem with the lack of tail modifier syntax. Observe how this works if Range is really a dynamic array: @property inout(T)[] items() inout { return theItems; // a dynamic array } Works just fine. What we need is a way to say tailinout(Range), which means that the table member is mutable, but points at inout data. > I ended up with > > @property items() { > return Range!false(&this); > } > @property items() const { > return Range!true(&this); > } There is a way to make this more DRY, but it is still ugly, and loses the benefits of inout. You need to use template this parameters: struct Range(T) { T *table; } @property items(this T)() { return Range!T(&this); } > It would be really nice if I could "capture" the qualifiers and be > parameterized on them as well. For example, > > int opApply(qual Q)(scope int delegate(int x) Q dg) Q; I once thought this would work well, but in practice I think it would be a disaster. Imagine everyone defining their own set of qualifiers and how they will work. It's also a template, and does not protect against modification of mutable data, or static if to change layout/implementation/etc. I am working on an article to propose a tail modifier syntax. This would solve most of these problems. -Steve |
Copyright © 1999-2021 by the D Language Foundation