How can I define an exception like the following?
exception CustomExn<'TMessage> of 'TMessage list
A method is not allowed to catch an instance of a type parameter. public static <T extends Exception, J> void execute(List<J> jobs) { try { for (J job : jobs) {} // compile-time error //Cannot use the type parameter T in a catch block } catch (T e) { // ... } }
Since type parameters of generics are erased at runtime, there is no way to distinguish between generic exceptions with different type parameters in the catch clause, thus generic exceptions are not supported.
It refers to exception class that is near the top of the exception class hierarchy. Note that an exception class cannot be a generic class ... in the Java sense of generic types. The JLS says: "Note that a subclass of Throwable cannot be generic (§8.1.2)." -
In that context, the word "generic" is being used in the normal English sense: i.e. "not specific". It refers to exception class that is near the top of the exception class hierarchy. Note that an exception class cannot be a generic class ... in the Java sense of generic types. The JLS says:
This topic describes how to define and use F# exception types. In the previous syntax, exception-type is the name of a new F# exception type, and argument-type represents the type of an argument that can be supplied when you raise an exception of this type. You can specify multiple arguments by using a tuple type for argument-type.
While exception are not allowed to contain generic type parameters it is perfectly fine to throw generic types (if they extend Throwable ). The following code compiles fine: .. However, it is not possible to use generic type parameters in catch blocks.
F# - Generics. In F#, function values, methods, properties, and aggregate types such as classes, records, and discriminated unions can be generic. Generic constructs contain at least one type parameter. Generic functions and types enable you to write code that works with a variety of types without repeating the code for each type.
Maybe you can just inherit from System.Exception?
type CustomExn<'TMessage> (message:'TMessage list) =
inherit System.Exception ()
let test =
try
raise (CustomExn["string"] )
with
| :? CustomExn<string> -> "CustomExn of string"
| :? CustomExn<int> -> "CustomExn of int"
| _ -> "Everything else"
Not sure it is possible with F# Exception Definitions
according to specs (page 164-165)
This one also NOT A GOOD SOLUTION because try with
will only catch ExceptionList<string>
in this case so there is no good way to make it generic
type ExceptionList<'a>(msgList: 'a list) =
inherit Exception()
member __.MessageList = msgList
let mock() =
raise <| ExceptionList(["failed"])
try
mock() //raises ExceptionList<string>
with
//this catch block won't fire, because it is not generic, it is ExceptionList<obj>
| :? ExceptionList<_> as exnList ->
exnList.MessageList
|> List.iter (printfn "%A")
The better way though: Result<'a,'b list>
:
let mock'() =
if DateTime.Now.Ticks % 2L = 0L
then Ok()
else Error(["failed"])
let result = mock'()
match result with
| Ok _ -> printfn "Ok!"
| Error (msgList) ->
msgList
|> List.iter (printfn "%A")
Added There is a workaround with type loss:
type ExceptionList(msgList: obj list) =
inherit Exception()
member __.MessageList = msgList
// Here is F# exception definition
exception CustomException of ExceptionList
let failwithMany msgs =
raise <| CustomException (ExceptionList(msgs))
let mock() =
//zero type checking here
failwithMany[1;2;"a";[];"failed"]
try
mock()
with
// exnList is list of objects
| CustomException exnList ->
exnList.MessageList
|> List.iter (printfn "%A")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With