On Monday, 12 July 2021 at 23:18:57 UTC, jfondren wrote:
On Monday, 12 July 2021 at 22:35:27 UTC, someone wrote:
Bug: `scope` makes no sense if you want to return `lstrSequence` (throughout).

Teach me please: if I declare a variable right after the function declaration like this one ... ain't scope its default visibility ? I understand (not quite sure whether correct or not right now) that everything you declare without explicitly stating its visibility (public/private/whatever) becomes scope ie: what in many languages are called a local variable. What actually is the visibility of lstrSequence without my scope declaration ?

Local variables don't have a visibility in the sense of public or private. They do have a 'scope' in the general computer science sense, and a variable can be said to be in or out of scope at different points in a program, but this is the case without regard for whether the variable is declared with D's `scope`. What `scope` says is https://dlang.org/spec/attribute.html#scope

For local declarations, scope ... means that the destructor for an object is automatically called when the reference to it goes out of scope.

The value of a normal, non-scope local variable has a somewhat indefinite lifetime: you have to examine the program and think about operations on the variable to be sure about that lifetime. Does it survive the function? Might it die even before the function completes? Does it live until the next GC collection or until the program ends? These are questions you can ask.

For a `scope` variable, the lifetime of its value ends with the scope of the variable.

Consider:

```d
import std.stdio : writeln, writefln;
import std.conv : to;
import core.memory : pureMalloc, pureFree;

class Noisy {
    static int ids;
    int* id;
    this() {
        id = cast(int*) pureMalloc(int.sizeof);
        *id = ids++;
    }

    ~this() {
        writefln!"[%d] I perish."(*id);
        pureFree(id);
    }
}

Noisy f() {
    scope n = new Noisy;
    return n;
}

void main() {
    scope a = f();
    writeln("Checking a.n...");
    writefln!"a.n = %d"(*a.id);
}
```

Which has this output on my system:

```d
[0] I perish.
Checking a.n...
Error: program killed by signal 11
```

Or with -preview=dip1000, this dmd output:

```d
Error: scope variable `n` may not be returned
```

the lifetime of the Noisy object bound by `scope n` is the same as the scope of the variable, and the varaible goes out of scope when the function returns, so the Noisy object is destructed at that point.

Some days ago I assumed scope was, as I previously stated, the local default scope, and explicitly added scope to all my *local* variables. Soon afterward I encountered a situation which gave me the "program killed by signal 11" which I did not fully-understand why it was happening at all, because it never occurred to me it was connected to my previous scope refactor. Now I understand.

Regarding -preview=dip1000 (and the explicit error description that could have helped me a lot back then) : DMD man page says the preview switch lists upcoming language features, so DIP1000 is something like a D proposal as I glanced somewhere sometime ago ... where do DIPs get listed (docs I mean) ?

So, every *local* variable within a chunk of code, say, a function, should be declared without anything else to avoid this type of behavior ? I mean, anything in code that it is not private/public/etc.

Or, as I presume, every *local* meaning *aux* variable that won't need to survive the function should be declared scope but *not* the one we are returning ... lstrSequence in my specific case ?

Can I declare everything *scope* within and on the last line using lstrSequence.dup instead ? dup/idup duplicates the variable (the first allowing mutability while the second not) right ?

Which one of the following approaches do you consider best practice if you were directed to explicitly state as much behavior as possible ?

Your reply with this example included was very illustrating to me -right to the point.

Thanks a lot for your time :) !

Reply via email to