digitalmars.D.learn - safe question
- forkit (21/21) Jan 09 2022 Do not understand why one line is not considered @safe, but the
- Salih Dincer (27/48) Jan 09 2022 Try the @trusted and in/out:
- forkit (6/10) Jan 09 2022 thanks for introducing me to the in/out feature of D :-)
- Paul Backus (5/16) Jan 09 2022 Taking the address of a local variable is forbidden in @safe
- forkit (9/13) Jan 11 2022 but strings[] is also a local variable declared in the body of
- Paul Backus (14/28) Jan 11 2022 Because the compiler doesn't look at that much context, and it's
- forkit (4/11) Jan 11 2022 Thanks. Appreciate the explanation :-)
- Paul Backus (21/32) Jan 11 2022 In any statically typed language, there is always going to be
- forkit (4/13) Jan 11 2022 Thanks again. Really useful information.
- H. S. Teoh (14/30) Jan 11 2022 IMNSHO, that @trusted lambda thing is an anti-pattern that should be
- Paul Backus (9/18) Jan 11 2022 There's nothing wrong with @trusted lambdas. The recent FUD
Do not understand why one line is not considered safe, but the other is. //---- module test; import std; safe void main() { immutable string[] strings = ["one", "one", "two"]; immutable(string)*[] pointers = null; foreach(size_t i, ref str; strings) { if(str == "one") { //pointers ~= &str; // not allowed in safe ?? pointers ~= &strings[i]; // for safe, I have to revert to using an index into strings. } i++; } } //-----
Jan 09 2022
On Sunday, 9 January 2022 at 20:58:05 UTC, forkit wrote:Do not understand why one line is not considered safe, but the other is. //---- module test; import std; safe void main() { immutable string[] strings = ["one", "one", "two"]; immutable(string)*[] pointers = null; foreach(size_t i, ref str; strings) { if(str == "one") { //pointers ~= &str; // not allowed in safe ?? pointers ~= &strings[i]; // for safe, I have to revert to using an index into strings. } i++; } } //-----Try the trusted and in/out: ```d auto pro(in immutable string[] strings, out immutable(string)*[] pointers) trusted { foreach(i, ref str; strings) { if(str == "one") { //pointers ~= &strings[i]/* ok pointers ~= &str;//*/ } /* unnecessary: i++;//*/ } } safe void main() { immutable string[] strings = ["one", "one", "two"]; immutable(string)*[] pointers = null; strings.pro(pointers); assert(pointers[0] == &strings[0]); // ok assert(pointers[1] == &strings[1]); // ok } ```
Jan 09 2022
On Sunday, 9 January 2022 at 21:56:05 UTC, Salih Dincer wrote:Try the trusted and in/out: ... .. .thanks for introducing me to the in/out feature of D :-) I'll certainly look into that feature more. But my question still remains: //pointers ~= &str; // why is this *not* allowed in safe pointers ~= &strings[i]; // while this *is* allowed in safe
Jan 09 2022
On Monday, 10 January 2022 at 01:16:31 UTC, forkit wrote:On Sunday, 9 January 2022 at 21:56:05 UTC, Salih Dincer wrote:Taking the address of a local variable is forbidden in safe code. Even though str is a ref variable that points to a heap-allocated string, it is still considered a local variable because it is declared inside the body of a function.Try the trusted and in/out: ... .. .thanks for introducing me to the in/out feature of D :-) I'll certainly look into that feature more. But my question still remains: //pointers ~= &str; // why is this *not* allowed in safe pointers ~= &strings[i]; // while this *is* allowed in safe
Jan 09 2022
On Monday, 10 January 2022 at 03:21:46 UTC, Paul Backus wrote:Taking the address of a local variable is forbidden in safe code. Even though str is a ref variable that points to a heap-allocated string, it is still considered a local variable because it is declared inside the body of a function.but strings[] is also a local variable declared in the body of the same function, and yet within the foreach statement, safe lets me do: pointers ~= &strings[i]; // safe ...but not this below, where str is just a reference to the exact same memory as the statement above... is it not? How is this below any more or less safe than the above statement. pointers ~= &str; // not safe - ok, but why??
Jan 11 2022
On Tuesday, 11 January 2022 at 10:57:28 UTC, forkit wrote:On Monday, 10 January 2022 at 03:21:46 UTC, Paul Backus wrote:Because the compiler doesn't look at that much context, and it's possible to write code where `str` points to memory that's on the stack; for example: string[3] strings = ["foo", "bar", "baz"]; foreach (ref str; strings) { // ... } If you compile with -preview=dip1000, the compiler will actually keep track of which pointers point to stack memory, and will allow your original code. But -preview=dip1000 is still somewhat experimental, and the documentation for it is pretty sparse, so you may have an easier time just working around the limitations of the default safety checks.Taking the address of a local variable is forbidden in safe code. Even though str is a ref variable that points to a heap-allocated string, it is still considered a local variable because it is declared inside the body of a function.but strings[] is also a local variable declared in the body of the same function, and yet within the foreach statement, safe lets me do: pointers ~= &strings[i]; // safe ...but not this below, where str is just a reference to the exact same memory as the statement above... is it not? How is this below any more or less safe than the above statement. pointers ~= &str; // not safe - ok, but why??
Jan 11 2022
On Tuesday, 11 January 2022 at 14:54:51 UTC, Paul Backus wrote:.. If you compile with -preview=dip1000, the compiler will actually keep track of which pointers point to stack memory, and will allow your original code. But -preview=dip1000 is still somewhat experimental, and the documentation for it is pretty sparse, so you may have an easier time just working around the limitations of the default safety checks.Thanks. Appreciate the explanation :-) In the end though, correct code should just compile. I shouldn't need a 'work around' :-(
Jan 11 2022
On Tuesday, 11 January 2022 at 21:38:58 UTC, forkit wrote:On Tuesday, 11 January 2022 at 14:54:51 UTC, Paul Backus wrote:In any statically typed language, there is always going to be code which you, the programmer, know is correct, but which the compiler can't automatically prove is correct. The same is true for safety. If you know a particular bit of code is memory safe, but the compiler can't prove it, you can mark that code as trusted. For example: () trusted { pointers ~= &str; )(); This example uses an immediately-invoked function literal [1] (also known as a "lambda") to apply the trusted attribute to a single statement. Of course, when you write trusted code, you must be *very* sure that what you are doing cannot possibly lead to undefined behavior, no matter what happens in other parts of the program. There's a post on the official D blog, "How to Write trusted Code in D," [2] that talks about some of the most common pitfalls, and gives advice for avoiding them. [1] https://dlang.org/spec/expression.html#function_literals [2] https://dlang.org/blog/2016/09/28/how-to-write-trusted-code-in-d/.. If you compile with -preview=dip1000, the compiler will actually keep track of which pointers point to stack memory, and will allow your original code. But -preview=dip1000 is still somewhat experimental, and the documentation for it is pretty sparse, so you may have an easier time just working around the limitations of the default safety checks.Thanks. Appreciate the explanation :-) In the end though, correct code should just compile. I shouldn't need a 'work around' :-(
Jan 11 2022
On Tuesday, 11 January 2022 at 21:50:00 UTC, Paul Backus wrote:.. If you know a particular bit of code is memory safe, but the compiler can't prove it, you can mark that code as trusted. For example: () trusted { pointers ~= &str; )(); This example uses an immediately-invoked function literal [1] (also known as a "lambda") to apply the trusted attribute to a single statement. ...Thanks again. Really useful information. The more I use D, the more I feel that I'm falling into a deep, deep, deep....rabbit hole.
Jan 11 2022
On Wed, Jan 12, 2022 at 12:24:14AM +0000, forkit via Digitalmars-d-learn wrote:On Tuesday, 11 January 2022 at 21:50:00 UTC, Paul Backus wrote:IMNSHO, that trusted lambda thing is an anti-pattern that should be avoided, needless to say already promoted. It's papering over a problem that ought to be fixed instead of being pushed under the rug. If it takes -dip1000 to compile the OP's code, then I say, by all means, use -dip1000. It's not *that* hard to add a compile switch to your build. I know dip1000 isn't quite there yet, but how is it supposed to "get there" if everyone is avoiding to use it? We should rather be pushing more people to use it so that more flaws are discovered and fixed, rather than avoiding it and letting it languish, and 5 years later the same old flaws continue to sit unfixed. T -- People walk. Computers run... If you know a particular bit of code is memory safe, but the compiler can't prove it, you can mark that code as trusted. For example: () trusted { pointers ~= &str; )(); This example uses an immediately-invoked function literal [1] (also known as a "lambda") to apply the trusted attribute to a single statement. ...Thanks again. Really useful information. The more I use D, the more I feel that I'm falling into a deep, deep, deep....rabbit hole.
Jan 11 2022
On Wednesday, 12 January 2022 at 00:45:23 UTC, H. S. Teoh wrote:IMNSHO, that trusted lambda thing is an anti-pattern that should be avoided, needless to say already promoted. It's papering over a problem that ought to be fixed instead of being pushed under the rug.There's nothing wrong with trusted lambdas. The recent FUD around them is almost entirely unjustified.If it takes -dip1000 to compile the OP's code, then I say, by all means, use -dip1000. It's not *that* hard to add a compile switch to your build. I know dip1000 isn't quite there yet, but how is it supposed to "get there" if everyone is avoiding to use it?The reason I hesitate to recommend -preview=dip1000 to a beginning D programmer is that because the documentation is incomplete, it can be very difficult to *debug* DIP 1000 errors, and because the implementation has several known bugs, you cannot simply rely on the compiler to tell you when you've gotten things right.
Jan 11 2022