Why is pattern matching not performed in this case?

I have this simple exception hierarchy:

type FirstLevelException(msg) = inherit System.Exception (msg) type SecondLevelException(msg, inner) = inherit System.Exception (msg, inner) type ThirdLevelException(msg, inner) = inherit System.Exception (msg, inner) 

and these three (dummy) functions:

 member this.FirstFunction a = raise (new FirstLevelException("one")) member this.SecondFunction a = try this.FirstFunction a with | :? FirstLevelException as ex -> raise (new SecondLevelException("two", ex)) member this.ThirdFunction a = try this.SecondFunction 25 with | :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex)) 

It is easy to see that when you call ThirdFunction:

  • firstFunction throws FirstLevelException
  • secondFunction catches it, wraps it in a SecondLevelException, and throws it
  • thirdFunction catches it, wraps it in a ThirdLevelException and throws it
  • the caller may catch a ThirdLevelException.

All is well. Now I am changing thirdFunction as follows:

 member this.ThirdFunction a = 25 |> try this.SecondFunction with | :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex)) 

things get weird: it looks like pattern matching in ThirdFunction is no longer working, and the SecondLevelException is thrown right up to the caller of ThirdFunction without being wrapped in a ThirdLevelException.

I am sure there is a logical explanation that my C # -deformed mind does not see. Can someone shed some light?

+2
source share
1 answer

The behavior that you described is true - when writing 25 |> expr , the code in expr calculated, and the result (function) is called with 25 as an argument.

In your case, the result of expr is a function, and the evaluation of the expression (returning the function) is protected by a try block. However, as soon as the function returns, it exits the try block, and the call is executed outside the exception handler.

To move the exception handling inside this returned function, you need to write something like this:

 25 |> (fun n -> try // You need to call the function (ie give it something as an argument) // inside the try-with block, otherwise it won't be executed here! this.SecondFunction n with | :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex))) 

No one will write this code in practice, but I hope it demonstrates the problem!

By the way: I suppose this is related to your previous SO question about pipeline exception handling. I have added an answer that may help you understand the problem. (The problem is that pipeline wrapping operations in try .. with will not prevent exceptions that occur inside pipeline functions).

+7
source

Source: https://habr.com/ru/post/902258/


All Articles