ranges of characters and the overabundance of traits that go with them

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Sun Mar 12 01:26:08 PST 2017


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



More information about the Digitalmars-d mailing list