January 27, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Kevin Bealer wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
> [about deducing storage types]
>>> The syntax that I am proposing does away with storageof and is very much in spirit with the current D:
>>>
>>> S int foo(S, T)(S T t) { }
>>>
>>> It does exactly what it says it does, in a clear and terse manner, and is 100% within the spirit of existing D:
>>>
>>> * It's customized on symbols S and T
>>>
>>> * It's matching (by sheer position of S and T) the storage (i.e., all of the gooey fuzzy nice information about the argument passed) and the type of the incoming argument
>>>
>>> * In this example it uses the storage in the result type (e.g. const goes to const)
>>>
>>> * Inside the function can easily use either T separately or S T as a group that transports the storage around. You have total flexibility (and don't forget that juxtaposition is always easier than extraction).
>>>
>>> So far we're only thinking of storage-like attributes, but a good deal of information can be encoded under the loose declaration of "storage".
>>>
>>>
>>> Andrei
>>
>> I like this; does this mean that when declaring an instance, you would do something like this?  Or do the 'const' parts get deduced?
>>
>> alias Foo!(const, int) TheFoo;
> 
> The intent is to deduce the storage, but specifying it explicitly works just as well.
> 
> There is strong resistance against my notation because manipulating the storage class separately is something entirely new, which means a lot of work in the compiler implementation. Also, S is not a type but a (new kind of) alias, which might confuse people who read:
> 
> template Foo(S, T)
> {
>   ...
> }
> 
> and expect S and T to be types, just to discover in the body of the template that S is actually a qualifier.
> 
> The strawman we're discussing now looks like this:
> 
> void foo(auto T)(T t) { }
> 
> meaning, T will match whatever you throw at foo, including storage:
> 
> int a = 5;
> foo(a);     // T == inout int
> foo(a + 1); // T == int

So how would one declare such a type?  typeof(T) perhaps?  I imagine there must be some way to separate the storage class from the type for this to work.


Sean
January 27, 2007
Frits van Bommel wrote:
> kris wrote:
> 
>> Andrei Alexandrescu (See Website For Email) wrote:
>>
>>> 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
> 
> [snip]
> 
>>>> 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.
>>
>>
>> You'll have noticed that the constant 'c' defaults to /char/, and that there's no compile-time conflict between the write(char) & write(wchar)?  Are people unhappy about that too? Perhaps defaulting of char constants and int constants should be abolished also?
> 
> 
> It's a bit more complicated with character literals than just defaulting to 'char':
> -----
> import std.stdio;
> void main() {
>     writefln(typeid(typeof('a')));          // c <= \u007f
>     writefln(typeid(typeof('\uabcd')));     // c <= \uffff
>     writefln(typeid(typeof('\U000abcde'))); // c <= \U0010ffff
> 
> }
> -----
> outputs:
> """
> char
> wchar
> dchar
> """
> So it defaults to the *smallest* character type that can hold it in one element.
> Pretty cool, actually.
> 
> This also applies to other types, by the way. If you type an integer literal that won't fit into an 'int', it'll be a 'long' constant (assuming it fits), not an 'int' constant.

Yes. Kinda glossed over that part, didn't I <g>


> Perhaps we should do something similar with string literals, defaulting it to use an array of the smallest character type that can hold all of the characters in the string (i.e. the maximum "character type" of the component characters) ?
> That seems like a reasonable rule. And it has the added benefit that "some string constant".length will always be the number of characters in the string.


Yes, that would seem eminently reasonable.
January 27, 2007
Frits van Bommel wrote:
> Bill Baxter wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> You will be able to cherry-pick with "is" tests. Walter is opposed to manipulating the raw storage attributes.
>>
>> If you have to cherry pick with "is" tests to separate the bits out of the S above, then why not just use "is" tests to pick the S info off the type to begin with?
> 
> Because just 'S' is much shorter when you don't want to cherry-pick?

Just wondering if there are that many cases where all want to do is pick off S without 'deconstructing' it further.  Especially given Andrei's statement "there are lots of things that could go under the vague heading of storage class", it seems like it may be rare that you can actually just use S as-is without picking out the particular attributes you care about -- const or inout or any one of the 'lots of other things'.

And if that's the case then maybe the benefits of having the "template foo(S T)(S T x)" syntax are not so huge.  You could get S using
    alias storageof(T) S
in the first line of the template instead.  Or lets say you just want to use the constness part of S, which seems like a fairly common thing to want.  Then you'll still need something like:
     constof(S) template foo(S T)(S T v) { ... }
But if you have to say constof(S) you might as well just make constof operate on T directly instead.
     constof(T) template foo(T)(T v) { ... }

I'm willing to be convinced, but so far it's not clear to me that "template xx(S T)" would be all that useful in practice.

--bb
January 27, 2007
Frits van Bommel wrote:

> So it defaults to the *smallest* character type that can hold it in one element.
> Pretty cool, actually.
> 
> This also applies to other types, by the way. If you type an integer literal that won't fit into an 'int', it'll be a 'long' constant (assuming it fits), not an 'int' constant.
> 
> Perhaps we should do something similar with string literals, defaulting it to use an array of the smallest character type that can hold all of the characters in the string (i.e. the maximum "character type" of the component characters) ?

And while you're at it do the same for integer and float literals -- use the "best" type considering _all_ the elements rather than just the first one so that this doesn't mean an array with two 1 integers.

   [1, 1.5];

--bb
January 29, 2007
Frits van Bommel wrote:
> kris wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> kris wrote:
>>> [about implicit conversion rules]
>>>>         void write (char[] x) {printf("char[]\n");}
>>>>         void write (wchar[] x) {printf("wchar[]\n");}
>>>>         //foo.write ("asa");
>>>> 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.

A slight inconsistency here is that:

foo("test");

gives a syntax error, while:

auto t = "test";
foo(t);

compiles and selects the char[] overload. Also:

void bar(T)(T x) { foo(x); }
...
bar("test");

compiles and selects the char[] overload.

> It's a bit more complicated with character literals than just defaulting to 'char':
[snip typeof('e') == char, typeof('é') == wchar, ...]]
> So it defaults to the *smallest* character type that can hold it in one element.
> Pretty cool, actually.

