www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - make a nothrow call a throwing function

reply "monarch_dodra" <monarchdodra gmail.com> writes:
Is there any way that a nothrow function can call a function that 
throws, but without even trying to catch if an exception is 
thrown?

My use case is a pretty low level nothrow function, that needs to 
call something that never ever throws, but was not marked as such.

I want to avoid the "try/catch/[do nothing|assert]" because I 
don't want to pay for that. Ideally, i'd really just want to mark 
my function as nothrow, and have undefined behavior if it *does* 
throw.

Any way to do that?
Feb 07 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, February 07, 2013 11:06:14 monarch_dodra wrote:
 Is there any way that a nothrow function can call a function that
 throws, but without even trying to catch if an exception is
 thrown?
 
 My use case is a pretty low level nothrow function, that needs to
 call something that never ever throws, but was not marked as such.
 
 I want to avoid the "try/catch/[do nothing|assert]" because I
 don't want to pay for that. Ideally, i'd really just want to mark
 my function as nothrow, and have undefined behavior if it *does*
 throw.
 
 Any way to do that?
You can cast the function. - Jonathan M Davis
Feb 07 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 7 February 2013 at 10:55:26 UTC, Jonathan M Davis 
wrote:
 On Thursday, February 07, 2013 11:06:14 monarch_dodra wrote:
 Is there any way that a nothrow function can call a function 
 that
 throws, but without even trying to catch if an exception is
 thrown?
 
 My use case is a pretty low level nothrow function, that needs 
 to
 call something that never ever throws, but was not marked as 
 such.
 
 I want to avoid the "try/catch/[do nothing|assert]" because I
 don't want to pay for that. Ideally, i'd really just want to 
 mark
 my function as nothrow, and have undefined behavior if it 
 *does*
 throw.
 
 Any way to do that?
You can cast the function. - Jonathan M Davis
Smart. Unfortunatly, in this case, I'm trying to call "string.dup". It would appear though that (apparently), dup is a property that returns a function pointer, or something. In any case, I can't seem to be able to get its address. Now I feel kind of bad for suggesting banning taking the address of a property function ... I can bypass this with a wrapper function I guess, but at this point, I'd have to bench to see if that is even worth it...
Feb 07 2013
next sibling parent 1100110 <0b1100110 gmail.com> writes:
On 02/07/2013 05:38 AM, monarch_dodra wrote:
 On Thursday, 7 February 2013 at 10:55:26 UTC, Jonathan M Davis wrote:
 On Thursday, February 07, 2013 11:06:14 monarch_dodra wrote:
 Is there any way that a nothrow function can call a function that
 throws, but without even trying to catch if an exception is
 thrown?

 My use case is a pretty low level nothrow function, that needs to
 call something that never ever throws, but was not marked as such.

 I want to avoid the "try/catch/[do nothing|assert]" because I
 don't want to pay for that. Ideally, i'd really just want to mark
 my function as nothrow, and have undefined behavior if it *does*
 throw.

 Any way to do that?
You can cast the function. - Jonathan M Davis
Smart. Unfortunatly, in this case, I'm trying to call "string.dup". It would appear though that (apparently), dup is a property that returns a function pointer, or something. In any case, I can't seem to be able to get its address. Now I feel kind of bad for suggesting banning taking the address of a property function ... I can bypass this with a wrapper function I guess, but at this point, I'd have to bench to see if that is even worth it...
scope(failure) has worked for me in the past, but mostly calling C functions from nothrow. You do have to put it at the top of the function, but it's simple and nice.
Feb 07 2013
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 7 February 2013 at 11:38:29 UTC, monarch_dodra wrote:
 On Thursday, 7 February 2013 at 10:55:26 UTC, Jonathan M Davis 
 wrote:
 On Thursday, February 07, 2013 11:06:14 monarch_dodra wrote:
 Any way to do that?
You can cast the function. - Jonathan M Davis
Smart. Unfortunatly, in this case, I'm trying to call "string.dup". It would appear though that (apparently), dup is a property that returns a function pointer, or something. In any case, I can't seem to be able to get its address. Now I feel kind of bad for suggesting banning taking the address of a property function ... I can bypass this with a wrapper function I guess, but at this point, I'd have to bench to see if that is even worth it...
So, you want to call function (which throws) from function marked as nothrow? It seems to be breaking idea of what nothrow does. You can do this in general by casting (which is preferred way) and by exploiting current holes/misspecified tricks/corner language cases which should be in general avoided. Unfortunately, it appears that you cannot cast in your particular case of array duplication. However there are other ways to break nothrow and you can use them (declaration mismatch, unions, delegates). I think the problem is not absence of ways of doing what you want, but in limitation of casting with respect to some properties of built-in types. By the way, I would not say that dup array property cannot throw exceptions.
Feb 07 2013
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 7 February 2013 at 20:46:22 UTC, Maxim Fomin wrote:
 On Thursday, 7 February 2013 at 11:38:29 UTC, monarch_dodra 
 wrote:
 On Thursday, 7 February 2013 at 10:55:26 UTC, Jonathan M Davis 
 wrote:
 On Thursday, February 07, 2013 11:06:14 monarch_dodra wrote:
 Any way to do that?
