special formsince v0.0-927 clojure.core/finallyEdit
(finally expr*)


finally should be the last form inside of a try expression. It is optional.

finally clauses are always evaluated for their side effects whether there was an error or not, but they are never the return value of a try expression.

See Also:

Source docstring:
catch-clause => (catch classname name expr*)
finally-clause => (finally expr*)
Catches and handles JavaScript exceptions.
Parser code @ clojurescript:src/main/clojure/cljs/analyzer.cljc
(defmethod parse 'try
  [op env [_ & body :as form] name _]
  (let [catchenv (update-in env [:context] #(if (= :expr %) :return %))
        catch? (every-pred seq? #(= (first %) 'catch))
        default? (every-pred catch? #(= (second %) :default))
        finally? (every-pred seq? #(= (first %) 'finally))

        {:keys [body cblocks dblock fblock]}
        (loop [parser {:state :start :forms body
                       :body [] :cblocks [] :dblock nil :fblock nil}]
          (if (seq? (:forms parser))
            (let [[form & forms*] (:forms parser)
                  parser* (assoc parser :forms forms*)]
              (case (:state parser)
                :start (cond
                         (catch? form) (recur (assoc parser :state :catches))
                         (finally? form) (recur (assoc parser :state :finally))
                         :else (recur (update-in parser* [:body] conj form)))
                :catches (cond
                           (default? form) (recur (assoc parser* :dblock form :state :finally))
                           (catch? form) (recur (update-in parser* [:cblocks] conj form))
                           (finally? form) (recur (assoc parser :state :finally))
                           :else (throw (error env "Invalid try form")))
                :finally (recur (assoc parser* :fblock form :state :done))
                :done (throw (error env "Unexpected form after finally"))))

        finally (when (seq fblock)
                  (-> (disallowing-recur (analyze (assoc env :context :statement) `(do ~@(rest fblock))))
                      (assoc :body? true)))
        e (when (or (seq cblocks) dblock) (gensym "e"))
        default (if-let [[_ _ name & cb] dblock]
                  `(cljs.core/let [~name ~e] ~@cb)
                  `(throw ~e))
        cblock (if (seq cblocks)
                      (fn [[_ type name & cb]]
                        (when name (assert (not (namespace name)) "Can't qualify symbol in catch"))
                        `[(cljs.core/instance? ~type ~e)
                          (cljs.core/let [~name ~e] ~@cb)])
                   :else ~default)
        locals (:locals catchenv)
        locals (if e
                 (assoc locals e
                        {:name e
                         :line (get-line e env)
                         :column (get-col e env)})
        catch (when cblock
                (disallowing-recur (analyze (assoc catchenv :locals locals) cblock)))
        try (disallowing-recur (analyze (if (or e finally) catchenv env) `(do ~@body)))]

    {:env env :op :try :form form
     :body (assoc try :body? true)
     :finally finally
     :name e
     :catch catch
     :children (vec
                 (concat [:body]
                         (when catch
                         (when finally

Emitting code @ clojurescript:src/main/clojure/cljs/compiler.cljc
(defmethod emit* :try
  [{try :body :keys [env catch name finally]}]
  (let [context (:context env)]
    (if (or name finally)
        (when (= :expr context)
          (emits "(function (){"))
        (emits "try{" try "}")
        (when name
          (emits "catch (" (munge name) "){" catch "}"))
        (when finally
          (assert (not= :const (:op (ana/unwrap-quote finally))) "finally block cannot contain constant")
          (emits "finally {" finally "}"))
        (when (= :expr context)
          (emits "})()")))
      (emits try))))