A problem related to this, that might actually warrant a bug report, is that given:

char[] str = "abcd";

str ~= 'e';
writefln(str);

Is OK, while

str ~= 'é';
writefln(str);

Generates an invalid UTF-8 string ant gives the runtime "Error: 4invalid UTF-8 sequence"

It seems like the wchar 'é' gets int-promoted to 0xE9 that is different from the char[] (utf-8) representation of "é", that would be x"C3 A9".

-- 
/Oskar
January 29, 2007
Oskar Linde wrote:
> Frits van Bommel wrote:
>> It's a bit more complicated with character literals than just defaulting to 'char':
> [snip typeof('e') == char, typeof('é') == wchar, ...]]
>> So it defaults to the *smallest* character type that can hold it in one element.
>> Pretty cool, actually.
> 
> A problem related to this, that might actually warrant a bug report, is that given:
> 
> char[] str = "abcd";
> 
> str ~= 'e';
> writefln(str);
> 
> Is OK, while
> 
> str ~= 'é';
> writefln(str);
> 
> Generates an invalid UTF-8 string ant gives the runtime "Error: 4invalid UTF-8 sequence"
> 
> It seems like the wchar 'é' gets int-promoted to 0xE9 that is different from the char[] (utf-8) representation of "é", that would be x"C3 A9".

Yes, that probably warrants a bug report. Either an error should be produced (something like "Invalid operation: str ~= 'é', cannot concatenate wchar to char[]"), or (preferably) it should just work.
The latter can (for example) be implemented by doing the equivalent of std.utf.encode(str, 'é'), or the equivalent of str ~= "é" (note the quotes, implicitly converting it to char[] instead of wchar).
1 2 3 4 5 6 7
Next ›   Last »