You can cast the function. - Jonathan M Davis
Smart. Unfortunatly, in this case, I'm trying to call "string.dup". It would appear though that (apparently), dup is a property that returns a function pointer, or something. In any case, I can't seem to be able to get its address. Now I feel kind of bad for suggesting banning taking the address of a property function ... I can bypass this with a wrapper function I guess, but at this point, I'd have to bench to see if that is even worth it...
So, you want to call function (which throws) from function marked as nothrow? It seems to be breaking idea of what nothrow does. You can do this in general by casting (which is preferred way) and by exploiting current holes/misspecified tricks/corner language cases which should be in general avoided. Unfortunately, it appears that you cannot cast in your particular case of array duplication. However there are other ways to break nothrow and you can use them (declaration mismatch, unions, delegates). I think the problem is not absence of ways of doing what you want, but in limitation of casting with respect to some properties of built-in types. By the way, I would not say that dup array property cannot throw exceptions.
In this particular case, in is an string dup, so it *should* be nothrow. Still the final solution has is more problematic than anything, so I'll just try/catch.
Feb 07 2013
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, February 07, 2013 21:46:21 Maxim Fomin wrote:
 So, you want to call function (which throws) from function marked
 as nothrow? It seems to be breaking idea of what nothrow does.
I believe that the problem is that the function isn't marked nothrow even though it doesn't throw. He essentially wants to be able to make the compiler treat it as nothrow at the call site (since he can't change the function definition) without any overhead, and I don't think that that's actually possible. The normal way to handle cases where you know that a function won't throw but isn't nothrow is to wrap it in a try block and put an assert(0) statement in the catch block. That does incur some amound of overhead, but I don't know how much. Apparently, monarch_dodra thinks that it's too much for what he's doing though. - Jonathan M Davis
Feb 07 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 7 February 2013 at 21:32:28 UTC, Jonathan M Davis 
wrote:
 On Thursday, February 07, 2013 21:46:21 Maxim Fomin wrote:
 So, you want to call function (which throws) from function 
 marked
 as nothrow? It seems to be breaking idea of what nothrow does.
I believe that the problem is that the function isn't marked nothrow even though it doesn't throw. He essentially wants to be able to make the compiler treat it as nothrow at the call site (since he can't change the function definition) without any overhead, and I don't think that that's actually possible.
I was though able to get a function pointer, and cast said pointer, at compile time (place it an enum). At that point, calling the function via the compile-time known pointer *should* be just as efficient as calling the function directly. I'll need to check the assembly. EG: //---- import std.stdio; void bar() {writeln("bar");} void foo() nothrow { enum barnothrow = cast(void function() nothrow)(&bar); barnothrow(); } void main() {foo();} //---- Yes, writeln actually can throw, so it's a bad example, but a proof. I'd be surprised if there was any run-time overhead (but I could be wrong). In my case though, there is an extra overhead that I can't get a function pointer to dup, so I have to create an intermediary function. Depending on the inlined-ness of things, *that* may or may not incur an overhead.
 The normal way to handle cases where you know that a function 
 won't throw but
 isn't nothrow is to wrap it in a try block and put an assert(0) 
 statement in
 the catch block. That does incur some amound of overhead, but I 
 don't know how
 much. Apparently, monarch_dodra thinks that it's too much for 
 what he's doing
 though.

 - Jonathan M Davis
Well, I don't think it's too much, but wanted to know the alternatives. I like to know my options, and their costs. It costs nothing to ask, and you never know what you'll learn. I think the conclusion I came to though is to bite the bullet, and not worry too about it. Thank you for your answers anyways.
Feb 07 2013
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, February 07, 2013 23:14:51 monarch_dodra wrote:
 I was though able to get a function pointer, and cast said
 pointer, at compile time (place it an enum). At that point,
 calling the function via the compile-time known pointer *should*
 be just as efficient as calling the function directly. I'll need
 to check the assembly.
Hmmm. I wouldn't have thought that you could get the function pointer at compiler time. Regardless, you lose any possibility of inlining the function call, which is the main problem AFAIK, though I don't know if they would have been an option in the case of dup anyway.
 I think the conclusion I came to though is to bite the bullet,
 and not worry too about it.
Well, long term, this should be solved by dup actually being nothrow when it can't throw. - Jonathan M Davis
Feb 07 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/08/13 01:33, Jonathan M Davis wrote:
 Hmmm. I wouldn't have thought that you could get the function pointer at 
 compiler time. Regardless, you lose any possibility of inlining the function 
 call, which is the main problem AFAIK, though I don't know if they would have 
 been an option in the case of dup anyway.
It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc) artur
Feb 08 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
 On 02/08/13 01:33, Jonathan M Davis wrote:
 Hmmm. I wouldn't have thought that you could get the function pointer at
 compiler time. Regardless, you lose any possibility of inlining the
 function call, which is the main problem AFAIK, though I don't know if
 they would have been an option in the case of dup anyway.
It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc)
How could it not affect inlining? You're using a pointer to a function instead of the function itself, so it can't be inlined. Do you mean that dup in particular doens't get inlined even when called directly? That's quite possible, but in the general case, using a function pointer rather than calling a function directly risks taking a small efficiency hit due to the fact that the function can no longer be inlined. - Jonathan M Davis
Feb 08 2013
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 8 February 2013 at 09:33:19 UTC, Jonathan M Davis 
wrote:
 On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
 On 02/08/13 01:33, Jonathan M Davis wrote:
 Hmmm. I wouldn't have thought that you could get the 
 function pointer at
 compiler time. Regardless, you lose any possibility of 
 inlining the
 function call, which is the main problem AFAIK, though I 
 don't know if
 they would have been an option in the case of dup anyway.
