throw exception in async - exception

I have the following code:
member public this.GetData(uri: string) = async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
return res
}
When the property res.IsSuccessStatusCode is false I would like to throw an exception, how can I achieve this. The following code won't compile:
member public this.GetData(uri: string) = async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
match res.IsSuccessStatusCode with
| true -> return res
| false -> raise new Exception("")
}

You certainly need to wrap new Exception(...) in brackets, but that is not sufficient in this case - both branches of the match statement need to return a value, so you also need to insert return:
async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
match res.IsSuccessStatusCode with
| true -> return res
| false -> return raise (new Exception(""))
}
This is actually easier to write using an if computation which can contain body that returns unit (and throws an exception if the operation did not succeed) - and so you do not need return in that case:
async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
if not res.IsSuccessStatusCode then
raise (new Exception(""))
return res
}

So the first part is that you need to wrap the new Exception() with brackets to make sure that F# interprets the code correctly.
raise (new Exception(""))
or you can use either of the pipe operators
raise <| new Exception("")
new Exception |> raise
or you can change the type and use failwith
failwith "some message"
Secondly, you need to return from both branches, so prefix raise with return

Related

Create parent entity and children and redirect request in fluent vapor

I´m trying to create an entity Task and one children using the same request object
func create(_ req: Request) throws -> Future<Response> {
return try req.content.decode(Task.TaskForm.self).flatMap { taskForm in
let user = try req.requireAuthenticated(User.self)
let task = Task(name: taskForm.name, userId: user.id!)
return task.save(on: req).map { t in
let interval = try Interval(taskId: t.requireID())
let t = interval.save(on: req)
return t.save(on: req).map { _ in
return req.redirect(to: "/dashboard")
}
}
}
}
The error that I'm getting is this one:
Cannot convert return expression of type 'EventLoopFuture' to return type 'Response'.
Any ideas on what's the problem?
This code should work
func create(_ req: Request) throws -> Future<Response> {
return try req.content.decode(Task.TaskForm.self).flatMap { taskForm in
let user = try req.requireAuthenticated(User.self)
let task = Task(name: taskForm.name, userId: user.id!)
return task.create(on: req).flatMap { t in
let interval = try Interval(taskId: t.requireID())
return interval.create(on: req).flatMap { _ in
return t.create(on: req).transform(to: req.redirect(to: "/dashboard"))
// or your previous variant
// return t.create(on: req).map { _ in
// return req.redirect(to: "/dashboard")
// }
}
}
}
}
There are a few things you could learn
use map when you have to return non-future result
use flatMap you have to return Future<> result
use create instead of save when you are creating object in the db
don't leave future calls without handling them like you do on line #7

Can I pass type information to simplify this somehow?

