www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Temporary trusted scope

reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
What's the preferred way of creating a temporary  trusted scope 
without writing a separate  function?

Similar to Rust's

unsafe { /* unsafe stuff here */ }
Dec 18 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, December 18, 2018 3:14:50 AM MST Per Nordlw via Digitalmars-d-
learn wrote:
 What's the preferred way of creating a temporary  trusted scope
 without writing a separate  function?

 Similar to Rust's

 unsafe { /* unsafe stuff here */ }
Unfortunately, D does not currently have a way to do that. Only functions can be marked with trusted. However, the typical approach to this problem is to use a lambda, which is more or less syntactically the same except that it has some extra parens. e.g. () trusted { doUnsafe(); }(); or auto result = () trusted { getUnsafe:() }(); So, it's less than ideal, but it gets us close, and unless the code is long enough that maybe it should be in its own function, it's better than declaring a nested function, let alone declaring an entirely separate function at module scope. - Jonathan M Davis
Dec 18 2018
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 18 December 2018 at 10:42:51 UTC, Jonathan M Davis 
wrote:
 Unfortunately, D does not currently have a way to do that. Only 
 functions can be marked with  trusted. However, the typical 
 approach to this problem is to use a lambda, which is more or 
 less syntactically the same except that it has some extra 
 parens. e.g.

 ()  trusted { doUnsafe(); }();
Is there a performance hit when using this?
Dec 18 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 19/12/2018 1:34 AM, Per Nordlöw wrote:
 On Tuesday, 18 December 2018 at 10:42:51 UTC, Jonathan M Davis wrote:
 Unfortunately, D does not currently have a way to do that. Only 
 functions can be marked with  trusted. However, the typical approach 
 to this problem is to use a lambda, which is more or less 
 syntactically the same except that it has some extra parens. e.g.

 ()  trusted { doUnsafe(); }();
Is there a performance hit when using this?
Yes except for ldc with -O3. But it is a function not a delegate so it should be all nicely prefetched and ready to go. So I wouldn't worry about it too much.
Dec 18 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, December 18, 2018 5:42:12 AM MST rikki cattermole via 
Digitalmars-d-learn wrote:
 On 19/12/2018 1:34 AM, Per Nordlw wrote:
 On Tuesday, 18 December 2018 at 10:42:51 UTC, Jonathan M Davis wrote:
 Unfortunately, D does not currently have a way to do that. Only
 functions can be marked with  trusted. However, the typical approach
 to this problem is to use a lambda, which is more or less
 syntactically the same except that it has some extra parens. e.g.

 ()  trusted { doUnsafe(); }();
Is there a performance hit when using this?
Yes except for ldc with -O3. But it is a function not a delegate so it should be all nicely prefetched and ready to go. So I wouldn't worry about it too much.
Really? I would have thought that that would be a pretty obvious optimization (especially if inlining is enabled). I suppose that it doesn't entirely surprise me if dmd does a poor job of it, but I would have expected ldc to do better than that. I would think that such an improvement would be pretty low-hanging fruit for adding to dmd's optimizer though. If not, it sounds like further justification for adding a feature for this rather than having to use a lambda. Aside from that though, the lambda trick is simple enough that it wouldn't surprise me if Walter and Andrei's response to such a DIP would be to just use the lambda trick. - Jonathan M Davis
Dec 18 2018
next sibling parent Kagamin <spam here.lot> writes:
On Wednesday, 19 December 2018 at 06:11:48 UTC, Jonathan M Davis 
wrote:
 Really? I would have thought that that would be a pretty 
 obvious optimization (especially if inlining is enabled). I 
 suppose that it doesn't entirely surprise me if dmd does a poor 
 job of it, but I would have expected ldc to do better than 
 that. I would think that such an improvement would be pretty 
 low-hanging fruit for adding to dmd's optimizer though.
AFAIK, it was added.
Dec 19 2018
prev sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 19/12/2018 7:11 PM, Jonathan M Davis wrote:
 Really? I would have thought that that would be a pretty obvious
 optimization (especially if inlining is enabled).
Assembly doesn't lie.
Dec 19 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, December 19, 2018 1:19:42 AM MST rikki cattermole via 
Digitalmars-d-learn wrote:
 On 19/12/2018 7:11 PM, Jonathan M Davis wrote:
 Really? I would have thought that that would be a pretty obvious
 optimization (especially if inlining is enabled).
