www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - scope parameter has effect only on pointers?

reply Neto <netorib94 gmail.com> writes:
this give the error:

```d
 safe:
int *gp2;
int g(scope int *p)
{
	gp2 = p;
	return -1;
}
```

  Error: scope variable p assigned to non-scope gp2
but this one doesn't give any error: ```d safe: int gg; int f(scope int c) { int k = c; gg = c; return k * 8; } ``` this is why `c` is a "simple variable" can be allocated onto stack and copied without any issue? if not, why exactly this one doesn't give error?
Jun 22
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 23/06/2025 3:08 AM, Neto wrote:
 this give the error:
 
 ```d
  safe:
 int *gp2;
 int g(scope int *p)
 {
      gp2 = p;
      return -1;
 }
 ```
 
  Error: scope variable p assigned to non-scope gp2
but this one doesn't give any error: ```d safe: int gg; int f(scope int c) {     int k = c;     gg = c;     return k * 8; } ``` this is why `c` is a "simple variable" can be allocated onto stack and copied without any issue? if not, why exactly this one doesn't give error?
An int is a basic type, by itself it can live in a register and does not have a unique memory address. The location its in on the stack is irrelevant unless you take a pointer to it. In essence its a implementation detail. It'll move between locations freely, this is why scope doesn't affect it. Because there is no resource to protect.
Jun 22
parent reply Dom DiSc <dominikus scherkl.de> writes:
On Sunday, 22 June 2025 at 15:53:45 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 An int is a basic type, by itself it can live in a register and 
 does not have a unique memory address.

 The location its in on the stack is irrelevant unless you take 
 a pointer to it. In essence its a implementation detail.

 It'll move between locations freely, this is why scope doesn't 
 affect it. Because there is no resource to protect.
I think scope should not be allowed on basic types, as it has no effect and is only confusing. I know, it would be needed to enable generic programming, but I find a function that can take both an int and an int* suspect anyway - this is kind of too generic for my taste.
Jun 23
next sibling parent user1234 <user1234 12.de> writes:
On Monday, 23 June 2025 at 10:37:58 UTC, Dom DiSc wrote:
 I think scope should not be allowed on basic types, as it has 
 no effect and is only confusing.
 I know, it would be needed to enable generic programming, but I 
 find a function that can take both an int and an int* suspect 
 anyway - this is kind of too generic for my taste.
This is more about the fact that D has a long history when it's about not checking attributes or storage classes when they are noop. The situation toward that problem seems to be better than a few years ago, however things like ``` struct S { pure a = 0; } ``` are still compilable.
Jun 23
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Monday, 23 June 2025 at 10:37:58 UTC, Dom DiSc wrote:
 I know, it would be needed to enable generic programming, but I 
 find a function that can take both an int and an int* suspect 
 anyway - this is kind of too generic for my taste.
Would you say `HashMap!(Key, Value).opIndex(scope Key)` is too generic, and that `int[string]` and `int[int]` should have separate implementation code? I'm not against the compiler giving errors on no-op single attributes, but in some cases this can be complex for dmd's current implementation. For example, `pure T x;` has no effect unless T turns out to be a function type, which requires extra checks after `T` has been resolved. `scope` was internally removed from parameters by the compiler when the type had no pointers, but this caused forward reference errors: https://issues.dlang.org/show_bug.cgi?id=21667 Giving an error on no-op `scope` attributes has the exact same problem.
Jun 23
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, June 23, 2025 8:53:18 AM Mountain Daylight Time Dennis via
Digitalmars-d-learn wrote:
 On Monday, 23 June 2025 at 10:37:58 UTC, Dom DiSc wrote:
 I know, it would be needed to enable generic programming, but I
 find a function that can take both an int and an int* suspect
 anyway - this is kind of too generic for my taste.