I have a lot of code like this, it is all the same except for the type PositionJson, it could be AnotherJson or FooJson or BarJson
Is there some way I can exctract all this code into one function that I can somehow pass into it the type? So that I don't have several of these big blocks of almost identical code littering my class?
I'm not sure if this is possible or not, just thought I'd ask because it would be nice to do...
/**
* #return the _open_ [PositionJson]s
*/
val positions: Array<PositionJson>?
#Throws(AccountsAPIException::class)
get() {
val service = constructServiceURL(POSITIONS, null, true)
try {
val messageJson = mapper.readValue<MessageJson<Array<PositionJson>>>(
callURL(service),
object: TypeReference<MessageJson<Array<PositionJson>>>() {
})
val error = messageJson.error
if (error != null) throw AccountsAPIException(error.errorCode, error.description)
return messageJson.data
} catch (e: Exception) {
throw AccountsAPIException(e)
}
}
You can do what you want with generics. However, to use generics we first need to extract that giant block of code into a method:
val positions: Array<PositionJson>? get() = getPositions()
fun getPositions(): Array<PositionJson>? {
...
}
We haven't solved the problem, but now we're in a position to be able to solve it by making getPositions generic (note that I also rename the function):
val positions: Array<PositionJson> get() = getArrayOf<PositionJson>()
// thanks to type inference I can omit the type on getArrayOf if desired:
val positions: Array<PositionJson> get() = getArrayOf()
fun <T> getArrayOf(): Array<T>? {
val service = constructServiceURL(POSITIONS, null, true)
try {
val messageJson = mapper.readValue<MessageJson<Array<T>>>(
callURL(service),
object: TypeReference<MessageJson<Array<T>>>() {
})
val error = messageJson.error
if (error != null) throw AccountsAPIException(error.errorCode, error.description)
return messageJson.data
} catch (e: Exception) {
throw AccountsAPIException(e)
}
}
Perfect! Except this won't compile thanks to type erasure. But we can fix this too by making the function inline and making the type parameter reified:
inline fun <reified T: Any> getArrayOf(): Array<T>? {
...
}
And that should do it. Now you can reuse this function as needed:
val positions: Array<PositionJson>? get() = getArrayOf()
val persons: Array<PersonJson>? get() = getArrayOf()
val bananas: Array<BananaJson>? get() = getArrayOf()
inline fun <reified T: Any> getArrayOf(): Array<T>? {
val service = constructServiceURL(POSITIONS, null, true)
try {
val messageJson = mapper.readValue<MessageJson<Array<T>>>(
callURL(service),
object: TypeReference<MessageJson<Array<T>>>() {
})
val error = messageJson.error
if (error != null) throw AccountsAPIException(error.errorCode, error.description)
return messageJson.data
} catch (e: Exception) {
throw AccountsAPIException(e)
}
}
One last thing: note that in all my examples I used property getters (get() = ...) as in your original code. However, I strongly suspect that you do NOT want to use a getter. Getters will be called every time someone accesses your property, which in this case means that every time someone reads the positions property you'll be calling constructServiceURL and making the service call, etc. If you want that code to only happen once then you should just call getArrayOf() once and assign the result to your property:
val positions: Array<PositionJson>? = getArrayOf()
// this syntax would also work:
val positions = getArrayOf<PositionJson>()

In SML, how to assert that a particular exception is thrown?

Without taking the effort to actually clone JUnit or something, I'm throwing together a few utility functions to help test some SML code. I do know about QCheck, but it can't do this one thing either and isn't what I want generally. (But if you know of another automated-testing framework for SML, please speak up.)
I'd like to be able to assert that some function will throw an exception, e.g., given a function
fun broken x = raise Fail
I'd like to be able to write something like
throws ("ERROR: function is not broken enough!", fn () => broken 1, Fail)
and have it throw an error if the given function does not raise the expected exception.
I tried to write a throws function with type (string * exn * (unit -> unit)) -> unit like so:
fun throws (msg, e, func) = func ()
handle e' => if e = e'
then ()
else raise ERROR (SOME msg)
But this generates a bunch of compile-time errors, apparently because ML
does not define equality over exceptions:
sexp-tests.sml:54.31-57.49 Error: types of rules don't agree [equality type required]
earlier rule(s): ''Z -> unit
this rule: exn -> 'Y
in rule:
exn => raise exn
sexp-tests.sml:54.31-57.49 Error: handler domain is not exn [equality type required]
handler domain: ''Z
in expression:
func ()
handle
e' => if e = e' then () else raise (ERROR <exp>)
| exn => raise exn
As a workaround, I suspect I could just reuse an existing assert function I have:
assert ((broken 1; false) handle Fail => true | _ => false)
But it's a bit more thinking and typing.
So, is there any way to write that throws function in SML?
This following function should work:
exception ERROR of string option;
fun throwError msg = raise ERROR (SOME msg);
fun throws (msg, func, e) =
(func (); throwError msg) handle e' =>
if exnName e = exnName e'
then ()
else raise throwError msg
This uses the function exnName, which gets the name of the exception as a string, and uses that for comparison instead.
More importantly, it also handles the case where no exception is thrown at all, and gives an error on that, too.
Alternatively, if you simply need a boolean value, indicating whether the exception was thrown or not, you can use:
fun bthrows (func, e) = (func (); false) handle e' => exnName e = exnName e'
Note that, for the case of Fail, you'll actually have to create an instance of a Fail-exception, for instance like so:
throws ("ERROR: Oh no!", fn () => test 5, Fail "")
Alternatively, you could take the name of the exception, for a cleaner general case:
fun throws (msg, func, e) =
(func (); throwError msg) handle e' =>
if e = exnName e'
then ()
else raise throwError msg
fun bthrows (func, e) = (func (); false) handle e' => e = exnName e'
And then use it like this:
throws ("ERROR: Oh no!", fn () => test 5, "Fail")

