Issues with constants, and inout (was Real World usage of D, Today)

Andrei Alexandrescu (See Website For Email) SeeWebsiteForEmail at erdani.org
Fri Jan 26 16:50:57 PST 2007


kris wrote:
[about implicit conversion rules]
> extern (C) int printf (char*, ...);
> 
> class Foo
> {
>         void write (int x) {printf("int\n");}
>         void write (uint x) {printf("uint\n");}
>         void write (long x) {printf("long\n");}
>         void write (char x) {printf("char\n");}
>         void write (wchar x) {printf("wchar\n");}
>         void write (double x) {printf("double\n");}
> 
>         void write (char[] x) {printf("char[]\n");}
>         void write (wchar[] x) {printf("wchar[]\n");}
> }
> 
> void main()
> {
>         auto foo = new Foo;
> 
>         foo.write ('c');
>         foo.write (1);
>         foo.write (1u);
>         foo.write (3.14);
>         //foo.write ("asa");
> }
> 
> prints:
> 
> char
> int
> uint
> double
> 
> 
> DMD has actually become smarter than the last time I tried something 
> like this: it manages to select the correct overload for 'c' whereas 
> before it couldn't decide whether int or uint was a better match for the 
> char instead. This is good.
> It seems clear from the above that D /defaults/ the type of character, 
> and undecorated integers, to something appropriate? In the above case 
> 'c' is defaulted to char, rather than wchar, for example. The 
> undecorated int constant is defaulted to int, rather than uint or long. 
> This is good.

Yup. So far so good.

> Now for the broken part. When you uncomment the string constant, the 
> compiler gets all confused about whether it's a char[] or wchar[]. There 
> is no defaulting to one type, as there is for other constants (such as 
> char). It /is/ possible to decorate the string constant in a similar 
> manner to decorating integer constants:
> 
> foo.write ("qwe"c);
> 
> And this, of course, compiles. It's a PITA though, and differs from the 
> rules for other constants.

I talked to Walter about this and it's not a bug, it's a feature :o). 
Basically it's hard to decide what to do with an unadorned string when 
both wchar[] and char[] would want to "attract" it. I understand you're 
leaning towards defaulting to char[]? Then probably others will be unhappy.

> Things start to go south when using templates 
> with string constants. For example, take this template sig:
> 
> uint locate(T) (T[] source, T match, uint start=0)
> 
> This is intended to handle types of char[], wchar[] and dchar[]. There's 
> a uint on the end, as opposed to an int. Suppose I call it like this:
> 
> locate ("abc", "ab", 1);
> 
> we get a compile error, since the int-constant does not match a uint in 
> the sig (IFTI currently needs exact sig matches). In order to get around 
> this, we wrap the template with a few functions:
> 
> uint locate (char[] source, char[] match, uint start=0)
> {
>     return locateT!(char) (source, match, start);
> }
> 
> uint locate (wchar[] source, wchar[] match, uint start=0)
> {
>     return locateT!(wchar) (source, match, start);
> }
> 
> and dchar too.
> 
> Now we call it:
> 
> locate ("abc", "ab", 1);
> 
> Well, the int/uint error goes away (since function matching operates 
> differently than IFTI matching), but we've now got our old friend back 
> again -- the constant char[], wchar[], dchar[] mismatch problem.

I think a sound solution to this should be found. It's kind of hard, 
because char[] is the worst match but also probably the most used one. 
The most generous match is dchar[] but wastes much time and space for 
the minority of cases in which it's useful.

> How about another type of template? Here's one that does some simply 
> text processing:
> 
> T[] layout(T) (T[] output, T[] format, T[][] subs...)
> 
> This has an output buffer, a format string, and a set of optional args; 
> all of the same type. If I call it like so:
> 
> char[128] tmp;
> char[]    world = "world";
> layout (tmp, "hello %1", world);
> 
> that compiles ok. If I use wchar[] instead, it doesn't compile:
> 
> wchar[128] tmp;
> wchar[]    world = "world";
> layout (tmp, "hello %1", world);
> 
> In this case, the constant string used for formatting remains as a 
> char[], so the template match fails (args: wchar[], char[], wchar[])
> 
> However, if I change the template signature to this instead:
> 
> T[] layout(T) (T[] output, T[][] subs...)
> 
> then everything works the way I want it to, but the design is actually 
> wrong (the format string is now not required). String constants can be a 
> royal PITA.

Color me convinced. :o) I have no bright ideas on solving it though.

> inout
> -----
> 
> Since you're working on inout also, I'd like to ask what the plan is 
> relating to a couple of examples. Tango uses this style of call quite 
> regularly:
> 
> get (inout int x);
> get (inout char[] x);
> etc.
> 
> This is a clean way to pass-by-reference, instead of dealing with all 
> the pointer syntax. I sure hope D will retain reference semantics like 
> this, in some form?

It will, and in the same form.

> One current problem with inout, which you might not be aware of, is with 
> regard to const structs. I need to pass structs by reference, because I 
> don't want to pass them by value. Applying inout is the mechanism for 
> describing this:
> 
> struct Bar {int a, b;}
> 
> Bar b = {1, 2};
> 
> void parf (inout Bar x) {}
> 
> void main()
> {
>    parf (b);
> }
> 
> That all works fine. However, when I want to make those structs /const/ 
> instead, I cannot use inout since it has mutating semantics: I get a 
> compile error to that effect:
> 
> const Bar b = {1, 2};
> 
>  >> Error: cannot modify const variable 'b'
> 
> That is, there's no supported way to pass a const struct by reference. 
> The response from Walter in the past has been "just use a pointer 
> instead" ... well, yes I could do that. But it appears to be indicative 
> of a problem with the language design?

This case is on the list. You will definitely have a sane and simple way 
to pass const structs by reference, while having a guarantee that they 
can't be changed by the callee.

> Why do I want to use const? Well, the data held therein is for reference 
> only, and (via some future D vendor) I want that reference data placed 
> into a ROM segment. I do a lot of work with MCUs, and this sort of thing 
> is a common requirement.

I agree.


Andrei



More information about the Digitalmars-d mailing list