It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc)
How could it not affect inlining? You're using a pointer to a function instead of the function itself, so it can't be inlined. Do you mean that dup in particular doens't get inlined even when called directly? That's quite possible, but in the general case, using a function pointer rather than calling a function directly risks taking a small efficiency hit due to the fact that the function can no longer be inlined. - Jonathan M Davis
Well, aren't you saying that because usually, function pointers aren't obtained at compile time? In any case, I also tested it, and the disassemble seems to give the exact same code (inlined, as far as I can tell) for calling via function or function pointer: http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29\n{\n%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20fun%28%29%3B\n%20%20%2F%2Ffoo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]} http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29\n{\n%20%20%2F%2Fenum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20%2F%2Ffun%28%29%3B\n%20%20foo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]} And a third version, after adding the "nothrow" keyword. Slight changes, but I can't tell if they are "true" changes: http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29%20nothrow\n{\n%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20fun%28%29%3B\n%20%20%2F%2Ffoo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]} That said, when everything is said and done, the try catch version also generates the same inline code http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29%20nothrow\n{\n%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20fun%28%29%3B\n%20%20%2F%2Ffoo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]} But in this case, the compiler has access to the call, so it can *tell* exceptions won't get thrown. Finally, in this last version, which calls dup, we can see the "cast" version takes less intructions that the try/catch version. http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nchar[]%20s%3B\n\nvoid%20foo%28%29\n{\n%20%20s%20%3D%20\%22hello\%22.dup%3B\n}\n\nversion%28all%29\n{\n%20%20void%20bar%28%29%20nothrow\n%20%20{\n%20%20%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20%20%20fun%28%29%3B\n%20%20}\n}\nelse\n{\n%20%20void%20bar%28%29%20nothrow\n%20%20{\n%20%20%20%20try{\n%20%20%20%20%20%20foo%28%29%3B\n%20%20%20%20}catch{}\n%20%20}\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28s%20%3D%3D%20\%22hello\%22%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]} But at the end of the day, it is a dangerous semantic for not that much gain.
Feb 08 2013
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/08/2013 01:32 AM, Jonathan M Davis wrote:
 On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
 On 02/08/13 01:33, Jonathan M Davis wrote:
 Hmmm. I wouldn't have thought that you could get the function 
pointer at
 compiler time. Regardless, you lose any possibility of inlining the
 function call, which is the main problem AFAIK, though I don't know if
 they would have been an option in the case of dup anyway.
It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc)
How could it not affect inlining? You're using a pointer to a
function instead
 of the function itself, so it can't be inlined.
Taking the address of a function ensures that the function exists but it does not preclude inlining the code of that function. Ali
Feb 08 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/08/13 10:32, Jonathan M Davis wrote:
 On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
 On 02/08/13 01:33, Jonathan M Davis wrote:
 Hmmm. I wouldn't have thought that you could get the function pointer at
 compiler time. Regardless, you lose any possibility of inlining the
 function call, which is the main problem AFAIK, though I don't know if
 they would have been an option in the case of dup anyway.
It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc)
How could it not affect inlining? You're using a pointer to a function instead of the function itself, so it can't be inlined. Do you mean that dup in
"&f" is an expression that evaluates to a constant, known at compile time (modulo link-/run-time relocation/offset fixups, but that's irrelevant here). "(&f)()" is trivially recognizable (for the compiler) as equivalent to "f()". Not unlike the "int i; auto j = *&i, k = i;" case where you can expect the compiler to optimize away the address-of and dereferencing, and evaluate the first expression just like the second one.
 of the function itself, so it can't be inlined. Do you mean that dup in 
 particular doens't get inlined even when called directly? That's quite 
 possible, but in the general case, using a function pointer rather than 
 calling a function directly risks taking a small efficiency hit due to the
fact 
 that the function can no longer be inlined.
It makes no difference. I actually checked, because I was wondering if the reinterpret cast wasn't confusing the compiler - it doesn't and inlining happens as it should even with that cast in the mix. artur
Feb 08 2013