The first thing I ran into was some dependencies on "old" contrib bits
and pieces. Clearly those dependencies have to be removed in the "new"
contrib stuff so I wondered whether anyone had thought much about how
to handle the lower-level utilities that some of the "old" contrib may
rely on? c.c.except is used in several for throwf. c.c.seq is used in
a few for indexed. These are mostly just simple conveniences so one
possibility is to simply unwind the convenience layer back to the
underlying necessary code but I wonder about possible duplication...
For example, indexed seems useful but c.c.sql is the only module that
relies on it so simply replacing it with (map vector (iterate inc 0)
s) is fine (although my temptation is to use the more obvious
(map-indexed identity s) here even tho' that's heavier code!).
On the other hand, several modules use throwf and that's quite a chunk
of code, even tho' it can mostly be boiled down to (throw (Exception.
(format "..." ...))) in the cases where it is used.
Since the author of c.c.sql also wrote c.c.except, I'll see what he
wants to do there but I thought I'd raise the general issue to get
input / guidance from everyone.
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/
"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)
https://github.com/seancorfield/java.jdbc
I'll take further discussion off-list with Steve and see how he wants
to proceed.
Sean
If you need c.c.except only to have a compiled exception from Clojure, see http://dev.clojure.org/jira/browse/CLJ-733, still in progress.
Cheers,
Stu
> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
Already replaced in my fork - mostly with (throw (Exception. (format
"..." args))) since that meant less futzing with the code. Switching
to (str ...) would be more efficient and I don't think the java.jdbc
code does anything very complex with (format ...) in this case.
> `indexed` is deprecated in favor of the (more efficient) `map-indexed` in
> clojure.core.
Good to know (about the efficiency of map-indexed).
> Expressions like this:
>
> (doseq [[index count] (indexed (.getUpdateCounts exception))] ...)
>
> should be replaced with the equivalent:
>
> (dorun (map-indexed (fn [count i] ...) (.getUpdateCounts exception)))
Thanx (although it's (fn [index count] ...) right?).
I also noticed:
(doseq [[index value] (map vector (iterate inc 1) params)]
(.setObject stmt index value))
which I replaced with:
(dorun
(map-indexed
(fn [index value]
(.setObject stmt (inc index) value))
params))
> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>
--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?
For the record, throwf is by far the most common old-contrib usage in
our codebase since clojure.java.io has been introduced. Second place
goes to clojure.contrib.io/to-byte-array.
-Phil
Phil,
Thanks for the specific, actionable feedback. I have added both of these, plus my recommendation, at http://dev.clojure.org/display/design/Contrib+Library+Names.
Stu
Since you seem interested in real use of stuff in old contrib, I went
through the four internal projects we have at Revelytix (about 46000
lines of clj, including test code).
Other than things already being handled (sql, logging, json, xml), I
found these usages below. I've put ****'s by ones that I think maybe
should be considered for either core or a new contrib module.
command-line - 6
core
-?> - 1
.?. - 1
def
name-with-attributes - 1
defn-memo - 1
error-kit **** - definitely want something
"standard" here
deferror
throw-msg
raise
with-handler
handle
generic.functor
fmap - 10 **** - consider for core maybe?
macro-utils
symbol-macrolet - 3 **** - candidate for tools.macro?
properties
read-properties - 1
str-utils2
partition - 3 **** - consider split variant for clojure.string?
take - 1
seq-utils
find-first - 9 **** - consider for core?
indexed - 2 **** - consider for core?
zip-filter - 2
For completeness sake, here's ours:
;; It's all about the throwf. I would be thrilled if throw were
;; upgraded to act like throwf if its first argument is a string, much
;; like how slurp gained super powers when clojure.java.io was added.
clojure.contrib.except :only [throw-arg]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
clojure.contrib.except :only [throwf]]
;; Lots of uses of c.c.condition, (elided) but we have a private fork
;; of that for our own patches that haven't been applied upstream yet.
;; The data-conveying-exception proposal sorta covers this.
;; Condition's handle appeals to me, but we're getting most of
;; the value from raise and haven't used handle enough to argue for
;; its promotion.
;; Mostly to-byte-array. IIRC delete-file-recursively can't be
;; promoted until the JVM can distinguish between directories and
;; symlinks. Unfortunate but understandable.
clojure.contrib.io :only [*buffer-size* *byte-array-type* copy]]
clojure.contrib.io :only [copy file to-byte-array]]
clojure.contrib.io :only [delete-file-recursively]]
clojure.contrib.io :only [delete-file-recursively]]
clojure.contrib.io :only [file delete-file-recursively]]
clojure.contrib.io :only [file-str to-byte-array]]
clojure.contrib.io :only [to-byte-array]]
clojure.contrib.io :only [to-byte-array]]
clojure.contrib.io :only [to-byte-array]]
clojure.contrib.io :only [to-byte-array]]
;; These are graduating to new libraries.
clojure.contrib.logging :only [debug warn]]
clojure.contrib.logging :only [error warn]]
clojure.contrib.logging :only [error warn]]
clojure.contrib.logging :only [error]]
clojure.contrib.logging :only [info debug]]
clojure.contrib.logging :only [info warn]]
clojure.contrib.logging :only [info]]
clojure.contrib.logging :only [warn]]
clojure.contrib.sql :only [with-connection with-query-results]]
clojure.contrib.sql :only [with-connection with-query-results]]
clojure.contrib.sql :only [with-connection with-query-results]]
clojure.contrib.sql :only [with-connection with-query-results]]
clojure.contrib.sql :only [with-connection with-query-results]]
;; Indexed is more composable than map-indexed and has value on its own.
clojure.contrib.seq :only [indexed]]
clojure.contrib.seq :only [indexed]]
clojure.contrib.seq :only [indexed]]
clojure.contrib.seq :only [indexed]]
clojure.contrib.seq :only [indexed]]
;; Extremely useful for deprecations, though a version that could
;; print a warning upon first use could be even better.
clojure.contrib.def :only [defalias]]
clojure.contrib.def :only [defalias]]
clojure.contrib.def :only [defalias]]
;; The single-use stragglers; not terribly attached to these. We would
;; probably just bundle them if they went away.
clojure.contrib.generic.comparison :only [< >]]
clojure.contrib.server-socket :only [create-server close-server]]
clojure.contrib.java-utils :only [as-str]]
clojure.contrib.java-utils :only [with-system-properties]]
-Phil
Given that throwf checks its first couple of arguments for optional
class name, optional cause etc and has arguments after the string that
represent substitutions for the format string, how would you see that
working? (I think I have some ideas, having just unwired except/throwf
from java.jdc, but I'd be interested to hear other thoughts - and,
yes, being about to (throw "message") and have it behave like (throw
(Exception. "message")) would be a great shorthand!).
> clojure.contrib.sql :only [with-connection with-query-results]]
Moving to clojure.java.jdbc.
> ;; Indexed is more composable than map-indexed and has value on its own.
I must admit, indexed does seem to be useful although in java.jdbc,
each use ended up being replaced with map-indexed. I'd be interested
to look at the uses of indexed with your code (it would be educational
for me, if nothing else :)
> ;; Extremely useful for deprecations, though a version that could
> ;; print a warning upon first use could be even better.
> clojure.contrib.def :only [defalias]]
java.jdbc had two uses of defalias which I simply replaced by def for
the time being, until I talk to scgilardi (or someone else can school
me on why a simple def wouldn't really work - in java.jdbc, it just
seemed a way to expose some internal functions with external names).
Rich and I met this afternoon, and I have updated http://dev.clojure.org/display/design/Contrib+Library+Names to include new homes for almost everything that has been pointed out here.
The one exception is error-kit, which needs more consideration.
Stu
> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>
--
Incubator namespaces represent things that might get moved in the future.
> what is its relationship with
> clojure.java.io?
clojure.java.io is a likely promotion target for clojure.io.incubator.
> do we really need a whole new namespace for a single
> function?
The other option is no function.
> why is to-byte-array going in clojure.io.incubator and not
> clojure.java.io?
Might get moved in the future.
> did someone take minutes at your meeting with rich?
Yes: http://bit.ly/g8U8Zb.
Stu
this seems like more of a restatement of the current state of affairs
instead of a reason for the current state of affairs. I am just
curious as to why to-byte-array is not suitable for clojure.java.io? I
know I am hesitant to trust it since the last time I used a function
with a vaguely similar name from duck-streams it transformed files
into byte arrays by slurping them and calling .toBytes on the string.
Are there actual concerns about to-byte-array that might be addressed
now, or it just has to sit in incubator for some length of time
waiting for bugs to show up and get shaken out?
[cleverly disguised link to the same content elided]
Would add-handler + the usage pattern shown below serve as a viable alternative to error-kit?
Stu
;; Copyright and license like Clojure, http://clojure.org
(defn add-handler
"Compose f, an arbitrary function, with a handler. The composed
function will call f. If f throws an exception, the handler is
called, with the exception, the function, and the original
function arguments as its arguments.
Typically used with a dynamically bound handler to permit error
handling strategies at the point of an error, without requiring
extra parameters throughout an API."
[f handler]
(if handler
(fn [& args]
(try
(apply f args)
(catch Exception e
(apply handler e f args))))
f))
(def ^:dynamic
*bad-number-handler*
"error handling contract is nothing more than a fn, dynamically bound"
nil)
(defn parse-int
"Contrived example that is forced to use exceptions for flow control."
[s]
(Long/parseLong s))
(defn better-parse-int
"Provide a higher arity version that lets the caller pass in a
strategy for dealing with trouble."
([s]
(Long/parseLong s))
([s handler]
(try
(better-parse-int s)
(catch NumberFormatException e
(handler s)))))
;; bending parse-int to your will
(binding [*bad-number-handler* (constantly 0)]
(vec
(map
(add-handler parse-int *bad-number-handler*)
["2" "4" "duck typing rules"])))
;; using better-parse-int
(vec
(map
#(better-parse-int % (constantly 0))
["2" "4" "duck typing rules"]))
Talking with Ryan, though, the choice to use error-kit was driven by
the hope that our use of the lib would expand to use more of its
features. My hope, specifically, was that our routines could provide
one or several default handlers for common exception cases.
An issue of Java, that Clojure could improve upon here, is that APIs
merely signal that an exception has occurred and leave it to the
consumer to figure out how to recover. I've seen a lot of empty Java
catch blocks. It's a bit more insidious in Clojure since the compiler
doesn't force you to catch checked exceptions, that try/catch is often
omitted entirely, or an application has only a single try/catch around
the program's highest entry point and the error message is simply
printed to the console.
tl;dr `add-handler` if added to core, could replace our current
error-kit usage, but I want restarts
Same here. We too use error-kit pretty heavily and our use-case is
identical to what Ryan & Nate have.
Would love restarts if possible.
Regards,
BG
--
Baishampayan Ghose
b.ghose at gmail.com
I'm a little puzzled by the discussion of add-handler. It seems like a
band-aid solution to the real problem. Perhaps it's time to talk about
language-level error handling again
(http://dev.clojure.org/display/design/Error+Handling)?