Thread overview
Documentation: is it intentional that template constraints are displayed after the signature?
Oct 31, 2019
Tobias Pankrath
Nov 01, 2019
Dennis
Nov 01, 2019
Tobias Pankrath
Nov 01, 2019
berni44
Nov 01, 2019
Ali Çehreli
Nov 01, 2019
Paul Backus
Nov 01, 2019
Ali Çehreli
Nov 01, 2019
Jonathan M Davis
October 31, 2019
e.g. here: https://dlang.org/library/object/destroy.html

I was confused at first by the trailing

 if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T));

after I somehow managed to completely parse that page without recognizing all other constraints.
November 01, 2019
Template constraints are not allowed before the signature in the language, so it can be expected the documentation does not swap that order.

On Thursday, 31 October 2019 at 13:34:35 UTC, Tobias Pankrath wrote:
> I was confused at first by the trailing
>
>  if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T));

Or are you confused by the newline between the ) and the if?
I do think the indentation is a bit confusing, but I don't know a better one.
I always have difficulty myself when trying to cleanly format long signatures of template functions.
November 01, 2019
On Friday, 1 November 2019 at 09:17:03 UTC, Dennis wrote:
> Template constraints are not allowed before the signature in the language, so it can be expected the documentation does not swap that order.
>
> On Thursday, 31 October 2019 at 13:34:35 UTC, Tobias Pankrath wrote:
>> I was confused at first by the trailing
>>
>>  if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T));
>
> Or are you confused by the newline between the ) and the if?
> I do think the indentation is a bit confusing, but I don't know a better one.
> I always have difficulty myself when trying to cleanly format long signatures of template functions.

Ah yes, now I see it.
November 01, 2019
On Thursday, 31 October 2019 at 13:34:35 UTC, Tobias Pankrath wrote:
> I was confused at first by the trailing
>
>  if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T));

I understood your question different from what Dennis answered. At least I was confused by similar lines, when I was a beginner and did not know much about template constraints. What I would have needed to know at that time is, that template constraints limit the situations, where the template can be used. Here for example, this destroy template can only be used, when the type T is neither struct, interface nor class (these three have separate instances, probably because they need different treatment) and it's also not a static array, for unknown reasons.

What I don't understand is the 4th version with two extra parameters. Here the documentation lacks an explanation, what this is good for.
November 01, 2019
On 11/01/2019 04:09 AM, berni44 wrote:

> What I don't understand is the 4th version with two extra parameters.
> Here the documentation lacks an explanation, what this is good for.

I went to the documentation by clicking "View source code" and scrolled a bit and found this:

  https://github.com/dlang/druntime/blob/v2.088.1/src/object.d#L590

void destroy(bool initialize = true, T : U[n], U, size_t n)(ref T obj) if (!is(T == struct))
{
    foreach_reverse (ref e; obj[])
        destroy!initialize(e);
}

Apparently, it's the version for static arrays. However, I don't think the template constraint is doing anything there because if T matches a static array (of the form U[n]), then T is not a struct anyway.

Ali

November 01, 2019
On Friday, 1 November 2019 at 15:29:24 UTC, Ali Çehreli wrote:
> On 11/01/2019 04:09 AM, berni44 wrote:
>
> > What I don't understand is the 4th version with two extra
> parameters.
> > Here the documentation lacks an explanation, what this is
> good for.
>
> I went to the documentation by clicking "View source code" and scrolled a bit and found this:
>
>   https://github.com/dlang/druntime/blob/v2.088.1/src/object.d#L590
>
> void destroy(bool initialize = true, T : U[n], U, size_t n)(ref T obj) if (!is(T == struct))
> {
>     foreach_reverse (ref e; obj[])
>         destroy!initialize(e);
> }
>
> Apparently, it's the version for static arrays. However, I don't think the template constraint is doing anything there because if T matches a static array (of the form U[n]), then T is not a struct anyway.
>
> Ali

`T : U[n]` could also be matched by a struct with an `alias this` to a static array member.

Example: https://run.dlang.io/is/NgRU94
November 01, 2019
On 11/01/2019 09:33 AM, Paul Backus wrote:
> On Friday, 1 November 2019 at 15:29:24 UTC, Ali Çehreli wrote:

>> Apparently, it's the version for static arrays. However, I don't think
>> the template constraint is doing anything there because if T matches a
>> static array (of the form U[n]), then T is not a struct anyway.
>>
>> Ali
>
> `T : U[n]` could also be matched by a struct with an `alias this` to a
> static array member.
>
> Example: https://run.dlang.io/is/NgRU94

Thanks. Is it special to destroy() to care for that case or should all our algorithms be on the watchout for such structs? I'm sure I would be missing that specialization if I ever needed to write similar specializations for an algorithm.

Ali


November 01, 2019
On Friday, November 1, 2019 11:23:42 AM MDT Ali Çehreli via Digitalmars-d- learn wrote:
> On 11/01/2019 09:33 AM, Paul Backus wrote:
>  > On Friday, 1 November 2019 at 15:29:24 UTC, Ali Çehreli wrote:
>  >> Apparently, it's the version for static arrays. However, I don't think
>  >> the template constraint is doing anything there because if T matches a
>  >> static array (of the form U[n]), then T is not a struct anyway.
>  >>
>  >> Ali
>  >
>  > `T : U[n]` could also be matched by a struct with an `alias this` to a
>  > static array member.
>  >
>  > Example: https://run.dlang.io/is/NgRU94
>
> Thanks. Is it special to destroy() to care for that case or should all our algorithms be on the watchout for such structs? I'm sure I would be missing that specialization if I ever needed to write similar specializations for an algorithm.

Pretty much any time that a template constraint uses an implicit conversion, the code needs to be careful. Typically, the code then needs to force the conversion and then operate on the exact type in order to avoid subtle bugs. Honestly, in general, I'd argue that it's better to just not accept implicit conversions with templates.

In this particular case, what it should probably be doing is just use __traits(isStaticArray, ...) in the template constraint, but whoever wrote that overload took a different tact (though depending on how old that trait is and how old that overload of destroy is, the trait may or may not have been an option when that overload of destroy was written).

- Jonathan M Davis