www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Fix template parameter

reply Dom Disc <dominikus scherkl.de> writes:
Hello.
I found in the documentation functions declared like this:

```D
pure  nogc  safe BigInt opAssign(T : BigInt)(T x);
```

What is the difference to declaring it like:

```D
pure  nogc  safe BigInt opAssign(BigInt x);
```

To me the first declaration seems to be unnecessarily bloated, so 
I ask myself: does it provide any kind of advantage? I can't see 
it.
Aug 08 2022
next sibling parent reply bauss <jacobbauss gmail.com> writes:
On Monday, 8 August 2022 at 12:02:02 UTC, Dom Disc wrote:
 ```D
 pure  nogc  safe BigInt opAssign(T : BigInt)(T x);
 ```
This will only be included in the object file if used.
 What is the difference to declaring it like:

 ```D
 pure  nogc  safe BigInt opAssign(BigInt x);
 ```
This will always be in the object file. Someone can correct me if I'm wrong, but I think it's mostly linkage optimization.
Aug 08 2022
parent reply Dom Disc <dominikus scherkl.de> writes:
On Monday, 8 August 2022 at 12:46:48 UTC, bauss wrote:
 On Monday, 8 August 2022 at 12:02:02 UTC, Dom Disc wrote:
 ```D
 pure  nogc  safe BigInt opAssign(T : BigInt)(T x);
 ```
This will only be included in the object file if used.
 ```D
 pure  nogc  safe BigInt opAssign(BigInt x);
 ```
This will always be in the object file.
Ah, ok. But shouldn't the linker throw it out of an executable, if it is not used? I mean, even the most dump linker should be able to do this basic optimization...
Aug 08 2022
parent pascal111 <judas.the.messiah.111 gmail.com> writes:
On Monday, 8 August 2022 at 14:48:27 UTC, Dom Disc wrote:
 On Monday, 8 August 2022 at 12:46:48 UTC, bauss wrote:
 On Monday, 8 August 2022 at 12:02:02 UTC, Dom Disc wrote:
 ```D
 pure  nogc  safe BigInt opAssign(T : BigInt)(T x);
 ```
This will only be included in the object file if used.
 ```D
 pure  nogc  safe BigInt opAssign(BigInt x);
 ```
This will always be in the object file.
Ah, ok. But shouldn't the linker throw it out of an executable, if it is not used? I mean, even the most dump linker should be able to do this basic optimization...
I didn't study this level yet in templates, but did you ask about if changing compiler can make a difference to what you desire? I know that there are gdc, ldc and dmd compilers. DMD is the most common one, I think.
Aug 09 2022
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/8/22 8:02 AM, Dom Disc wrote:
 Hello.
 I found in the documentation functions declared like this:
 
 ```D
 pure  nogc  safe BigInt opAssign(T : BigInt)(T x);
 ```
 
 What is the difference to declaring it like:
 
 ```D
 pure  nogc  safe BigInt opAssign(BigInt x);
 ```
 
 To me the first declaration seems to be unnecessarily bloated, so I ask 
 myself: does it provide any kind of advantage? I can't see it.
 
Just a guess, but there was a time in the distant past when you could not overload template functions with regular functions. Perhaps that's why? Otherwise, no there really isn't a difference in this case. -Steve
Aug 08 2022
prev sibling parent reply Meta <jared771 gmail.com> writes:
On Monday, 8 August 2022 at 12:02:02 UTC, Dom Disc wrote:
 Hello.
 I found in the documentation functions declared like this:

 ```D
 pure  nogc  safe BigInt opAssign(T : BigInt)(T x);
 ```
This is a template function, even if T is constrained to always be BigInt (it may also include anything that is a subtype of BigInt... I've received different answers on what exactly `(T: SomeType)` means in this context). This means that it cannot be virtual, you can't take its address, and as bauss said, it won't show up in the object file if it's not used. As far as I know, there's no advantage to doing this over `opAssign(BigInt x)`, UNLESS `(T: BigInt)` means "BigInt and any subtype of BigInt", in which case the advantage is similar to doing `<T extends BigInt> void opAssign(T val)` in Java (referring to polymorphism; this won't give you virtual dispatch like it does in Java).
Aug 09 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 9 August 2022 at 21:08:52 UTC, Meta wrote:
 (it may also include anything that is a subtype of BigInt... 
 I've received different answers on what exactly `(T: SomeType)` 
 means in this context).