Assembly doesn't lie.
I'm not saying that you're wrong, just expressing surprise. I've never checked to see what code actually got generated. But I do think that it's something that the compiler should be smart enough to do even if it isn't currently that smart, and the fact that it isn't is most defintely not a good thing. - Jonathan M Davis
Dec 19 2018
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 20/12/2018 5:02 AM, Jonathan M Davis wrote:
 On Wednesday, December 19, 2018 1:19:42 AM MST rikki cattermole via
 Digitalmars-d-learn wrote:
 On 19/12/2018 7:11 PM, Jonathan M Davis wrote:
 Really? I would have thought that that would be a pretty obvious
 optimization (especially if inlining is enabled).
Assembly doesn't lie.
I'm not saying that you're wrong, just expressing surprise. I've never checked to see what code actually got generated. But I do think that it's something that the compiler should be smart enough to do even if it isn't currently that smart, and the fact that it isn't is most defintely not a good thing. - Jonathan M Davis
I agree, this would be a very simple AST rewrite. Would be well worth doing since its a common-ish pattern.
Dec 19 2018
prev sibling parent Kagamin <spam here.lot> writes:
On Tuesday, 18 December 2018 at 12:42:12 UTC, rikki cattermole 
wrote:
 Yes except for ldc with -O3.
ldc with -O2 generates the same code.
Dec 19 2018
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Tuesday, 18 December 2018 at 10:14:50 UTC, Per Nordlöw wrote:
 What's the preferred way of creating a temporary  trusted scope 
 without writing a separate  function?
Jonathan's idea might also be encapsulated in a function, just like assumeUnique in Phobos: import std.stdio; template unsafe(alias fn) { trusted auto unsafe(T...)(T args) { return fn(args); } } system void fun(int n) { writeln("foo!"); } safe unittest { unsafe!({ fun(2); }); unsafe!fun(2); } -- Simen
Dec 18 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/18/18 6:29 AM, Simen Kjærås wrote:
 On Tuesday, 18 December 2018 at 10:14:50 UTC, Per Nordlöw wrote:
 What's the preferred way of creating a temporary  trusted scope 
 without writing a separate  function?
Jonathan's idea might also be encapsulated in a function, just like assumeUnique in Phobos: import std.stdio; template unsafe(alias fn) {     trusted auto unsafe(T...)(T args) {         return fn(args);     } } system void fun(int n) {     writeln("foo!"); } safe unittest {     unsafe!({         fun(2);     });     unsafe!fun(2); }
Wow, I really like this. The only real problem is that one generally searches for trusted when looking for unsafe code, but unsafe is pretty obvious too. Also, args should be auto ref. Only thing better I can think of (for the second example) is to define a prototype with the correct information, only with trusted (and specify the mangle). But any decent compiler should get rid of any overhead there. -Steve
Dec 18 2018
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 18 December 2018 at 13:52:29 UTC, Steven 
Schveighoffer wrote:
 template unsafe(alias fn) {
       trusted auto unsafe(T...)(T args) {
          return fn(args);
      }
 }
Very nice! What about proposing this for inclusion into `std.typecons` or `std.meta`?
Dec 18 2018
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Dec 18, 2018 at 08:52:29AM -0500, Steven Schveighoffer via
Digitalmars-d-learn wrote:
 On 12/18/18 6:29 AM, Simen Kjrs wrote:
 On Tuesday, 18 December 2018 at 10:14:50 UTC, Per Nordlw wrote:
 What's the preferred way of creating a temporary  trusted scope
 without writing a separate function?
Jonathan's idea might also be encapsulated in a function, just like assumeUnique in Phobos: import std.stdio; template unsafe(alias fn) { trusted auto unsafe(T...)(T args) { return fn(args); } } system void fun(int n) { writeln("foo!"); } safe unittest { unsafe!({ fun(2); }); unsafe!fun(2); }
Wow, I really like this. The only real problem is that one generally searches for trusted when looking for unsafe code, but unsafe is pretty obvious too. Also, args should be auto ref. Only thing better I can think of (for the second example) is to define a prototype with the correct information, only with trusted (and specify the mangle). But any decent compiler should get rid of any overhead there.
[...] I'm not so sure I like this. trusted bits of code really should have a safe API that cannot be called in a way that breaks safe. Being able to essentially "cast away" safe for arbitrary bits of code seems to me to be a rather scary, underhanded way of undermining safe. OTOH, if your function is very large and only isolated bits are non- safe, then a construct like this one could help, by making the code less noisy, and ensuring that the other parts of the code still remain safe. (Though IMO in such cases the function may be better refactored to encapsulate away the trusted bits in functions with safe APIs, and keep the safe code all in one place.) T -- MASM = Mana Ada Sistem, Man!
Dec 18 2018
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/18/18 10:53 AM, H. S. Teoh wrote:
 On Tue, Dec 18, 2018 at 08:52:29AM -0500, Steven Schveighoffer via
