www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How can I tell D that function args are nogc etc.

reply John Dougan <jdougan acm.org> writes:
Below is a example program that illustrates my issue.

When compiled at run.dlang I get:
```
onlineapp.d(18): Error: ` safe` function 
`onlineapp.processSafely!(1, 4).processSafely` cannot call 
` system` function pointer `shouldDo`
onlineapp.d(28): Error: template instance 
`onlineapp.processSafely!(1, 4)` error instantiating
```

Why isn't this working? How can I get the effect I want?

Cheers,
-- john

```
bool[7] stagesToProcess = false;

 nogc nothrow  safe bool shouldDoInStages(int index)
{
     return stagesToProcess[index];
}

 nogc nothrow  safe bool shouldDoNever(int index)
{
     return false;
}

template processSafely(int low, int high)
{
     alias ShouldDoFnT =  nogc nothrow  safe bool function(int);

      nogc nothrow  safe uint processSafely(ShouldDoFnT shouldDo)
     {
         assert(low < high);
         uint stepsProcessed;
         for (int ii = low; ii <= high; ii++)
         {
             if (shouldDo(ii))
             {
                 stepsProcessed++;
             }
         }
         return stepsProcessed;
     }
}

void main()
{
     stagesToProcess = [false, false, true, true, false, true, 
false];
     uint count = processSafely!(1, 4)(&shouldDoInStages);
     assert(count == 2);
}
```
Apr 09
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
Place your attributes on the right hand side of the function, not the 
left side.

Use the left side for attributes/type qualifiers that go on the return type.

```d
bool[7] stagesToProcess = false;

bool shouldDoInStages(int index)  nogc nothrow  safe
{
      return stagesToProcess[index];
}

bool shouldDoNever(int index)  nogc nothrow  safe
{
      return false;
}

template processSafely(int low, int high)
{
      alias ShouldDoFnT = bool function(int)  nogc nothrow  safe;

      uint processSafely(ShouldDoFnT shouldDo)  nogc nothrow  safe
      {
          assert(low < high);
          uint stepsProcessed;
          for (int ii = low; ii <= high; ii++)
          {
              if (shouldDo(ii))
              {
                  stepsProcessed++;
              }
          }
          return stepsProcessed;
      }
}

void main()
{
      stagesToProcess = [false, false, true, true, false, true,
false];
      uint count = processSafely!(1, 4)(&shouldDoInStages);
      assert(count == 2);
}
```
Apr 10
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Wednesday, 10 April 2024 at 11:34:06 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 Place your attributes on the right hand side of the function, 
 not the left side.

 Use the left side for attributes/type qualifiers that go on the 
 return type.
Just a word of warning, this explanation suggests putting qualifiers on the left side would affect the return type, this is not the case. Attributes apply to the *declaration*. In some cases this effectively applies to the return type, in some cases it applies to the function, in some cases it applies to the context pointer. In order to apply type constructors to the return type, you need to use parentheses: ```d const int foo(); // const applies to the context pointer of `foo`, not `int` const(int) bar(); // const applies to `int` return type ref int baz(); // ref applies to `baz`, which in turn means "ref returning function" ``` Where this becomes tricky is return types that are function pointers/delegates. Then using the right side of the function/delegate *type* is the only way. ```d safe void function() foo(); // `foo` is safe, the function pointer it returns is not void function() safe bar(); // `bar` is not safe, the function pointer returned is void function() safe baz() safe; // both are safe ``` -Steve
Apr 10
parent reply John Dougan <jdougan acm.org> writes:
Interesting. Thank you to both of you.

On Wednesday, 10 April 2024 at 17:38:21 UTC, Steven Schveighoffer 
wrote:
 On Wednesday, 10 April 2024 at 11:34:06 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 Place your attributes on the right hand side of the function, 
 not the left side.

 Use the left side for attributes/type qualifiers that go on 
 the return type.
Just a word of warning, this explanation suggests putting qualifiers on the left side would affect the return type, this is not the case.
So in my example, what did I actually tell the compiler with the placement of the attributes? And how was it different between the function type alias declaration, and the actual function declaration? More specifically, what are the semantic differences below? ```d alias FnPrefixT = nogc nothrow safe bool function(int); // Versus alias FnSuffixT = bool function(int) nogc nothrow safe; ``` and ```d nogc nothrow safe bool fnPrefix(int) { stuff } // Versus bool fnSuffix(int) nogc nothrow safe { stuff } ``` Is there a reasonably clear overview of how this works anywhere? What I have seen so far led me to the vague impression that it wasn't significant just like attribute ordering. -- john
Apr 10
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Thursday, 11 April 2024 at 03:17:36 UTC, John Dougan wrote:
 Interesting. Thank you to both of you.

 On Wednesday, 10 April 2024 at 17:38:21 UTC, Steven 
 Schveighoffer wrote:
 On Wednesday, 10 April 2024 at 11:34:06 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 Place your attributes on the right hand side of the function, 
 not the left side.

 Use the left side for attributes/type qualifiers that go on 
 the return type.