Yes, this syntax allows anything that implicitly converts to `BigInt`; for example: ```d import std.bigint; void fun(T : BigInt)(T t) { pragma(msg, "Instantiated with T = `" ~ T.stringof ~ "`"); } struct S { BigInt n; alias n this; } void main() { S s; fun(s); // Instantiated with T = `S` } ``` There is currently no way to write a template specialization that requires an exact type, with no implicit conversions. For that, you would have to use a template constraint instead: ```d void fun(T)(T t) if (is(T == BigInt)) { // ... } ```
Aug 09 2022
parent reply Dom Disc <dominikus scherkl.de> writes:
On Tuesday, 9 August 2022 at 21:16:22 UTC, Paul Backus wrote:
 Yes, this syntax allows anything that implicitly converts to 
 `BigInt`; for example:

 ```d
 import std.bigint;

 void fun(T : BigInt)(T t)
 {
     pragma(msg, "Instantiated with T = `" ~ T.stringof ~ "`");
 }

 struct S
 {
     BigInt n;
     alias n this;
 }

 void main()
 {
     S s;
     fun(s); // Instantiated with T = `S`
 }
Aha. But isn't that also true for the other declaration? ```d void fun(BigInt t) { } ``` will also accept anything that implicitly converts to BigInt, no? So I still don't see the big difference. Except that is is a template - for what ever that may be useful if it doesn't take more than one type. Relying on something as subtle as this difference does have a code-smell for me.
Aug 09 2022
parent reply Dom Disc <dominikus scherkl.de> writes:
On Tuesday, 9 August 2022 at 22:32:23 UTC, Dom Disc wrote:
 On Tuesday, 9 August 2022 at 21:16:22 UTC, Paul Backus wrote:
 Yes, this syntax allows anything that implicitly converts to 
 `BigInt`;
Oh, or do you mean I will get two different instances of the template, if I call it with two different types with implicit conversion? That would make it even worse than the non-templated declaration!
Aug 09 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 9 August 2022 at 22:36:23 UTC, Dom Disc wrote:
 On Tuesday, 9 August 2022 at 22:32:23 UTC, Dom Disc wrote:
 On Tuesday, 9 August 2022 at 21:16:22 UTC, Paul Backus wrote:
 Yes, this syntax allows anything that implicitly converts to 
 `BigInt`;
Oh, or do you mean I will get two different instances of the template, if I call it with two different types with implicit conversion? That would make it even worse than the non-templated declaration!
Yes, exactly.
Aug 09 2022
parent reply Dom Disc <dominikus scherkl.de> writes:
On Tuesday, 9 August 2022 at 22:58:16 UTC, Paul Backus wrote:
 On Tuesday, 9 August 2022 at 22:36:23 UTC, Dom Disc wrote:
 On Tuesday, 9 August 2022 at 22:32:23 UTC, Dom Disc wrote:
 On Tuesday, 9 August 2022 at 21:16:22 UTC, Paul Backus wrote:
 Yes, this syntax allows anything that implicitly converts to 
 `BigInt`;
Oh, or do you mean I will get two different instances of the template, if I call it with two different types with implicit conversion? That would make it even worse than the non-templated declaration!
Yes, exactly.
Ok, then I consider this is a bug in Phobos that should be corrected. All instances of ```D foo(T : fixedType)(T x) { } ``` should be replaced by ```D foo(fixedType x) { } ```
Aug 09 2022
parent Nick Treleaven <nick geany.org> writes:
On Wednesday, 10 August 2022 at 06:15:39 UTC, Dom Disc wrote:
 Ok, then I consider this is a bug in Phobos that should be 
 corrected.

 All instances of

 ```D
 foo(T : fixedType)(T x) { }
 ```
 should be replaced by

 ```D
 foo(fixedType x) { }
 ```
Perhaps, but not necessarily. The body of foo could do introspection on T with static if or overloaded functions and produce specialised code. Even if foo doesn't do that, perhaps the author reserves the right to do that in future. Or perhaps it needs to be a template to infer attributes. For that case, using an empty template parameter list would be clearer.
Aug 10 2022