www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Templates for DRY code

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
Nothing new here... I'm just reminded of how templates can help with DRY 
(don't repeat yourself) code.

Here is a piece of code that uses an alias to be flexible on the element 
type:

import std.conv;

alias MyType = double;    // <-- Nice, MyType is used twice below

void main() {
     MyType[] a;

     // ...

     string s = "1.2";
     a ~= s.to!MyType;     // <-- This usage is troubling
}

Although to!MyType looks like a good idea there, the two usages of 
MyType must be kept in sync manually. Why should we repeat MyType when 
it's already known to be ElementType!(typeof(a)) anyway. (Unfortunately, 
that syntax is not very clear in code.)

One solution is to wrap ~= in a function template. Now the conversion is 
automatically made to the element type of the array:

import std.conv;

void append(T, S)(ref T[] arr, S s) {
     arr ~= s.to!T;
}

void main() {
     double[] a;    // <-- Removed MyType alias as well

     // ...

     string s = "1.2";
     a.append(s);
}

In simple cases like this, one may not even need the alias. 'double' 
appears in just one place there.

I think append() could be a part of std.array but I can't find anything 
like that in Phobos.

Ali
Jan 05
parent reply codephantom <me noyb.com> writes:
On Saturday, 6 January 2018 at 01:33:11 UTC, Ali Çehreli wrote:
 One solution is to wrap ~= in a function template. Now the 
 conversion is automatically made to the element type of the 
 array:
 ...
 .....
 I think append() could be a part of std.array but I can't find 
 anything like that in Phobos.

 Ali
The problem with this, in my opinion, is that your template 'append' is doing a conversion behind the scenes..ie. I wouldn't know that 'append' actually means 'convert & then append'. When I read: double[] a; string s = "1.2"; a.append(s); I think to myself...wtf is going on here? How can you append a string to an array of doubles? That's when I'd have go and find the append template and work out what it is really doing.
Jan 05
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/05/2018 06:14 PM, codephantom wrote:
 On Saturday, 6 January 2018 at 01:33:11 UTC, Ali Çehreli wrote:
 One solution is to wrap ~= in a function template. Now the conversion
 is automatically made to the element type of the array:
 ...
 .....
 I think append() could be a part of std.array but I can't find
 anything like that in Phobos.

 Ali
The problem with this, in my opinion, is that your template 'append' is doing a conversion behind the scenes..ie. I wouldn't know that 'append' actually means 'convert & then append'. When I read: double[] a; string s = "1.2"; a.append(s); I think to myself...wtf is going on here? How can you append a string to an array of doubles? That's when I'd have go and find the append template and work out what it is really doing.
I agree with your point as well. A better name can help there a little. It's hard to find a balance between fully explicit and fully automatic. I find myself going back and forth between those two extremes. Ali
Jan 05
next sibling parent reply codephantom <me noyb.com> writes:
On Saturday, 6 January 2018 at 03:08:19 UTC, Ali Çehreli wrote:
 It's hard to find a balance between fully explicit and fully 
 automatic. I find myself going back and forth between those two 
 extremes.

 Ali
Code is something that humans write and read (and read far more than write). So I prefer to optimise for mental processing ;-) By this, I mean reducing the amount of information I need to chunk, to make sense of something (whether that be writing, or reading). e.g double[] a; string s = "1.2"; a.append(s) requires me to go off and discover what append is doing, since 'append' is clearly not correctly describing what is actually going on here, in this little chunk. So, now I have to go off and discover the extra chunk I need, in order to make sense of this little chunk. Suddenly, the chunk has become a lot larger than it needed to be. so yeah, a simple rename of append would help.. or even.. a.append( s.to!ConvertToElementType(a) ); That's not valid code of course, but the semantics are all contained in that single chunk.
Jan 05
parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 6 January 2018 at 03:38:35 UTC, codephantom wrote:
 or even..

 a.append( s.to!ConvertToElementType(a) );

 That's not valid code of course, but the semantics are all 
 contained in that single chunk.
This works: import std.range.primitives: ElementType; a ~= s.to!(ElementType!(typeof(a)));
Jan 06
next sibling parent codephantom <me noyb.com> writes:
On Saturday, 6 January 2018 at 23:32:42 UTC, Paul Backus wrote:
 On Saturday, 6 January 2018 at 03:38:35 UTC, codephantom wrote:
 or even..

 a.append( s.to!ConvertToElementType(a) );

 That's not valid code of course, but the semantics are all 
 contained in that single chunk.
This works: import std.range.primitives: ElementType; a ~= s.to!(ElementType!(typeof(a)));
I guess this brings us back to Ali's point about finding the balance between being explicit and fully automatic. I certainly prefer: a.append(s); vs a ~= s.to!(ElementType!(typeof(a))); // this hurts by brain ;-) The only problem with the Ali's suggestion of using append, is we always bring background knowledge everytime we read and write code, and, we all know that you cannot append a string to an array of doubles (that is our background knowledge). I guess if we knew that you can do that now, then 'a.append(s);' would be just fine. But I'm not a big fan of 'implicit' conversions in type safe languages, even when those conversion are type safe. So there's yet another balance to get right.
Jan 06
prev sibling parent Mark <smarksc gmail.com> writes:
On Saturday, 6 January 2018 at 23:32:42 UTC, Paul Backus wrote:
 On Saturday, 6 January 2018 at 03:38:35 UTC, codephantom wrote:
 or even..

 a.append( s.to!ConvertToElementType(a) );

 That's not valid code of course, but the semantics are all 
 contained in that single chunk.
This works: import std.range.primitives: ElementType; a ~= s.to!(ElementType!(typeof(a)));
I think you can just do: s.to!(typeof(a[0]));
Jan 08
prev sibling parent codephantom <me noyb.com> writes:
On Saturday, 6 January 2018 at 03:08:19 UTC, Ali Çehreli wrote:
 I agree with your point as well.
 A better name can help there a little.
void ConvertAndAppend(T, S)(ref T[] arr, S s) { arr ~= s.to!T; } problem solved ;-) btw. I never thought that I would be able (or actually..willing) to program using templates, still I found D. Thanks to those responsible for making them so easy to use (presumably Walter and Andrei).
Jan 06