Would you say `HashMap!(Key, Value).opIndex(scope Key)` is too generic, and that `int[string]` and `int[int]` should have separate implementation code? I'm not against the compiler giving errors on no-op single attributes, but in some cases this can be complex for dmd's current implementation. For example, `pure T x;` has no effect unless T turns out to be a function type, which requires extra checks after `T` has been resolved. `scope` was internally removed from parameters by the compiler when the type had no pointers, but this caused forward reference errors: https://issues.dlang.org/show_bug.cgi?id=21667 Giving an error on no-op `scope` attributes has the exact same problem.
There's also the issue of templated code. If an attribute is desirable in the cases where it works, and it's fine for it to be ignored in the cases where it doesn't apply, then that means that you can have code such as scope T foo; or pure T foo; without having to worry about whether the attribute works with a particular T. On the other hand, if it's an error for the attribute to be applied, then the code will need to do something like use a static if to apply the attribute, e.g. static if(isPointer!T || is(T == class) || isDynamicArray!T || isAssociativeArray!T) { scope T foo; } else T foo; and of course, if you get the check wrong, then the attribute won't be applied properly. So, if the attribute is no longer ignored, that will create certain classes of problems that we don't currently have. It's a different set of problems from the current situation, and it's debatable as to which situation is better or worse, but it's nowhere near as straightforward as it first seems. - Jonathan M Davis
Jun 23
parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Tuesday, 24 June 2025 at 02:05:40 UTC, Jonathan M Davis wrote:
 There's also the issue of templated code. If an attribute is 
 desirable in the cases where it works, and it's fine for it to 
 be ignored in the cases where it doesn't apply, then that means 
 that you can have code such as
 ```d
 scope T foo;
 ```
 or
 ```d
 pure T foo;
 ```
 without having to worry about whether the attribute works with 
 a particular T.

 On the other hand, if it's an error for the attribute to be 
 applied, then the code will need to do something like use a 
 static if to apply the attribute, e.g.
 ```d
 static if(isPointer!T || is(T == class) ||
           isDynamicArray!T || isAssociativeArray!T)
 {
     scope T foo;
 }
 else
     T foo;
 ```
 and of course, if you get the check wrong, then the attribute 
 won't be applied properly.
Getting the check wrong is fairly easy. The following cases are missing: `is(T == interface)`, `is(T == delegate)`, and maybe `is(typeof(*T.init) == function)` (I don’t know if `isPointer` catches function pointers). I’m not even sure those are all the missing cases.
Jun 27
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, June 27, 2025 10:31:42 AM Mountain Daylight Time Quirin Schroll
via Digitalmars-d-learn wrote:
 On Tuesday, 24 June 2025 at 02:05:40 UTC, Jonathan M Davis wrote:
 There's also the issue of templated code. If an attribute is
 desirable in the cases where it works, and it's fine for it to
 be ignored in the cases where it doesn't apply, then that means
 that you can have code such as
 ```d
 scope T foo;
 ```
 or
 ```d
 pure T foo;
 ```
 without having to worry about whether the attribute works with
 a particular T.

 On the other hand, if it's an error for the attribute to be
 applied, then the code will need to do something like use a
 static if to apply the attribute, e.g.
 ```d
 static if(isPointer!T || is(T == class) ||
           isDynamicArray!T || isAssociativeArray!T)
 {
     scope T foo;
 }
 else
     T foo;
 ```
 and of course, if you get the check wrong, then the attribute
 won't be applied properly.
Getting the check wrong is fairly easy. The following cases are missing: `is(T == interface)`, `is(T == delegate)`, and maybe `is(typeof(*T.init) == function)` (I don’t know if `isPointer` catches function pointers). I’m not even sure those are all the missing cases.
Yeah. I'd have to sit down and work through it to make sure that I found all of the cases. I just listed what I could think of off the top of my head, and this is the sort of thing where it's really easy to get it wrong. Looking at std.traits.hasIndirections, it lists what we've already mentioned plus types with context a pointer. And hasIndirections would _almost_ be the thing to use, but it also looks at the member variables. So, if you have a struct with a pointer, it would be true, whereas scope would have no effect on it, since from what I recall scope only goes one level deep. If we were going to make it so that scope were illegal on types where it had no effect, we'd either have to provide a trait for it that handled all of the cases, or you'd have to write out a condition that tried to put scope on a variable of that type to check whether it would compile, e.g. static if(is(typeof((){ scope T foo; }))) scope T foo; else T foo; Either way, templated code is just much easier and less error-prone to write if scope is ignored if it doesn't do anything, much as that might be confusing or annoying in some situations. - Jonathan M Davis
Jun 27