Jump to page: 1 2
Thread overview
nothrow and std.exception.ifThrown
Apr 29, 2021
novice2
Apr 29, 2021
Imperatorn
Apr 29, 2021
Meta
Apr 30, 2021
Meta
Apr 30, 2021
Meta
May 01, 2021
novice2
Apr 29, 2021
Ali Çehreli
Apr 29, 2021
novice2
Apr 30, 2021
Meta
April 29, 2021

Hello.
I need use std.format.format() in nothrow function.
format() can throw.
For this case i have special default string.
I don't want embrace format into try..catch block,
and i found elegant std.exception.ifThrown.
But DMD say "ifThrown not nothrow"

https://run.dlang.io/is/kXtt5q

nothrow string foo(int x, string def) {
    import std.format: format;
    import std.exception: ifThrown;

    return format("%d", x).ifThrown(def);
}

Error: function std.exception.ifThrown!(Exception, string, string).ifThrown is not nothrow

What i can use instead of ifThrown, or how it can be changed to nothrow?
Thanks.

April 29, 2021

On Thursday, 29 April 2021 at 16:02:20 UTC, novice2 wrote:

>

Hello.
I need use std.format.format() in nothrow function.
format() can throw.
For this case i have special default string.
I don't want embrace format into try..catch block,
and i found elegant std.exception.ifThrown.
But DMD say "ifThrown not nothrow"

https://run.dlang.io/is/kXtt5q

nothrow string foo(int x, string def) {
    import std.format: format;
    import std.exception: ifThrown;

    return format("%d", x).ifThrown(def);
}

Error: function std.exception.ifThrown!(Exception, string, string).ifThrown is not nothrow

What i can use instead of ifThrown, or how it can be changed to nothrow?
Thanks.

Try adding scope(failure) assert(0); in foo

April 29, 2021

On Thursday, 29 April 2021 at 16:02:20 UTC, novice2 wrote:

>

Hello.
I need use std.format.format() in nothrow function.
format() can throw.
For this case i have special default string.
I don't want embrace format into try..catch block,
and i found elegant std.exception.ifThrown.
But DMD say "ifThrown not nothrow"

https://run.dlang.io/is/kXtt5q

nothrow string foo(int x, string def) {
    import std.format: format;
    import std.exception: ifThrown;

    return format("%d", x).ifThrown(def);
}

Error: function std.exception.ifThrown!(Exception, string, string).ifThrown is not nothrow

What i can use instead of ifThrown, or how it can be changed to nothrow?
Thanks.

The reason for this, apparently, is in the definition of ifThrown:

CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) nothrow

It's not marked as nothrow in the function's definition, so even if the delegate passed to ifThrown is nothrow, the compiler can't tell. There's no easy way around this that I can think of OTOH that doesn't involve some effort on your part. One thing you can do is wrap ifThrown with std.exception.assumeWontThrow:

import std.exception: ifThrown, assumeWontThrow;
import std.functional: pipe;

alias ifThrown = pipe!(std.exception.ifThrown, assumeWontThrow);

nothrow string foo(int x, string def) nothrow {
    import std.format: format;

    return format("%d", x).ifThrown(def);
}

April 29, 2021
On 4/29/21 9:02 AM, novice2 wrote:

> format() can throw.

In order to throw for an int, I added a foo(x) expression to prove that the code works.

> I don't want embrace format into try..catch block,
> and i found elegant std.exception.ifThrown.

There are collectException and collectExceptionMsg as well. The following code works for 42 and uses the default string "error" for 43.

int foo(int x) {
  import std.exception : enforce;
  enforce(x == 42, "some error");
  return x;
}

nothrow string foo(int x, string def) {
  import std.format: format;
  import std.exception: collectException;

  string result;
  auto exc = collectException(format("%d", foo(x)), result);
  return (exc is null) ? result : def;
}

void main() {
  import std.stdio: writeln;
  writeln(foo(42, "error"));
  writeln(foo(43, "error"));
}

Ali

April 29, 2021

Thank you Imperatron, Ali
both variants

  scope(failure) assert(0);
  collectException

works!

Thank Meta

>

The reason for this, apparently, is in the definition of ifThrown

i tried to modify ifThrown adding nothrow,
but compiler dont understand, that second parameter cant throw,
it just expression.

i dont understand why (templates too dificult for me yet),
but if i comment "lazy" from T2,
then compiler allow add "nothrow" to "ifThrown"

CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, /*lazy*/ scope T2 errorHandler) nothrow

https://run.dlang.io/is/KTdd3G

April 30, 2021
On 4/29/21 1:50 PM, Meta wrote:

> 
> The reason for this, apparently, is in the definition of `ifThrown`:
> ```
> CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) nothrow
> ```
> 
> It's not marked as `nothrow` in the function's definition, so even if the delegate passed to ifThrown _is_ nothrow, the compiler can't tell. There's no easy way around this that I can think of OTOH that doesn't involve some effort on your part.

Wait, I don't get what you are saying. You mean it should be marked nothrow? It's a template, so it *should* be inferred nothrow if it were actually nothrow.

The current definition is not marked nothrow as you alluded, and when I do mark it nothrow, it complains that the lazy parameter used for the exception handler is not nothrow.

It seems there's no way to infer the throwing of the lazy parameter, lazy parameters are never nothrow.

The higher order function DIP would I think help with this.

