Workaround for DIP 1005

Meta via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 14 06:41:41 PST 2017


On Thursday, 9 February 2017 at 05:40:01 UTC, Jonathan M Davis 
wrote:
> On Friday, February 03, 2017 14:43:01 Dominikus Dittes Scherkl 
> via Digitalmars-d wrote:
>> Any thoughts?
>
> This is really cool, but I have a couple of concerns about this 
> and how it seems deficient in comparison to DIP 1005. I 
> mentioned it in Andrei's PR for this, but no one has responded 
> to my comment.
>
> This first problem is UFCS. While this technique works great 
> for parameters or on types you want to list in the template 
> constraint, I don't see how it can work with UFCS. So, if you 
> have something like
>
> auto func(alias pred, R)(R range)
>     if(isInputRange!R &&
>        is(typeof(pred(range.front)) == bool))
> {...}
>
> you can do
>
> auto func(alias pred, R)(R range)
>     if(from!"std.range.primitives".isInputRange!R &&
>        is(typeof(pred(range.front)) == bool))
> {...}
>
> but you can't import std.range.primitives.front to make dynamic 
> arrays work, whereas with DIP 1005, you can just add the import 
> to the function declaration, and it will work without having to 
> tie the import to a specific symbol.
>
> And while in many cases, you can just forgo UFCS - e.g.
>
> auto func(P)(P param)
>     if(is(typeof(from!"std.algorithm".find(param)) == param))
> {...}
>
> that not only doesn't work with the range primitives, but it's 
> bad practice to use UFCS in the function body and not the 
> template constraint (since the semantics may not be the same), 
> meaning that not using UFCS in the template constraint means 
> not using it in the function body for anything that's in the 
> template constraint (which many folks won't like and others 
> won't understand, resulting in subtle bugs), and any case where 
> you want a function to work with types that define a function 
> as a member function as well as with types that use a free 
> function, you need to use UFCS and thus cannot choose to not 
> use it in the template constraint.
>
> So, unless there's something that I don't understand about this 
> technique (which is definitely possible), it seems like it does 
> not work with UFCS and thus makes it considerably worse than 
> 1005 for a lot of templated code, much as it would work great 
> for code that doesn't need UFCS.
>
> The other problem is how much more verbose it is. With DIP 
> 1005, you can do
>
> with(import std.datetime)
> auto foo(SysTime st1, SysTime st2, Duration d);
>
> The import is only listed once, whereas with this technique, 
> you have to list it for each symbol. e.g.
>
> auto foo(from!"std.datetime".SysTime st1,
>          from!"std.datetime".SysTime st2,
>          from!"std.datetime".Duration d);
>
> The result is much more verbose, and if you have several 
> symbols that need imports between the return type, parameters, 
> and template constraint, you quickly end up with a lot of extra 
> text in the middle of your function signatures just because you 
> want to tie the imports to the functions that use them. With 
> DIP 1005, the imports are next to the function but separate 
> where they avoid the need for repeating imports and don't get 
> mixed into the middle of the function signature.
>
> So, while the proposed technique is really cool and clever in 
> what it lets us do without actually altering the language, it 
> seems like it's quite a bit worse than DIP 1005. As such, I'm 
> inclined to argue that we should favor DIP 1005 over this 
> proposal, as cool as it is.
>
> - Jonathan M Davis

It's a hack on top of a hack, but you can do something like this:

void test(T1, T2, alias isIntegral = 
from!"std.traits".isIntegral,(T1 t1, T2 t2)
if (isIntegral!T1 && isIntegral!T2)
{
	pragma(msg, isIntegral!T1);
	pragma(msg, isIntegral!T2);
}

void main()
{
}

The only problem is that it allows a user to supply their own 
value for isIntegral, which can lead to some weird error messages 
and confusion if they don't know about this idiom.

Also it can't quite do UFCS, because you cannot use UFCS with 
local symbols:

void test(T1, T2,
		  alias isIntegral = from!"std.traits".isIntegral,
		  alias chop = from!"std.string".chop)
	(T1 t1, T2 t2)
if (isIntegral!T1 && isIntegral!T2 && T1.stringof.chop() == 
"ubyt") //Error: no property 'chop' for type 'string'
{
}


More information about the Digitalmars-d mailing list