string, char[], overloaded functions.

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Oct 31 17:21:29 PDT 2014


On Friday, October 31, 2014 23:58:43 dajones via Digitalmars-d-learn wrote:
> Ok,
>
> void Foo(string name, string value);
> void Foo(string name, int value);
>
> then...
>
> char[] buf = "woo".dup;
> Foo("bar","woohoo"); // works ok
> Foo("bar",buf~"hoo"); // fails, error says cant match params (string, int)
>
> So shouldnt char[] implicity convert to string, and hence match the
> (string,string) parameter list?
>
> is there a better way than doing...
>
> cast(string)(buf~"hoo")
>
> to get it to pick the correct overload?

How could char[] implicitly convert to string? string is immutable(char)[], so
its elements can't be changed, whereas char[]'s can be. So, if char[]
implicitly converted to immutable(char)[], either it would be by casting and
make it possible to violate the immutability of the characters (because
something could change the original char[] array, and then affect the
supposedly immutable characters in the one that came from the cast), or it
would be doing idup for you, which would then be an invisible allocation and
potential performance hit.

string and char[] will implicitly convert to const(char)[], but mutable types
don't generally implicitly convert to immutable ones, immutable ones don't
implicitly convert to mutable ones, and const doesn't implicitly convert to
either.

The reason that "woohoo" works is because string literals are strings, not
char[]. In the case of, buf ~ "hoo", it generates a new char[] with the
elements of buf and "hoo", because buf was char[], not string, and char[]
isn't implicitly convertible to either string or int.

If you want a function to take any type of mutability for strings, then you
can use const:

void foo(const(char)[] name const(char)[] value);

though that has the downside of making it so that you're stuff using const,
which is particularly annoying if the function returns

const(char)[] foo(const(char)[] name const(char)[] value);

To fix that, you can use inout

inout(char)[] foo(inout(char)[] name inout(char)[] value);

so that the constness stays the same, but then the constness would have to
match in this case, because there are two inout parameters. If you want to
accept any constness without dealing with inout and without having to use
const, then you can just templatize the function, e.g.

C[] foo(C, D)(C[] name, D[] value)
    if(is(C == char) && is(D == char))

and to accept any character type, you could do something like

C[] foo(C, D)(C[] name, D[] value)
    if(isSomeChar!C && isSomeChar!D)

but obviously that gets more complicated.

In any case, the only type of argument that will be accepted for a string
parameter is string, not char[] or const(char)[], and casting to string from
char[] will violate the type system if any other references to that same array
exist (making it possible for the supposedly immutable chars to be mutated).
So, you should use either idup or to!string() (the advantage of std.conv.to
being that if the argument ever changed to string, no copy would be made,
whereas idup would still make a copy).

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list