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 :) !