digitalmars.D - D Primary Type Syntax is Essentially Implemented!
- Quirin Schroll (108/108) May 23 2023 #### Recap
- Richard (Rikki) Andrew Cattermole (7/11) May 23 2023 Are you sure that this is correct?
- Andrej Mitrovic (3/14) May 23 2023 Same, this is completely counter-intuitive to me.
- Olivier Pisano (2/20) May 23 2023 Same here.
- Quirin Schroll (7/29) May 24 2023 It's only the comments for `a` and `b` that are reversed. Still
- Quirin Schroll (4/15) May 24 2023 You're 100% right, I mixed it up. It's exactly the other way
- Basile B. (10/12) May 23 2023 I like this solution more than the [alterantivey
- Quirin Schroll (43/55) May 24 2023 Did you link the right PR? It seems you linked my PR calling it
- Nick Treleaven (16/48) Dec 21 2023 The solution seems to be more than what is required to solve the
- Nick Treleaven (8/12) Dec 21 2023 Sorry, that allows invalid types. Should be:
“D primary type syntax” is this recurrence: [`Type`](https://dlang.org/spec/type.html#Type) → [`BasicType`](https://dlang.org/spec/type.html#BasicType) [`BasicType`](https://dlang.org/spec/type.html#BasicType) → [`TypeCtor`](https://dlang.org/spec/type.html#TypeCtor)? **`(`**[`Type`](https://dlang.org/spec/type.html#Type)**`)`** (The novelty is that `TypeCtor` is optional.) This allows to add these additional grammar rules: [`Type`](https://dlang.org/spec/type.html#Type) → **`ref`** [`TypeCtors`](https://dlang.org/spec/type.html#TypeCtor)? [`BasicType`](https://dlang.org/spec/type.html#BasicType) *CallableSuffix* [`TypeSuffixes`](https://dlang.org/spec/type.html#TypeSuffix)? *CallableSuffix* → **`delegate`** [`Parameters`](https://dlang.org/spec/function.html#Parameters) [`MemberFunctionAttributes`](https://dlang.org/spec/function.html#MemberFunctionAttributes)? *CallableSuffix* → **`function`** [`Parameters`](https://dlang.org/spec/function.html#Parameters) [`FunctionAttributes`](https://dlang.org/spec/function.html#FunctionAttributes)? The goal was to make e.g. `(ref const int function() safe)[]` parse as a type. As of today, [this is possible](https://github.com/dlang/dmd/pull/15245). I borrowed the nomenclature of “primary types” from “primary expressions”: * Primary expressions are something like fundamental or parenthesized expressions. * Primary types (in D’s grammar: basic types) are something like fundamental types or parenthesized types. ```d // `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { } // Note: The parameter storage class has priority // over the value category of the parameter’s return type. // `c` is `a` without clarifiying parentheses. void c( ref int function() ) { } static assert(!is( typeof(&a) == typeof(&b) )); static assert( is( typeof(&a) == typeof(&c) )); ``` ```d // `x` returns by reference; the returned function ptr returns an `int` by value. // `y` returns by vale; the returned function ptr returns an `int` by reference. ref (int function()) x() { static typeof(return) fp = null; return fp; } (ref int function()) y() => null; // Note: The value category of the declared function has priority // over the value category of the return type. // `z` is `x` without clarifiying parentheses. ref int function() z() => x(); static assert(!is( typeof(&x) == typeof(&y) )); static assert( is( typeof(&x) == typeof(&z) )); ``` Especially pleasing is the congruence between function declaration and function type: ```d static int i = 0; ref int funcName() safe => i; (ref int delegate() safe) fptr = &funcName; ``` The parentheses are necessary. Not only is that an artifact of the implementation, but also the way I think it’s clearer. If we ever add `ref` local variables, they would change meaning. I also changed the pretty-print so that `ref` appears at the *beginning* of a function pointer or delegate type. This is where it should be according to my eye and the D grammar, but pretty-print gave us `ref` among `pure` and ` safe`. This meant that if you copied the type from the error message to your source file, it would not parse. Now, it will parse. (It might still not compile for other reasons, such as visibility.) With `pragma(msg)`: ```d pragma(msg, typeof( function ref int { static x = 0; return x; } )); // Old: int function() nothrow nogc ref safe // New: (ref int function() nothrow nogc safe) ``` With `.stringof`: ```d // Old: alias FP = ref int function(); static assert(FP.stringof == "int function() ref"); // New: static assert((ref int function()).stringof == "(ref int function())" ); // No alias required! ``` The parentheses on the right are somewhat intentional. I didn’t even try to make the pretty-print use parentheses only when necessary because it costs time and is not the main issue. As of now, it mindlessly inserts them. The pretty-print can be improved later. --- All the examples are tested and work as intended on my local machine. The code is [here](https://github.com/Bolpat/dmd/tree/patch-3). (I know the branch has a stupid name.) I hope you like it.
May 23 2023
Good work cleaning this up. On 24/05/2023 10:18 AM, Quirin Schroll wrote:|// `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { }|Are you sure that this is correct? I read this as `a` takes its parameter by reference; the argument returns by value. If this isn't what you intended its a little worrying because this is going to cause problems.
May 23 2023
On Tuesday, 23 May 2023 at 22:39:44 UTC, Richard (Rikki) Andrew Cattermole wrote:Good work cleaning this up. On 24/05/2023 10:18 AM, Quirin Schroll wrote:Same, this is completely counter-intuitive to me.|// `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { }|Are you sure that this is correct? I read this as `a` takes its parameter by reference; the argument returns by value. If this isn't what you intended its a little worrying because this is going to cause problems.
May 23 2023
On Wednesday, 24 May 2023 at 03:48:38 UTC, Andrej Mitrovic wrote:On Tuesday, 23 May 2023 at 22:39:44 UTC, Richard (Rikki) Andrew Cattermole wrote:Same here.Good work cleaning this up. On 24/05/2023 10:18 AM, Quirin Schroll wrote:Same, this is completely counter-intuitive to me.|// `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { }|Are you sure that this is correct? I read this as `a` takes its parameter by reference; the argument returns by value. If this isn't what you intended its a little worrying because this is going to cause problems.
May 23 2023
On Wednesday, 24 May 2023 at 05:15:27 UTC, Olivier Pisano wrote:On Wednesday, 24 May 2023 at 03:48:38 UTC, Andrej Mitrovic wrote:It's only the comments for `a` and `b` that are reversed. Still `a` and `c` are the same, which should have cleared things up. I'm sorry for the confusion. This is so embarrassing. The implementation is sane in your and the other commenters opinion. Unfortunately, the compiler has no AI to check if comments make sense. All the code is tested.On Tuesday, 23 May 2023 at 22:39:44 UTC, Richard (Rikki) Andrew Cattermole wrote:Same here.Good work cleaning this up. On 24/05/2023 10:18 AM, Quirin Schroll wrote:Same, this is completely counter-intuitive to me.|// `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { }|Are you sure that this is correct? I read this as `a` takes its parameter by reference; the argument returns by value. If this isn't what you intended its a little worrying because this is going to cause problems.
May 24 2023
On Tuesday, 23 May 2023 at 22:39:44 UTC, Richard (Rikki) Andrew Cattermole wrote:Good work cleaning this up. On 24/05/2023 10:18 AM, Quirin Schroll wrote:You're 100% right, I mixed it up. It's exactly the other way around.|// `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { }|Are you sure that this is correct? I read this as `a` takes its parameter by reference; the argument returns by value. If this isn't what you intended its a little worrying because this is going to cause problems.
May 24 2023
On Tuesday, 23 May 2023 at 22:18:35 UTC, Quirin Schroll wrote:[...] I hope you like it.I like this solution more than the [alterantivey proposed](https://github.com/dlang/dmd/pull/15245). Both work but yours try to be a bit more faithful to the language. The alternative can look more seducing because it's implemented by someone who knows his shits, so yeah it looks nicer, the checks are greens but it is based on a special case. I'm very "pro" your way, problem is that currently the implementation is not perfect (red checks).
May 23 2023
On Wednesday, 24 May 2023 at 00:24:38 UTC, Basile B. wrote:On Tuesday, 23 May 2023 at 22:18:35 UTC, Quirin Schroll wrote:Did you link the right PR? It seems you linked my PR calling it the alternative to the post.[...] I hope you like it.I like this solution more than the [alterantivey proposed](https://github.com/dlang/dmd/pull/15245).Both work but yours try to be a bit more faithful to the language. The alternative can look more seducing because it's implemented by someone who knows his shits, so yeah it looks nicer, the checks are greens but it is based on a special case.This is why I took every minute of time I had to draft an implementation. This was stupidly hard! The compiler (parser at least) isn’t exactly well-documented. I did that because there’s a tendency of quick and dirty solutions to stick. *Nichts ist zählebiger als ein Provisorium.* (German proverb; “Nothing’s more tenacious than a makeshift.”)I'm very "pro" your way, problem is that currently the implementation is not perfect (red checks).This was my first DMD PR that could be called a meaningful attempt. I definitely need help by “someone who knows his shits.” I tried to fix things so that the problems would be solved. --- If you (Basile B. or anyone reading this) would like to help, here’s a summary of the failed tests: 1. *CyberShadow/DAutoTest* checks that all the examples on the dlang.org website work. The one that fails is an intended breaking: `static assert(__traits(isSame, (e), 3))` (where `e` is an `enum` with value `3`) used to work but now fails. 2. *ci/circleci: build* has errors because “template instance `core.stdc.config._Complex!float` cannot resolve forward reference”. 3. I worked on the `fail_compilation`, but they still fail. (This accounts for a lot of failed tests, maybe even all except 1. and 2.) Comments: 1. This due to how `isSame` works: In essence, the reason is that, with the new grammar, `(e)` is not (necessarily) a primary expression anymore, therefore just putting parentheses around it is unsuited to force the evaluation as an expression; `(e)` becomes exactly equivalent to `e`, and `e` is a symbol, and `isSame` is always false if you compare a symbol with a literal. There’s two ways to tackle this: Change the example (e.g. use a cast) or change `isSame`. I’d prefer the former, but I don’t care much. 2. I don’t know what this means and I cannot reproduce this on my machine. The DMD files I changed I only touch the parser, but for all that I can tell this is a semantic problem. It even says that happened when instantiating the template, which has nothing to do with parsing. 3. The logs do not show the discrepancies of the expected and actual error messages, so it’s hard to know what is wrong. Maybe someone here knows how to get them.
May 24 2023
On Tuesday, 23 May 2023 at 22:18:35 UTC, Quirin Schroll wrote:```d // `a` takes its parameter by value; the parameter returns by reference. // `b` takes its parameter by reference; the parameter returns by value. void a( ref (int function()) ) { } void b((ref int function()) ) { } // Note: The parameter storage class has priority // over the value category of the parameter’s return type. // `c` is `a` without clarifiying parentheses. void c( ref int function() ) { } static assert(!is( typeof(&a) == typeof(&b) )); static assert( is( typeof(&a) == typeof(&c) )); ``` ```d // `x` returns by reference; the returned function ptr returns an `int` by value. // `y` returns by vale; the returned function ptr returns an `int` by reference. ref (int function()) x() { static typeof(return) fp = null; return fp; } (ref int function()) y() => null; // Note: The value category of the declared function has priority // over the value category of the return type. // `z` is `x` without clarifiying parentheses. ref int function() z() => x(); static assert(!is( typeof(&x) == typeof(&y) )); static assert( is( typeof(&x) == typeof(&z) )); ```The solution seems to be more than what is required to solve the `ref` problem. It also means we introduce multiple ways of spelling the same type. And as you found, it can break code: https://forum.dlang.org/post/eguzeiayudwqcvaencdf forum.dlang.org Instead, why not implement just the subset of this proposal that is actually needed - add this rule: ```md BasicType: `(` `ref` Type `)` ``` This rule doesn't allow `a` or `x`, yet allows `b` and `y`, and works for variable declarations. It doesn't conflict with any expression AFAIK. And if the full proposal is wanted later, the subset can be extended without breakage.
Dec 21 2023
On Thursday, 21 December 2023 at 15:34:11 UTC, Nick Treleaven wrote:``` BasicType: `(` `ref` Type `)` ```Sorry, that allows invalid types. Should be: ``` BasicType: ( ref Type delegate Parameters MemberFunctionAttributes? ) ( ref Type function Parameters FunctionAttributes? ) ```
Dec 21 2023