www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Giant template - changing types everywhere

reply Cecil Ward <cecil cecilward.com> writes:
Some advice on a couple of points.

I have been working on a module that works on either dchar / 
dstrings or wchar / wstrings with just two changes of alias 
definitions and a recompile.

What I really want to do though is provide one single templated 
function with the kind of characters / strings as a parameter. I 
want to have something like
T Transform( T )( T str)
called as
auto result = Transform!(dstring)( dstring str );

I only want to have one type as a parameter and derive other 
types from that: xstrings from xchars and I’ll need types of 
xchar arrays that are mutable and immutable.

I’m quite confused as to how to proceed. This is quite a large 
module ~ 2k loc, and I don’t really want to go through and change 
every private function into a templated one. Should I just make 
the whole thing into a giant template containing many functions?
Jul 13 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/13/23 8:08 PM, Cecil Ward wrote:

 What I really want to do though is provide one single templated function 
 with the kind of characters / strings as a parameter. I want to have 
 something like
 T Transform( T )( T str)
 called as
 auto result = Transform!(dstring)( dstring str );
```d T[] Transform(T)(T[] str) ``` Note that you don't have to specify the type when calling: ```d Transform(someDstring); // infers dchar ```
 I’m quite confused as to how to proceed. This is quite a large module ~ 
 2k loc, and I don’t really want to go through and change every private 
 function into a templated one. Should I just make the whole thing into a 
 giant template containing many functions?
If you have more questions, please ask. Some examples of how making a template would be painful would be helpful. -Steve
Jul 13 2023
parent reply Cecil Ward <cecil cecilward.com> writes:
On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer 
wrote:
 On 7/13/23 8:08 PM, Cecil Ward wrote:

 What I really want to do though is provide one single 
 templated function with the kind of characters / strings as a 
 parameter. I want to have something like
 T Transform( T )( T str)
 called as
 auto result = Transform!(dstring)( dstring str );
```d T[] Transform(T)(T[] str) ``` Note that you don't have to specify the type when calling: ```d Transform(someDstring); // infers dchar ```
 I’m quite confused as to how to proceed. This is quite a large 
 module ~ 2k loc, and I don’t really want to go through and 
 change every private function into a templated one. Should I 
 just make the whole thing into a giant template containing 
 many functions?
If you have more questions, please ask. Some examples of how making a template would be painful would be helpful. -Steve
The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ?
Jul 13 2023
parent reply Cecil Ward <cecil cecilward.com> writes:
On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer 
 wrote:
 [...]
The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ?
Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right?
Jul 13 2023
parent reply Cecil Ward <cecil cecilward.com> writes:
On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer 
 wrote:
 [...]
The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ?
Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right?
If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions?
Jul 13 2023
parent reply Cecil Ward <cecil cecilward.com> writes:
On Friday, 14 July 2023 at 05:09:58 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer 
 wrote:
 [...]
