On Sunday, March 12, 2017 09:02:53 Jack Stouffer via Digitalmars-d wrote: > On Sunday, 12 March 2017 at 03:23:21 UTC, Jonathan M Davis wrote: > > ... > > First off, I'd like to point out that creating specific overloads > for alias this-ed structs is a bad idea, because you just have to > ask the user to do this > > MyCustomType { string b; alias b this; } > > MyCustomType a; > foo!(string)(a); > > instead of > > MyCustomType a; > foo(a); > > And I think making the conversion on the user is better, because > once we go down the rabbit hole of offering custom template > support for user defined alias this-ed types, there's almost no > bottom. You have to do the same thing to every templated function > that uses traits like isNumeric, isPointer, etc. > > So with that in mind, your proposal for alias this overloads of > > > auto foo(C)(C[] str) > > if(isSomeChar!C) > > {...} > > Isn't really helpful for either because it still clutters code > with an extra overload. I think the problem we need to accept is > that alias this and template will always be sort of oil and water. > > I don't know if we should change the current overloads, as people > complained with std.file was range-ified and their code using > DirEntry broke. That's honestly what started this whole mess, and > honestly in hindsight we should have marked the issue as won't > fix and told them to use the above method. But people (including > me) wanted the regression fixed which is totally understandable. > > Maybe we should deprecate the isConvertibleToString overloads, > maybe not. But we really shouldn't add more.
I completely agree that in general, we should avoid implicit conversions with functions. I thought that I made that clear. Allowing implicit conversions with templates is error-prone and should be generally avoided. The issue is when you templatize a function that already exist. If you take a function that accepts string, and you try and make it so that it accepts arbitrary ranges of characters, you have to still accept all of the implicit conversions that the original function did, or you break code. So, it becomes a question of the best way to write the templatized version of the function. As it stands, using isConvertibleToString is the solution that seems to have been introduced to Phobos to fix that problem, and as I pointed out, that's a risky solution at best and an outright wrong solution at worst, because it does the conversion inside the function rather that at the call point, which creates safety issues. And in those cases, I think that we should be templatizing on character type like with auto foo(R)(R range) if(!isSomeString!R && isInputRange!R && isSomeChar!(ElementType!R)) { return _fooImpl(range); } auto foo(C)(C[] str) if(isSomeChar!C) { return _fooImpl(str); } private auto _fooImpl(R)(R range) if(isInputRange!R && isSomeChar!(ElementType!R)) {...} because that's safer. If we're talking about creating a new function rather than templatizing an existing function, then I don't think that it makes sense to add that extra overload. Just make it accept ranges of characters and be done with it. But the problem of templatizing existing functions still exists, and in that case, we're stuck doing _something_ to accept the implicit conversions, or we break code. - Jonathan M Davis