-Steve
April 30, 2021
On Friday, 30 April 2021 at 13:05:00 UTC, Steven Schveighoffer wrote:
> On 4/29/21 1:50 PM, Meta wrote:
>
>> 
>> The reason for this, apparently, is in the definition of `ifThrown`:
>> ```
>> CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) nothrow
>> ```
>> 
>> It's not marked as `nothrow` in the function's definition, so even if the delegate passed to ifThrown _is_ nothrow, the compiler can't tell. There's no easy way around this that I can think of OTOH that doesn't involve some effort on your part.
>
> Wait, I don't get what you are saying. You mean it should be marked nothrow? It's a template, so it *should* be inferred nothrow if it were actually nothrow.
>
> The current definition is not marked nothrow as you alluded, and when I do mark it nothrow, it complains that the lazy parameter used for the exception handler is not nothrow.
>
> It seems there's no way to infer the throwing of the lazy parameter, lazy parameters are never nothrow.
>
> The higher order function DIP would I think help with this.
>
> -Steve

Change it to a delegate and it's the same thing. ifThrown being a template is irrelevant in this case because it is accepting the handler as a function argument, not a template argument. You:

1. Need to make it a delegate instead of a lazy argument.

2. Need to mark the delegate as nothrow.

For the function to be inferred as nothrow.
April 30, 2021
On 4/30/21 9:24 AM, Meta wrote:
> On Friday, 30 April 2021 at 13:05:00 UTC, Steven Schveighoffer wrote:
>> On 4/29/21 1:50 PM, Meta wrote:
>>
>>>
>>> The reason for this, apparently, is in the definition of `ifThrown`:
>>> ```
>>> CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) nothrow
>>> ```
>>>
>>> It's not marked as `nothrow` in the function's definition, so even if the delegate passed to ifThrown _is_ nothrow, the compiler can't tell. There's no easy way around this that I can think of OTOH that doesn't involve some effort on your part.
>>
>> Wait, I don't get what you are saying. You mean it should be marked nothrow? It's a template, so it *should* be inferred nothrow if it were actually nothrow.
>>
>> The current definition is not marked nothrow as you alluded, and when I do mark it nothrow, it complains that the lazy parameter used for the exception handler is not nothrow.
>>
>> It seems there's no way to infer the throwing of the lazy parameter, lazy parameters are never nothrow.
>>
>> The higher order function DIP would I think help with this.
> 
> Change it to a delegate and it's the same thing. ifThrown being a template is irrelevant in this case because it is accepting the handler as a function argument, not a template argument. You:
> 
> 1. Need to make it a delegate instead of a lazy argument.
> 
> 2. Need to mark the delegate as nothrow.
> 
> For the function to be inferred as nothrow.

My point is that I think marking the *function* nothrow is not correct, it's the second parameter that dictates the throwing of the result.

And you can probably fix the second parameter to be a templated delegate:

```d
CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, scope T2 errorHandler) if (is(typeof(errorHandler(E.init))))
```

And of course, we get into chicken-and-egg problems with this because if you pass in a lambda, there's no types for it to figure this stuff out. Another option is to overload on the delegate, but meh. I'd really like to see a language change that says "infer the attributes of this function based on the fact that it calls the delegate passed in."

-Steve
April 30, 2021

On Thursday, 29 April 2021 at 20:00:23 UTC, novice2 wrote:

>

i dont understand why (templates too dificult for me yet),
but if i comment "lazy" from T2,
then compiler allow add "nothrow" to "ifThrown"

CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, /*lazy*/ scope T2 errorHandler) nothrow

https://run.dlang.io/is/KTdd3G

This is because marking a function parameter as lazy is just syntax sugar for the following:

CommonType!(T1, T2) ifThrown(E: Throwable = Exception, T1, T2)(scope T1 delegate() expression, scope T2 delegate() errorHandler);

string def = "some string";
auto s = format("%d", x).ifThrown({ return def; });

Behind the scenes, a lazy parameter is not really a value - it's a function that returns a value. The problem is that this function is not nothrow, and can't be marked as such (this is arguably a gap in the language). Removing lazy changes errorHandler to be a plain old value again - which cannot throw an exception, of course - so ifThrown can be marked nothrow. However, you lose all the benefits of errorHandler being lazily computed.

April 30, 2021
On Friday, 30 April 2021 at 13:42:49 UTC, Steven Schveighoffer wrote:
> On 4/30/21 9:24 AM, Meta wrote:
>
> My point is that I think marking the *function* nothrow is not correct, it's the second parameter that dictates the throwing of the result.
>
> And you can probably fix the second parameter to be a templated delegate:
>
> ```d
> CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, scope T2 errorHandler) if (is(typeof(errorHandler(E.init))))
> ```
>
> And of course, we get into chicken-and-egg problems with this because if you pass in a lambda, there's no types for it to figure this stuff out. Another option is to overload on the delegate, but meh. I'd really like to see a language change that says "infer the attributes of this function based on the fact that it calls the delegate passed in."
>
> -Steve

Now that you mention it, I don't see why lazy parameters can't have their attributes inferred. What happened to the DIP to replace lazy parameters with automatic conversion of passed values to delegates, anyway? I.e.:
```
CommonType!(T1, T2) ifThrown(E: Throwable = Exception, T1, T2)(scope T1 delegate() expression, scope T2 delegate() errorHandler);

//getString() and "some string" automatically converted to `string delegate()`
auto s = getString().ifThrown("some string");
```
« First   ‹ Prev
1 2