The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ?
Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right?
If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions?
I tried it, wrapped the whole thing in a template definition and it compiled, but then my test file which calls Transform( someDString ) failed to compile with errors saying it couldn’t find the definition of Transform in the other module, which is or was public. It’s as if it is no longer public because it’s now inside the template.
Jul 13 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/14/23 1:51 AM, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:09:58 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote:
 The way I can see it going is a giant template encompassing pretty 
 much the whole file. Does that mean that the caller who calls my one 
 public function does so by passing the type dchar or wchar ? And 
 then we generate the strings from that. It might be rather more 
 natural for the caller to pass one of the string types into the 
 template. That’s where I get rather more confused, say caller calls

 Transform(dstring)(dstring str)

 or can they just do Transform( "str"d ) and it would work out that 
 the type is immutable dchar[] ?
Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right?
If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions?
I tried it, wrapped the whole thing in a template definition and it compiled, but then my test file which calls Transform( someDString ) failed to compile with errors saying it couldn’t find the definition of Transform in the other module, which is or was public. It’s as if it is no longer public because it’s now inside the template.
So templates don't automatically instantiate, you have to specify them. And then if your function is inside the template, to access it, you will need to do: ```d GiantTemplate!dstring.Transform(str); ``` But this is not a usual way of creating API. Instead, you should template individual functions on the string type. Depending on what you are doing, you can use: ```d T Transform(T)(T val) T[] Transform(T)(T[] val) ``` The first will cover cases where you have custom string types that aren't arrays, the second will just capture the array type, and ensures that the parameter/return is an array. When you make template functions like this, a feature of D called Implicit Function Template Instantiation (IFTI) will automatically instantiate the template for you, so you don't have to specify the template parameters. You just call `Transform(str)` and it works. With the wrapping template solution, this is not available -- you must explicitly instantiate the wrapper. If you are having problems, it is nearly impossible to diagnose without some actual code to look at. -Steve
Jul 14 2023
next sibling parent reply =?UTF-8?Q?Christian_K=c3=b6stlin?= <christian.koestlin gmail.com> writes:
On 14.07.23 16:15, Steven Schveighoffer wrote:
 On 7/14/23 1:51 AM, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:09:58 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote:
 On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote:
 The way I can see it going is a giant template encompassing pretty 
 much the whole file. Does that mean that the caller who calls my 
 one public function does so by passing the type dchar or wchar ? 
 And then we generate the strings from that. It might be rather more 
 natural for the caller to pass one of the string types into the 
 template. That’s where I get rather more confused, say caller calls

 Transform(dstring)(dstring str)

 or can they just do Transform( "str"d ) and it would work out that 
 the type is immutable dchar[] ?
Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right?
If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions?
I tried it, wrapped the whole thing in a template definition and it compiled, but then my test file which calls Transform( someDString ) failed to compile with errors saying it couldn’t find the definition of Transform in the other module, which is or was public. It’s as if it is no longer public because it’s now inside the template.
So templates don't automatically instantiate, you have to specify them. And then if your function is inside the template, to access it, you will need to do: ```d GiantTemplate!dstring.Transform(str); ``` But this is not a usual way of creating API. Instead, you should template individual functions on the string type. Depending on what you are doing, you can use: ```d T Transform(T)(T val) T[] Transform(T)(T[] val) ``` The first will cover cases where you have custom string types that aren't arrays, the second will just capture the array type, and ensures that the parameter/return is an array. When you make template functions like this, a feature of D called Implicit Function Template Instantiation (IFTI) will automatically instantiate the template for you, so you don't have to specify the template parameters. You just call `Transform(str)` and it works. With the wrapping template solution, this is not available -- you must explicitly instantiate the wrapper. If you are having problems, it is nearly impossible to diagnose without some actual code to look at. -Steve
Would Eponymous Templates (https://dlang.org/spec/template.html#implicit_template_properties) work with the wrapping template? Kind regards, Christian
Jul 14 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/14/23 12:40 PM, Christian Köstlin wrote:


 Would Eponymous Templates 
 (https://dlang.org/spec/template.html#implicit_template_properties) work 
 with the wrapping template?
Only if all the functions are named the same as the template. With eponymous templates, you no longer get access to any of the members of the template aside from the eponymous member(s). -Steve
Jul 14 2023
parent =?UTF-8?Q?Christian_K=c3=b6stlin?= <christian.koestlin gmail.com> writes:
On 14.07.23 18:51, Steven Schveighoffer wrote:
 On 7/14/23 12:40 PM, Christian Köstlin wrote:
 

 Would Eponymous Templates 
 (https://dlang.org/spec/template.html#implicit_template_properties) 
 work with the wrapping template?
Only if all the functions are named the same as the template. With eponymous templates, you no longer get access to any of the members of the template aside from the eponymous member(s). -Steve
I see ... thanks for the explanation!!! Kind regards, Christian
Jul 14 2023
prev sibling parent Cecil Ward <cecil cecilward.com> writes:
On Friday, 14 July 2023 at 14:15:29 UTC, Steven Schveighoffer 
wrote:
 On 7/14/23 1:51 AM, Cecil Ward wrote:
 [...]
So templates don't automatically instantiate, you have to specify them. And then if your function is inside the template, to access it, you will need to do: [...]
I can give you the code if you wish. I am cecil (at) cecil ward (dot) com. I can’t thank you enough for your generous help. I don’t want you to get sucked into a black hole with this though. I don’t understand why the public keyword fails to work inside a template, but I suppose that that’s just a wishlist feature.
Jul 14 2023