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