Digitalmars-d-learn wrote:
 On 12/18/18 6:29 AM, Simen Kjærås wrote:
 On Tuesday, 18 December 2018 at 10:14:50 UTC, Per Nordlöw wrote:
 What's the preferred way of creating a temporary  trusted scope
 without writing a separate  function?
Jonathan's idea might also be encapsulated in a function, just like assumeUnique in Phobos: import std.stdio; template unsafe(alias fn) {     trusted auto unsafe(T...)(T args) {         return fn(args);     } } system void fun(int n) {     writeln("foo!"); } safe unittest {     unsafe!({         fun(2);     });     unsafe!fun(2); }
Wow, I really like this. The only real problem is that one generally searches for trusted when looking for unsafe code, but unsafe is pretty obvious too. Also, args should be auto ref. Only thing better I can think of (for the second example) is to define a prototype with the correct information, only with trusted (and specify the mangle). But any decent compiler should get rid of any overhead there.
[...] I'm not so sure I like this. trusted bits of code really should have a safe API that cannot be called in a way that breaks safe. Being able to essentially "cast away" safe for arbitrary bits of code seems to me to be a rather scary, underhanded way of undermining safe.
You may not be realizing what the point of this is. Essentially, you replace your inline trusted lambda with this call. It's just nicer syntax/usage without all the extra parentheses. Other than that, every usage of it would need as much scrutiny as a trusted lambda.
 OTOH, if your function is very large and only isolated bits are
 non- safe, then a construct like this one could help, by making the code
 less noisy, and ensuring that the other parts of the code still remain
  safe. (Though IMO in such cases the function may be better refactored
 to encapsulate away the  trusted bits in functions with safe APIs, and
 keep the  safe code all in one place.)
Yes, exactly. The point of trusted lambdas are so that only the parts you want to trust are actually trusted, the rest of the function is safe. It doesn't prevent you from having to locally verify that implementation leaks don't happen (for example, () trusted {free(ptr);}() can still leak dangling pointers out into the safe portion), but it allows you to focus where your code is trusted. For more details, see this: https://dlang.org/blog/2016/09/28/how-to-write-trusted-code-in-d/ -Steve
Dec 18 2018
prev sibling next sibling parent aliak <something something.com> writes:
On Tuesday, 18 December 2018 at 13:52:29 UTC, Steven 
Schveighoffer wrote:
 On 12/18/18 6:29 AM, Simen Kjærås wrote:
 On Tuesday, 18 December 2018 at 10:14:50 UTC, Per Nordlöw 
 wrote:
 What's the preferred way of creating a temporary  trusted 
 scope without writing a separate  function?
Jonathan's idea might also be encapsulated in a function, just like assumeUnique in Phobos: import std.stdio; template unsafe(alias fn) {     trusted auto unsafe(T...)(T args) {         return fn(args);     } } system void fun(int n) {     writeln("foo!"); } safe unittest {     unsafe!({         fun(2);     });     unsafe!fun(2); }
Wow, I really like this. The only real problem is that one generally searches for trusted when looking for unsafe code, but unsafe is pretty obvious too. Also, args should be auto ref. Only thing better I can think of (for the second example) is to define a prototype with the correct information, only with trusted (and specify the mangle). But any decent compiler should get rid of any overhead there. -Steve
I've been gathering assume related stuff like this in a lib under an "assume" template. You can generalize further with multiple attributes inside a non-eponymous thing and use them like: assume!fun.safe_(2); assume!fun.nogc_(2); I guess it's no very idiomatic D though, but I feel it reads better ... ok well maybe 🤷‍♂️: https://aliak00.github.io/bolts/bolts/assume/assume.html Easier to be more specific with searches for "assumeSafe" instead of just "assume!" though. Cheers, - Ali
Dec 18 2018
prev sibling parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Tuesday, 18 December 2018 at 13:52:29 UTC, Steven 
Schveighoffer wrote:
 On 12/18/18 6:29 AM, Simen Kjærås wrote:
  safe unittest {
      unsafe!({
          fun(2);
      });
 
      unsafe!fun(2);
 }
Wow, I really like this. The only real problem is that one generally searches for trusted when looking for unsafe code, but unsafe is pretty obvious too. Also, args should be auto ref.
While trusted wouldn't work, it could be named 'trusted' instead of 'unsafe'. That's not gonna help those who search for ' trusted', but it's closer, at least. -- Simen
Dec 19 2018