digitalmars.D - preview in: it seems that return type auto solves scope variable
- Dmytro Katyukha (62/62) Feb 09 Hi,
- Dennis (8/11) Feb 09 When calling a member function like `other.toAbsolute`, you're
- Dmytro Katyukha (34/45) Feb 09 Hi, thank you. Got it)
- tsbockman (41/73) Feb 09 `scope` restricts what a function's implementation can do, while
Hi, Not sure it is bug, or feature, or what is going on in examples below (with `-preview=in` enabled). For example, we have following code snippet: ```d import std.stdio; import std.path; struct Path { private string _path; safe pure nothrow this(in string path) { _path = path.dup; } safe pure nothrow this(in string[] segments...) { this(std.path.buildNormalizedPath(segments)); } /// Check if current path is inside other path safe bool isInside(in Path other) const { import std.algorithm: startsWith; return this.toAbsolute.segments.startsWith( other.toAbsolute.segments); } safe Path toAbsolute() const { return Path( std.path.buildNormalizedPath( std.path.absolutePath(_path.dup.expandTilde))); } safe pure auto segments() const { return std.path.pathSplitter(_path); } } unittest { assert(Path("my", "dir", "42").isInside(Path("my", "dir")) == true); assert(Path("my", "dir", "42").isInside(Path("oth", "dir")) == false); } void main() { auto p = Path("."); auto h = Path("~"); auto r = p.isInside(h); } ``` Without `-preview=in` option, this code sample works just fine. But when i enable `-preview=in` (or just manualy replace `in` with `scope const` in `isInside` method) it fails with following error: ``` source/app.d(19,13): Error: scope variable `other` assigned to non-scope parameter `this` calling `toAbsolute` ``` So, the first question is: where in this code assignment to `this` happens? But, what is more strange, is that if i change return type for method `toAbsolute` to `auto`, error disappears: ```diff - safe Path toAbsolute() const { + safe auto toAbsolute() const { ``` So, the second question is: what happens in this case? PS: What is the status of preview `in`? Do it have sense to take it into account?
Feb 09
On Thursday, 9 February 2023 at 17:42:00 UTC, Dmytro Katyukha wrote:So, the first question is: where in this code assignment to `this` happens?When calling a member function like `other.toAbsolute`, you're assigning `other` to the implicit `this` parameter, as if you are calling `toAbsolute(this: other)`.So, the second question is: what happens in this case?Functions with `auto` return get attributes inferred, just like template functions. The compiler infers `scope` based on the implementation of `toAbsolute`.
Feb 09
On Thursday, 9 February 2023 at 17:59:39 UTC, Dennis wrote:On Thursday, 9 February 2023 at 17:42:00 UTC, Dmytro Katyukha wrote:Hi, thank you. Got it) So, the next questions: - Do it have sense to explicitly annotate all (most) member methods of a struct with `scope` attribute? Or it is better to use `auto` everywhere?. - What drawbacks of annotating all (most) parameters as scope? Is it correct approach? - What about `in` parameter attribute? Why it is not used wide in Phobos? How to correctly call method from standard lib (for example [expandTilde](https://dlang.org/phobos/std_path.html#expandTilde)) that does not annotated param with `scope` attribute? For example: ```d safe unittest { scope string p1 = "~/projects/d"; scope string p2 = expandTilde(p1); assert(p1 != p2); } ``` In this case, following error raised: ``` source/app.d(41,35): Error: scope variable `p1` assigned to non-scope parameter `inputPath` calling `expandTilde` ``` Is it correct, to use `.dup` method? ```diff safe unittest { scope string p1 = "~/projects/d"; - scope string p2 = expandTilde(p1); + scope string p2 = expandTilde(p1.dup); assert(p1 != p2); } ```So, the first question is: where in this code assignment to `this` happens?When calling a member function like `other.toAbsolute`, you're assigning `other` to the implicit `this` parameter, as if you are calling `toAbsolute(this: other)`.So, the second question is: what happens in this case?Functions with `auto` return get attributes inferred, just like template functions. The compiler infers `scope` based on the implementation of `toAbsolute`.
Feb 09
On Thursday, 9 February 2023 at 21:28:54 UTC, Dmytro Katyukha wrote:So, the next questions: - Do it have sense to explicitly annotate all (most) member methods of a struct with `scope` attribute? ... - What drawbacks of annotating all (most) parameters as scope?`scope` restricts what a function's implementation can do, while giving more freedom to the caller. (Mostly, this is the freedom to allocate less things with the GC.) This is generally a good thing, provided that you understand when `scope` and `return scope` apply well enough not to be slowed down or confused by them too much. Of course, sometimes you will actually have a good reason to escape a reference to a global or whatever, and `scope` doesn't do anything for types without indirections, so obviously you shouldn't put `scope` *everwhere*.Or it is better to use `auto` everywhere?.Whether it is better to explicitly write out attributes and types, or have the compiler infer them via `auto` and/or templatization, depends on whether you want the compiler to give you an error message if you change the implementation in a way that alters the API, and how you value explicit documentation of the API versus keeping your code concise. I recommend being as explicit as practical for public APIs, and for any aspect of any API that is fundamental to its purpose. (For example, a function intended to be used in CTFE should be explicitly `pure`.) Just be careful not to over-constrain template APIs without a good reason.- What about `in` parameter attribute? Why it is not used wide in Phobos?Most of Phobos was written before the semantics of `in` or `scope` were finalized. That's why there is `-preview=in` and `-dip1000`, because them actually working is a somewhat new, work-in-progress feature.How to correctly call method from standard lib (for example [expandTilde](https://dlang.org/phobos/std_path.html#expandTilde)) that does not annotated param with `scope` attribute?If there is no obvious valid reason for the function to be escaping one of its parameters, it's likely a bug in Phobos - a bit of code that hasn't been fully updated yet for `-dip1000`. This is especially likely to be the case if the parameter in question is not `immutable`.For example: ```d safe unittest { scope string p1 = "~/projects/d"; scope string p2 = expandTilde(p1); assert(p1 != p2); } ``` In this case, following error raised: ``` source/app.d(41,35): Error: scope variable `p1` assigned to non-scope parameter `inputPath` calling `expandTilde` ``` Is it correct, to use `.dup` method? ```diff safe unittest { scope string p1 = "~/projects/d"; - scope string p2 = expandTilde(p1); + scope string p2 = expandTilde(p1.dup); assert(p1 != p2); } ```Either use `.dup`, `.idup`, or don't make `p1` `scope` in the first place. The last option is preferred if you know you would otherwise need to `.dup` the majority of the time. Also, the compiler is generally pretty good about inferring `scope` where needed for local stack variables, so `scope` should mostly only appear explicitly when receiving `scope` parameters, not when sending them.
Feb 09