ref int c() { static int a=2; return a; }
ref int function() d = &c; // line 8
foo.d(8): variable foo.d only parameters or foreach declarations can be ref
Type inference, however, is able to figure it out:
ref int c() { static int a=2; return a; }
auto d = &c; // whee
Correctly reporting the issue from bug 2735
Comment #1 by smjg — 2009-03-21T17:34:35Z
The problem seems to be an ambiguity in the grammar: is it ref (int function()) or (ref int) function()?
Maybe we need a bracket notation for ref like we have for const and invariant.
Note that, if we have both this and the notation proposed in bug 1961, ref and inout would no longer be synonyms.
Comment #2 by dfj1esp02 — 2009-03-22T03:00:31Z
judging from compiler error messages, ref is not a type modifier, it's a function attribute, so brackets won't help. It should also be noted, that others function attributes' grammar is also ambiguous.
---
nothrow int function() foo();
---
What is nothrow here?
---
const int foo();
---
What is const here?
---
int foo(ref int function() goo);
---
This one would probably give no error.
Is it keyword saving issue? Semantically different things have the same syntax. If Walter wants context-dependent keywords, he should mark those contexts better.
I would like to see function attributes at predictable, easy-to-spot locations, so it would be no chanse to mess storage class with function attributes. There are already good places for function attributes (after function) and storage class attributes (before type). If the attributes will be restricted to corresponding places, there will be no ambiguity (except const).
---
int foo(ref int function() goo); //ref parameter
int goo(int function() ref foo); //return byref function
---
Comment #3 by smjg — 2009-03-22T16:50:34Z
(In reply to comment #2)
> judging from compiler error messages, ref is not a type modifier, it's a
> function attribute, so brackets won't help.
I'm a little confused - if that were the case, surely it would work?
Moreover, what is there preventing ref from becoming a type modifier, if this would fix the problem?
It should also be noted, that
> others function attributes' grammar is also ambiguous.
> ---
> nothrow int function() foo();
> ---
> What is nothrow here?
So there's actually an advantage to the suffix notation for function attributes.
> ---
> const int foo();
> ---
> What is const here?
>
> ---
> int foo(ref int function() goo);
> ---
> This one would probably give no error.
But that is a case that really is ambiguous.
> Is it keyword saving issue? Semantically different things have the same syntax.
> If Walter wants context-dependent keywords, he should mark those contexts
> better.
> I would like to see function attributes at predictable, easy-to-spot locations,
> so it would be no chanse to mess storage class with function attributes. There
> are already good places for function attributes (after function) and storage
> class attributes (before type). If the attributes will be restricted to
> corresponding places, there will be no ambiguity (except const).
> ---
> int foo(ref int function() goo); //ref parameter
> int goo(int function() ref foo); //return byref function
> ---
I don't really like this. The ref essentially means the same thing, it's just whether it applies to the parameter or the return. In the latter, it's being moved further from what it applies to: the return type.
IIRC, the equivalent C++ syntax is
int foo(int (*&goo)()); // ref parameter
int goo(int& (*foo)()); // ref return in parameter
It isn't exactly clear, but at least it's unambiguous. If D got the & notation for reference, we would have
int foo(int function()& goo); // ref parameter
int goo(int& function() foo); // ref return in parameter
Indeed, we could have ref take the place of & in this notation
int foo(int function() ref goo); // ref parameter
int goo(int ref function() foo); // ref return in parameter
and so the syntax of ref/& would become consistent with that of *.
We could do it like this, or we could make ref a type modifier along the lines of const. Take your pick.
Comment #4 by dfj1esp02 — 2009-03-24T04:17:38Z
(In reply to comment #3)
> int foo(int function() ref goo); // ref parameter
> int goo(int ref function() foo); // ref return in parameter
Providing the place between return type and function name for function attributes... interesting...
Comment #5 by smjg — 2009-03-24T04:26:03Z
(In reply to comment #4)
> (In reply to comment #3)
>> int foo(int function() ref goo); // ref parameter
>> int goo(int ref function() foo); // ref return in parameter
> Providing the place between return type and function name for function
> attributes... interesting...
Any particular reason you feel it still has to count as a function attribute?
Comment #6 by dfj1esp02 — 2009-03-26T03:46:40Z
1) if it can why not?
2) this is usable for other function attributes
Comment #7 by yebblies — 2011-06-06T19:46:53Z
*** Issue 5421 has been marked as a duplicate of this issue. ***
Comment #8 by yebblies — 2011-06-06T21:26:33Z
*** Issue 5828 has been marked as a duplicate of this issue. ***
Comment #9 by bugzilla — 2012-01-23T00:34:00Z
ref is a storage class - not a function attribute or type modifier. The grammar isn't broken, it's just a quirk in it. Changing it would be an enhancement request.
Comment #10 by qs.il.paperinik — 2022-10-25T13:59:07Z
@Walter: It is “broken” in the sense that the grammar should(!) be able to express a type without requiring type aliases.
I’d suggest minimal changes to the Type grammar to allow for it.
TL;DR: The semantics is obvious, I hope. Let’s allow the following:
```d
ref (int function()) f1();
(ref int function()) f2();
void g1(ref (int function()) fp);
void g2((ref int function()) fp);
void hImpl(DG : ref int delegate())(DG dg) { }
alias h = fImpl!(ref int delegate() @safe);
```
――― End of TL;DR ―――
Note that `f1` and `g1` are equivalent to:
```d
ref int function() f1();
void g1(ref int function() fp);
```
In the grammar, I use `?` to signify optional occurrence.
```diff
Type:
TypeCtors? BasicType TypeSuffixes?
+ ref TypeCtors? BasicType CallableSuffix TypeSuffixes?
BasicType:
FundamentalType
. QualifiedIdentifier
QualifiedIdentifier
Typeof
Typeof . QualifiedIdentifier
− TypeCtor ( Type )
+ TypeCtor? ( Type )
Vector
TraitsExpression
MixinType
TypeSuffix:
*
[ ]
[ AssignExpression ]
[ AssignExpression .. AssignExpression ]
[ Type ]
+ CallableSuffix
+
+ CallableSuffix:
delegate Parameters MemberFunctionAttributes?
function Parameters FunctionAttributes?
```
(This grammar diff does not address the special casing for `alias` that is currently in place and superseded by this. As far as I can tell, it’ll be still good and should not be changed.)
It is worth considering to deprecate the syntax without disambiguating parentheses, akin to comparison and bit-wise operators and `() => { }`. The deprecation only applies to cases where a non-aliased function pointer or delegate type is used on a `ref` parameter or as the return type of a `ref` returning function.
@ntrel updated dlang/dmd pull request #15243 "[new syntax] Support `function` `ref` Type Parameters for function pointer types" fixing this issue:
- Fix Issue 2753 - Cannot declare pointer to function returning ref.
https://github.com/dlang/dmd/pull/15243
Comment #13 by dlang-bot — 2023-05-17T17:08:05Z
@Bolpat updated dlang/dmd pull request #15245 "Fix Issue 2753" fixing this issue:
- Fix issue 2753 - add good case tests
https://github.com/dlang/dmd/pull/15245
@Bolpat created dlang/dmd pull request #15269 "Primary Type Syntax" fixing this issue:
- Fix issue 2753 - add good case tests
https://github.com/dlang/dmd/pull/15269
Comment #16 by nick — 2023-11-08T10:38:56Z
*** Issue 21521 has been marked as a duplicate of this issue. ***
Comment #17 by nick — 2024-10-19T10:00:20Z
(In reply to anonymous4 from comment #2)
> int goo(int function() ref foo); //return byref function
Allowing that would seem to be a simple fix to the problem, except now it would be confusing with the `return ref` attribute. The latter didn't exist when you wrote that though.
Comment #18 by smjg — 2024-10-19T10:23:51Z
(In reply to Nick Treleaven from comment #17)
> (In reply to anonymous4 from comment #2)
>> int goo(int function() ref foo); //return byref function
>
> Allowing that would seem to be a simple fix to the problem, except now it
> would be confusing with the `return ref` attribute. The latter didn't exist
> when you wrote that though.
I stand by what I said before. It makes no sense to me to have the notation for "reference to an integer" split in two like this. To me, that notation reads as declaring foo as a byref parameter, not as a parameter of function-with-byref-return type. I think most people would agree. Hence my earlier proposal:
> int foo(int function() ref goo); // ref parameter
> int goo(int ref function() foo); // ref return in parameter
Here, the 'ref' would be exactly the same as '*' for pointers and '[]' for arrays in terms of how it is placed. That 'ref' is a keyword rather than a symbol shouldn't have to make any difference to this.
Comment #19 by nick — 2024-10-19T11:51:27Z
> int foo(int function() ref goo); // ref parameter
Again, that is going to be confusing with the `return ref` attribute. (And it looks weird having a parameter storage class not come first).
>> int goo(int ref function() foo); // ref return in parameter
> Here, the 'ref' would be exactly the same as '*' for pointers and '[]' for
arrays in terms of how it is placed
It would be a simple fix to the problem, though it might make people think `ref` is a type modifier.
Comment #20 by smjg — 2024-10-19T12:26:30Z
(In reply to Nick Treleaven from comment #19)
> > int foo(int function() ref goo); // ref parameter
>
> Again, that is going to be confusing with the `return ref` attribute. (And
> it looks weird having a parameter storage class not come first).
Is the distinction between "storage class" and "type modifier" syntactic or semantic? I'm not sure where to find the exact definitions of these terms. dlang.org implies both in different places for "storage class", and I can't seem to find anything for "type modifier".
If syntactic, then how would 'ref' be a storage class under such a syntax? This would surely mean '*' and '[]' are already storage classes, so if that's a problem then it's already a problem for these.
If semantic, I would need to understand the definitions better to comment further.
Comment #21 by robert.schadek — 2024-12-13T17:49:36Z