Explicit this for methods
Quirin Schroll
qs.il.paperinik at gmail.com
Tue Jul 23 11:42:03 UTC 2024
On Tuesday, 23 July 2024 at 11:07:54 UTC, vit wrote:
> Explicit `this` allow manipulating of `this` type without
> interacting with function attributes and without need to create
> template function or string mixin-s.
Reminds me of C++23’s explicit object parameters. In C++, using D
lingo, `this` was added as a parameter storage class. The
disadvantage is that in C++, the instance pointer (normally
`this`) must have a name different from `this`.
> Syntax:
> - explicit `this` must be first parameter of non-static method
> - name is not identifier but keyword `this`.
> - explicit `this` doesn't support all parameter attributes like
> `ref`, `out`, `in` and `lazy`, but attributes like `scope` and
> `return` can be supported.
>
> Why?:
> - Type qualifiers can be in position of function attributes
> when `this` type qualifier need to be specified. Conditional
> manipulation of function attributes at compile time is very
> hard but manipulating types is much easier.
> - `this template parameter` can by replaced with explicit
> `this` + normal template parameter.
> - easier distinction between qualifiers/attributes for `this`
> and other function attributes like `pure` `nothrow` `@nogc`
> `ref`
>
> examples:
>
>
> ```d
> class C{
> […]
> abstract void test2(const C this)pure; //method with explicit
> this with type (is(Unqual!T == C))
> ```
What is `T`? Did you intend `Unqual!(typeof(this))`?
> ```d
>
> //this 3 methods are same:
> void test3(this This)()const pure{} //template method with
> implicit this with this template parameter
> void test3(this This)(const this)pure{} //template method with
> ```
The semantics of the one above is unclear.
> ```d
> […]
> const{ //can not be conditionaly specified at compile time
> abstract void foo();
> abstract void foo(int i);
> abstract void foo(string str);
> }
> ```
“can not be conditionaly specified at compile time” No idea what
that means.
> ```d
> alias FooThis = const(C); //can be conditionaly specified at
> compile time
> abstract void foo2(FooThis this);
> abstract void foo2(FooThis this, int i);
> abstract void foo2(FooThis this, string str);
> }
>
> struct S{
>
> //this 2 methods are same:
> ref S test2() @safe scope return pure{return this;}
> ref S test2(scope return this)@safe {return this;}
> //ref S test2(ref return this)@safe {return this;}
>
> }
>
> ```
> One problem is postblit constructor:
> ```d
>
> class C{
>
> //this 3 ctors are same:
> this(); //constructor with implicit this
> this(this); //AMBIGUOUS: conflict with postblit
> this(C this); //constructor with explicit this with type
> (is(Unqual!T == C))
>
> //this 3 ctors are same:
> this()const; //constructor with implicit const this
> this(const this); //AMBIGUOUS: conflict with postblit
> this(const C this); //constructor with explicit this with type
> (is(Unqual!T == C))
> }
> ```
Aren’t postblits deprecated? If not, the conflict with postblits
can be rectified with `this(const typeof(this) this)`.
> […]
>
> Explicit `this` can have other parameter attributes like:
> - `scope`
> - `return scope`
> - `scope return`
Logical.
> In the future explicit `this` can allow making lvalue `this`:
> ```d
> struct S{
> void test1(ref this)pure; //callable only on lvalue?
> }
> ```
There’s a bigger issue with structs. For classes, binding `this`
is by value, i.e. the class reference is copied. For structs,
`this` is a reference to the object. However, unlike with `ref`,
of course this by-reference binding can bind rvalues.
I’d do a complete 180° here: Allow `ref this` for structs and
allow it to bind rvalues. A non-`ref` `this` parameter binds by
copy. (For classes, no big deal, for structs, big difference.)
If we had `@rvalue ref` and `@universal ref`, I’d say use those
and `ref` means lvalues only.
It may be a stupid question, but why allow the type of the `this`
parameter to be specified? It only makes sense for templates.
There, the semantics could just say that `this` simply has the
type of the object it’s called on, i.e. explicit `this` implies
template `this`.
Another question: Can `this` parameters be used to bind by
pointer? That could actually be useful for handling `null`. I.e.
if I have `S* ptr` for some struct `S`, a `void f(S* this)` could
bind to `ptr.f()` and handle the case that `ptr` is `null`.
More information about the dip.ideas
mailing list