Do I have to pass parameters with ref explicitly?
Ali Çehreli
acehreli at yahoo.com
Sun Apr 17 08:45:11 UTC 2022
On 4/16/22 21:56, Elfstone wrote:
> On Sunday, 17 April 2022 at 04:00:19 UTC, max haughton wrote:
>> On Sunday, 17 April 2022 at 03:00:28 UTC, Elfstone wrote:
>>> I'm reading some d-sources, and it looks like they pass big structs
>>> by value.
>>> Such as:
>>>
>>> Matrix4x4f opBinary(string op)(Matrix4x4f rhs) { ... }
>>>
>>> I came from a C++ background,
Me too. The situation is much simpler compared to C++:
- Classes have no issues with copying at all because they are proper
reference types. (I argue that classes (types used in OOP hierarchies)
are reference types in C++ as well but in C++ the programmer must be
careful to not pass class objects by value. (See the slicing problem.))
- Structs usually don't have issues with copying either because their
copy is bit-level copying (blitting) by default. In D, structs are value
types that should not have identities. It is illegal to have struct
objects that refer to structs or their members by reference. They can be
moved around at will.
- The latter point happens all the time with rvalues: They are blitted
around without copying anything.
Still, the language had (and still has) the post-blit function to give
the programmer a chance to fix things around when struct objects got
blitted.
Further still, some industry users (I think it was Weka.io) convinced
the D community that it was impossible to implement certain idioms (was
that reference-counting?) without proper copy constructors; so now D has
copy constructors which are encouraged. (Post-blit are discouraged but
they take precedence when both the post-blit and the copy constructor
exist for a type.)
- Somewhat related, unlike C++, D does not allow binding rvalues to
'const ref'. (This point is relevant for 'in' below.)
>>> and I would have written:
>>>
>>> Matrix4x4f opBinary(string op)(const ref Matrix4x4f rhs) { ... }
D has always had 'in' parameters but they were nothing other than the
shorter syntax for 'const scope'. Now, when compiled with the
-preview=in compiler command line switch, 'in' parameters relieve the
programmer from some mental load on how to pass parameters. In D, if it
is an input to a function, then mark it as 'in' and the compiler will do
some magic:
https://dlang.org/spec/function.html#in-params
I call it magic because it allows passing rvalues as ref! (I think this
obviates the "missing" feature of D that should allow binding rvalues to
const ref. Well, who really needs it when we have -preview=in now?)
It is further magical because 'in' does not pass types that have copy
constructor, post-blit, or destructor by-value! Wow!
So, this leaves only your concern of blitting big structs. I still don't
know size of a struct should be considered big when the following two
costs are compared:
- Blitting bytes has a cost
- Reaching members of structs (which 'const ref' would incur) through a
pointer has a cost
>>> I haven't found anything in the docs yet. Will the d-compiler
>>> optimize them into virtually the same? Can someone give me a reference?
>>
>> It's the same as C++.
>
> In C++ I would expect the copy to be optimized away, even when passed by
> value. Do you mean d-compilers (optionally?) do the same optimization
too?
You can expect at least the same optimizations for D because two major
C++ and D compilers share the same backend: clang for C++ and ldc for D.
Judging from how Walter Bright, the creator of D, has been a C++
compiler writer, to me it is hard to imagine that he would not make D at
least as much capable as C++ when it comes to optimizations. However,
dmd, the reference compiler, is known to be less capable in optimizing
code from both from ldc and gdc (the gcc's D compiler).
Ali
More information about the Digitalmars-d-learn
mailing list