Interesting. Validation is the case I am thinking of - but it might also apply to any situation where you offer a different path of control - i.e. not stepping back up the stack. That's why I mentioned CPS. That's also (maybe) why true tail calls would be useful.
The mention of binding dynamic vars is interesting and I will look at this. It still leaves the question of how/when to pass control to actually manage or respond to the validation error. I have generally kept away from dynamic vars to date because I don't have a good feel for when and where they are and are not a good choice. This would be a great area for a blog post - or clojure docs doco - if anyone who has used them extensively can offer a good view of pros and cons, whens and when nots :) Marko, do you have a good example of doing what you say? The reasons given for not using Exceptions are still not really convincing to me (yet). Although I do accept that some things may become more difficult to manage if you don't take care in what you do. This is generally true. I just see Exceptions as a way of managing control with pros and cons, not an anti pattern. Maybe a more general question is what alternative control flows are available - which are possible but not available - and which are good for which situations. Apologies to the original questioner for changing the focus of the recent posts. Dave On Wednesday, 20 March 2013 19:36:46 UTC+11, Marko Topolnik wrote: > > Exceptions are a perfect tool for flow control, if used judiciously. The > typical criticism revolves around their incompetent usage, and a more > general criticism can be made against a mechanism that is subverted all too > easily. > > If you responsibly keep to the "good parts", exceptions could be the way > to go. Validation is one example where I love them because it happens all > around, but validation failures are all handled uniformly. > > However, I would also urge you to explore other approaches, such as having > a dynamically-bound variable that collects all the validation failures, > which will potentially give you better diagnostics than the fail-fast > behavior of validation excptions. > > -marko > > On Wednesday, March 20, 2013 2:24:12 AM UTC+1, Dave Sann wrote: >> >> I am interested in this view that exceptions are an anti pattern. I have >> heard it voiced before. >> >> I am not sure that I understand why. >> >> As I see it you have a choices: >> >> 1. Handle in the result - and test this result repeatedly all the way >> back to the caller >> 2. Handle "out of band" - Throw an exception, allow the stack to unwind >> and catch where it matters >> >> [And maybe - but I am not very knowledgeable on this and it won't work >> today on the JVM anyway >> 3. Use continuation passing style with TCO to shortcut the return to >> follow an exception path] >> >> So, ignoring 3. >> >> Why is 2 preferable over 1? There are certainly pros and cons. >> >> Dave >> >> >> On Wednesday, 20 March 2013 09:42:11 UTC+11, James Reeves wrote: >>> >>> I'd argue that using exceptions for control flow is something of an >>> anti-pattern, even in Java. >>> >>> In this case a better mechanism might be to use polymorphism. For >>> instance: >>> >>> (defprotocol Validatable >>> (validation-errors [x] "Return the validation errors for x.")) >>> >>> (defn valid? [x] >>> (empty? (validation-errors x))) >>> >>> Then you can define a general function to validate and store that item >>> in a database: >>> >>> (defn store-valid [db x] >>> (if (valid? x) >>> (store db x) >>> (validation-error-response x))) >>> >>> - James >>> >>> >>> On 19 March 2013 16:43, Julien Dreux <[email protected]> wrote: >>> >>>> Hi all, >>>> >>>> Coming from a Java background, I am having a hard time understanding >>>> how validation error propagation should work in clojure web APIs. >>>> >>>> To be clear, this is similar to how my Java web service would be setup: >>>> >>>> /** Method that validates the model, accesses the DB. If something went >>>> wrong, throw an exception */ >>>> public void validateAndCreateUser(User u) throws ValidationException, >>>> EmailAlreadyInUseException, ... { >>>> ... >>>> if(...) { >>>> throw new ValidationException(fieldName); >>>> } else if (...) { >>>> throw new EmailAlreadyInUseException(u.getEmail()); >>>> } >>>> } >>>> >>>> /** Endpoint method, catches & formats the exceptions thrown by the db >>>> method. **/ >>>> @POST("/api/user/create") >>>> public Response createUser (User u) { >>>> .. >>>> try{ >>>> validateAndCreateUser(u); >>>> return Response.ok(); >>>> } catch (Exception e) { >>>> return generateExceptionResponse(e); //Method that maps exceptions >>>> to responses. >>>> } >>>> } >>>> >>>> For all of Java's clunkiness, this had the benefit of not having to >>>> write tons of if/else statements for validation handling. Exception were >>>> just thrown from anywhere, bubbling back up to inital call, and if not >>>> handled in the endpoint method, a specialized class mapped them into a >>>> proper response. The exceptions contained all the information needed to >>>> generate 'rich' error messages back to the client. >>>> >>>> Being a Clojure newbie, I wonder what a good pattern is for a similar >>>> situation. So far, I have a method that validates models based on a >>>> schema, >>>> that returns >>>> >>>> {:success true} >>>> >>>> or >>>> >>>> {:success false :errors ["error 1" "error 2" ...]} >>>> >>>> But I don't know how to avoid having to write if/else conditions of the >>>> sort in each function between my endpoint and db functions. >>>> >>>> (if (validation :success) >>>> (follow-normal-path) >>>> (handle-validation-errors validation)) >>>> >>>> >>>> Any guidance appreciated. >>>> >>>> Cheers, >>>> >>>> Julien >>>> >>>> -- >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To post to this group, send email to [email protected] >>>> Note that posts from new members are moderated - please be patient with >>>> your first post. >>>> To unsubscribe from this group, send email to >>>> [email protected] >>>> For more options, visit this group at >>>> http://groups.google.com/group/clojure?hl=en >>>> --- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to [email protected]. >>>> For more options, visit https://groups.google.com/groups/opt_out. >>>> >>>> >>>> >>> >>> -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
