C++'s this() equivalent?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Jun 16 01:54:22 UTC 2023


On Thursday, June 15, 2023 7:18:25 PM MDT zjh via Digitalmars-d-learn wrote:
> On Friday, 16 June 2023 at 01:00:05 UTC, Steven Schveighoffer
>
> wrote:
> > B b = B.make(); // call factory function
> >
> > -Steve
>
> Thank you for your tip.
> If could simplify it a bit more, it would be even better. It's
> really uncomfortable without `this()`.

The reasons for it have to do with how D in general is set up to require
that the value of all types be known at compile-time. Types in general use
default initialization rather than default construction. The language then
depends on this for a variety of things. For instance, when you construct a
an array (dynamic or static), it fills in all of the values in the array by
bit-blitting the init value of the element type onto the elements.
Similarly, when you expand the length of a dynamic array, it bit-blits the
init value of the element type onto the new elements. Other language
features such as in and out on function parameters rely on the init value as
well.

For all of that to work, the type's init value must be known at
compile-time, which means that default construction is off the table. For
most things, this is just fine and is quite beneficial. However, it does
make certain things (like RAII) more annoying than they are in C++.

That being said, as has been pointed out, the simple workaround if you want
RAII is to use a factory function. It's a bit of extra typing, since you
have to call a function instead of simply declaring the variable, but the
factory function then works like the constructor would have in C++, and the
destructor does the clean-up like it would have in C++. It just comes with
the downsides of the extra typing and the fact that it's possible to have
variables of that type that did not go through the factory function, because
they were default-initialized with the init value rather than constructed
via the factory function.

To work around that, you can @disable this so that the type doesn't have an
init value, but then it can't be used in any context where the init value
would be required, which can become very annoying.

Unlike structs, classes can have default constructors, but that's because
they sit on the heap, and technically, when you refer to a class type,
you're almost always referring to a class reference rather than to the
object itself. And the class reference has an init value of null, so it can
be used in all of the places where an init value is required, whereas a
class object is never actually used in such a situation.

For RAII, as an alternative to using a factory function on a struct, you can
use a class and then use https://dlang.org/phobos/std_typecons.html#scoped
to ensure that it gets destroyed when it leaves scope.

There are also scope statements for ensuring that something is run when you
exit the scope, but it isn't really RAII, since you'd still have to call the
initialization portion of things separately. E.G.

doSomething();
scope(exit) undoSomething();

It just makes it easier to ensure that what you want to run when the scope
is exited is always run.

So, there are several ways that you could go about trying to get behavior
similar to RAII in C++ even if you can't actually have RAII. Probably the
best method though is to just use a factory function on a struct. Yes, it's
more annoying than proper RAII, but it's a side effect of other benefits
that D gives that C++ does not.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list