Just a word of warning, this explanation suggests putting qualifiers on the left side would affect the return type, this is not the case.
So in my example, what did I actually tell the compiler with the placement of the attributes? And how was it different between the function type alias declaration, and the actual function declaration? More specifically, what are the semantic differences below? ```d alias FnPrefixT = nogc nothrow safe bool function(int); // Versus alias FnSuffixT = bool function(int) nogc nothrow safe; ```
So D can provide a nice mechanism to show what is happening -- `pragma(msg, ...)` If I do that with the two types above I see something *very* interesting: ```d pragma(msg, FnPrefixT); pragma(msg, FnSuffixT); ``` ``` bool function(int) nothrow nogc bool function(int) nothrow nogc safe ``` That surprises me. `nothrow` and ` nogc` go onto the type, but not ` safe` if put before the declaration? I have no idea why. All I can think of is that it is a bug.
 and
 ```d
  nogc nothrow  safe bool fnPrefix(int) { stuff }
 // Versus
 bool fnSuffix(int)  nogc nothrow  safe  { stuff }
 ```
```d pragma(msg, typeof(fnPrefix)); pragma(msg, typeof(fnSuffix)); ``` ``` nothrow nogc safe bool(int) nothrow nogc safe bool(int) ``` (as expected) -Steve
Apr 11
parent reply John Dougan <jdougan acm.org> writes:
On Thursday, 11 April 2024 at 15:00:49 UTC, Steven Schveighoffer 
wrote:
 So D can provide a nice mechanism to show what is happening -- 
 `pragma(msg, ...)`

 If I do that with the two types above I see something *very* 
 interesting:

 ```d
 pragma(msg, FnPrefixT);
 pragma(msg, FnSuffixT);
 ```

 ```
 bool function(int) nothrow  nogc
 bool function(int) nothrow  nogc  safe
 ```

 That surprises me. `nothrow` and ` nogc` go onto the type, but 
 not ` safe` if put before the declaration? I have no idea why. 
 All I can think of is that it is a bug.
`pragma(msg,...)` is very useful. Thanks. My general impressions were correct then. It shouldn't matter on which side the attrs get put, except in some ambiguous cases. It's just broken. Not every day you get to blame a compiler bug. Feeding: ```d alias FnPrefixT = safe nothrow nogc bool function(int); alias FnSuffixT = bool function(int) safe nothrow nogc ; pragma(msg, FnPrefixT); pragma(msg, FnSuffixT); void main() { return; } ``` into run.dlang and having it compile with all the compilers...gets the same result all the way back to 2.060. It has this issue with gdc 2.076, which is what I'm using normally. What is the procedure for bug reporting? I'm looking at the issues tracker and have no clue how to drive the search to see if this is already there.
 -Steve
-- john
Apr 11
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 12 April 2024 at 03:57:40 UTC, John Dougan wrote:

 What is the procedure for bug reporting? I'm looking at the 
 issues tracker and have no clue how to drive the search to see 
 if this is already there.
https://issues.dlang.org While entering the bug title, it does a fuzzy search for existing open and closed issues. -Steve
Apr 12
parent John Dougan <jdougan acm.org> writes:
On Friday, 12 April 2024 at 15:08:50 UTC, Steven Schveighoffer 
wrote:
 On Friday, 12 April 2024 at 03:57:40 UTC, John Dougan wrote:

 What is the procedure for bug reporting? I'm looking at the 
 issues tracker and have no clue how to drive the search to see 
 if this is already there.
https://issues.dlang.org While entering the bug title, it does a fuzzy search for existing open and closed issues.
The typical problem with issue/bug database searches is you have to know the important discriminating keywords that projects evolve over time. When you are new to a system, as I am with D, you end up looking manually through a lot of possibles. Another barrier to noobs that project long timers may not notice. Any rate, it appears https://issues.dlang.org/show_bug.cgi?id=22046 is the same issue. And I'm not sure how to interpret it, as a noob I don't have enough context. It appears to be deliberate and also afflicts var declarations. Since 2014. From my point of view, either it's still a bug and needs to be written up in a best practices list with all the other long term stuff you need to work around until it can be fixed (eg. "in alias and var function declarations, put attributes as a suffix because...", https://dlang.org/dstyle.html *might* be a place), or it has aged in to become the effective intended behavior and should be documented other places and have a compiler error or warning (" safe in prefix position in alias, is ignored"). Or of course, it could get fixed but my experiences have shown me that after 10 years that is low probability with most projects. I'm not trying to be a dick here. I've managed projects and know what unintentional dumb stuff can happen. But, at the moment, I'm evaluating D for a project (porting 30,000 lines of very old C with strict timing requirements) and I've got some time to build impressions of system language candidates. There appears to be a lot of talk from time to time over in General about luring new people in to work with D, and this kind of issue is relevant.
 -Steve
--john
Apr 12
prev sibling parent Monkyyy <crazymonkyyy gmail.com> writes:
On Friday, 12 April 2024 at 03:57:40 UTC, John Dougan wrote:
  Not every day you get to blame a compiler bug.
D is uniquely: hacky, expressive and buggy. Having more metaprograming then c++ without the raw man power comes at a cost, in d you should distrust the spec and instead see what the compiler actually does far more then any other languge.
 -- john
-- monkyyy
Apr 13