| |
| Posted by Quirin Schroll in reply to Meta | PermalinkReply |
|
Quirin Schroll
| On Sunday, 4 September 2022 at 14:45:15 UTC, Meta wrote:
> On Sunday, 4 September 2022 at 12:33:37 UTC, Mathias LANG wrote:
> On Sunday, 4 September 2022 at 11:03:53 UTC, Nick Treleaven wrote:
> On Friday, 2 September 2022 at 18:58:43 UTC, Ali Çehreli wrote:
> But I am aware that we can't deduce T to be 'int' because we would be losing that qualifier and further template deductions would be wrong. :/
Another feature that would be interesting is if an auto declaration stripped const/immutable where possible. After all, if the user didn't want that they could've used const or immutable .
const i = 4; // const int
auto v = i; // int
const a = [0]; // const(int[])
auto s = a; // const(int)[]
This has been discussed in another thread and Walter approved it. Just need to implement it.
He did? This is straight out of Scott Myers' "The Last Thing D Needs" talk. He uses almost the same code as an example too.
I ran into this while writing a DIP that “abused” const . In C++, const is a far lower guarantee and it’s more like a convention than actual compiler checking. I really dislike the fact that Walter made const(int*) become const(int)* as well as const(int[]) become const(int)[] when an object of the former types is passed to a function template as an argument which has its type inferred:
void f(T)(T x) { pragma(msg, "parameter: ", T); }
void main()
{
const int[] xs;
pragma(msg, "argument : ", typeof(xs));
f(xs);
const int* p;
pragma(msg, "argument : ", typeof(p));
f(p);
}
What I started to love about C# is that you feel almost no difference between built-in stuff and user-defined stuff. (One notable exception to this is C#’s const .)
In C++, there’s has been lot of work put in to give user-defined types the same possibilities that built-in types have.
In D, there’s much more special casing around built-in types that make meta-programming tedious. Some examples:
- Value-range propagation: Given
int x , x & 0x7FFF converts to short (but x alone requires cast(int) . Nice for concrete code, but in meta-programming code, it opens the door for hard-to-understand errors appearing.
- Aforementioned
const(int*) becoming const(int)* . That does not happen with custom struct S(T) automatically even in cases where it is provably correct, and there is no way to tell the D compiler that copies of const(S!int) are better understood to be S!(const int) .
- Types are keywords: With
alias we could have alias int = __traits(signed_integer_type, 32); etc. There were a lot of issues in the parser that could be avoided. If you think this leads to problems, note that string is such an alias already.
- Type constructors are hard-wired: If templates want to deconstruct a type, a lot of special cases have to be written because in
int* , int[] , int[10] , and int[string] , the * , [] , [N] , [T] is not syntactic sugar for (hypothetical) Ptr!int , Slice!int , Array!(int, 10) , and AssocArray!(string, int) , respectively, so those would be matched by void f(alias TT, T)(TT!T value) . Technically speaking, const , immutable etc. and function /delegate are type constructors as well, but those have additional things going on: e.g. const methods and a function’s parameters have more on them than their type (e.g., ref ). As in the bullet above: alias Ptr = __traits(pointer_type_ctor); , etc.
The Last Thing D Needs is the opposite of streamlining.
|