Haskell: Dealing With Types And Exceptions

I'd like to know the "Haskell way" to catch and handle exceptions. As shown below, I understand the basic syntax, but I'm not sure how to deal with the type system in this situation.
The below code attempts to return the value of the requested environment variable. Obviously if that variable isn't there I want to catch the exception and return Nothing.
getEnvVar x = do {
var <- getEnv x;
Just var;
} `catch` \ex -> do {
Nothing
}
Here is the error:
Couldn't match expected type `IO a'
against inferred type `Maybe String'
In the expression: Just var
In the first argument of `catch', namely
`do { var <- getEnv x;
Just var }'
In the expression:
do { var <- getEnv x;
Just var }
`catch`
\ ex -> do { Nothing }
I could return string values:
getEnvVar x = do {
var <- getEnv x;
return var;
} `catch` \ex -> do {
""
}
however, this doesn't feel like the Haskell way. What is the Haskell way?
Edit: Updated code to properly reflect description.
You cannot strip away the IO and return Maybe String within a do-block. You need to return an IO (Maybe String).
getEnvVar x = do {
var <- getEnv x;
return (Just var);
} `catch` \ex -> do {
return Nothing
}
Why not use
import qualified System.IO.Error as E
getEnvVar :: String -> IO (Either IOError String)
getEnvVar = E.try . getEnv
Instead of Nothing and Just var, you get Left error and Right var.
Once you get that anything involving getEnv is going to involve returning a result in the IO monad, then there is nothing wrong with your basic approach. And while you could use System.IO.Error (and I would), it is just as valid, and instructive, to write it the way you did. However, you did use a bit more punctuation than idomatic Haskell would use:
getEnvVar x = (Just `fmap` getEnv x) `catch` const (return Nothing)
or
getEnvVar x = getEnv x `catch` const (return "")
You could also try
import System.Environment
getEnvVar :: String -> IO (Maybe String)
getEnvVar x = getEnvironment >>= return . lookup x
or a bit longer, but maybe easier to follow:
getEnvVar x = do
fullEnvironment <- getEnvironment
return (lookup x fullEnvironment)
if you don't mind going through the whole environment the whole time.

F#: Custom exceptions. Is there a better way to overload the exception type?

I have a simple custom exception defined like like the following but I don't like having to use the Throw function and I really don't like having both Throw and a Throw2 functions. Is there a more elegant way of doing this? Is there a way of throwing MyError or Error directly without the intermediate function?
#light
module Utilities.MyException
type MyError(code : int, msg : string) =
member e.Msg = msg
member e.Code = code
new (msg : string) = MyError(0, msg)
exception Error of MyError
let public Throw (msg : string) =
let err = new MyError(msg)
raise (Error err)
let public Throw2 (code : int) (msg : string) =
let err = new MyError(code, msg)
raise (Error err)
I'm using it like the following but I'd like to use one of the variants that didn't work
Throw(System.String.Format("Could not parse boolean value '{0}'", key))
//The string isn't of the correct type for Error
//raise(Error(System.String.Format("Could not parse boolean value '{0}'", key)))
//MyError isn't compatible with System.Exception
//raise(MyError(System.String.Format("Could not parse boolean value '{0}'", key)))
Just ignore exception construct and define the exception class - that is, one deriving from System.Exception - directly, as in C#:
type MyError(code : int, msg : string) =
inherit Exception(msg)
member e.Code = code
new (msg : string) = MyError(0, msg)
raise(MyError("Foo"))
raise(MyError("Foo", 1))
Note that I removed Msg member, because Exception has an equivalent Message property already.
I am unclear exactly what you are after, but how does this work for you?
exception Error of int * string
let ErrorC(s) = Error(0,s)
let F() =
try
let key = true
raise <| Error(42, System.String.Format("Could not parse '{0}'", key))
raise <| ErrorC(System.String.Format("Could not parse '{0}'", key))
with Error(code, msg) ->
printfn "%d: %s" code msg
How about redefining MyError as a record and using the record syntax to record the error, e.g.:-
type MyError =
{ Msg: string;
Code: int }
exception Error of MyError
raise <| Error { Msg = ( sprintf "Could not parse boolean value '%b'" key );
Code = code }