java.jdbc and a general question about dependencies on "old" contrib

104 views
Skip to first unread message

Sean Corfield

unread,
Apr 17, 2011, 7:17:32 PM4/17/11
to cloju...@googlegroups.com
I forked the new repo so I could see what's involved in getting this
into a working shape, using tools.logging as an example.

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)

Sean Corfield

unread,
Apr 17, 2011, 7:49:20 PM4/17/11
to cloju...@googlegroups.com
Just FYI, in my fork, it no longer depends on c.c.*, it "compiles" and
installs via maven and I'm able to use it for my own (soon to be
production) code. What it really needs are some tests that actually
pass / fail. Feel free to look it over and provide feedback:

https://github.com/seancorfield/java.jdbc

I'll take further discussion off-list with Steve and see how he wants
to proceed.

Sean

Stuart Sierra

unread,
Apr 17, 2011, 8:06:44 PM4/17/11
to cloju...@googlegroups.com
`throwf` is never necessary. As it's used in c.c.sql, it can be replaced by:

    (throw (Exception. (str "some message: " ...))))

`indexed` is deprecated in favor of the (more efficient) `map-indexed` in clojure.core.  Expressions like this:

    (doseq [[index count] (indexed (.getUpdateCounts exception))] ...)

should be replaced with the equivalent:

    (dorun (map-indexed (fn [count i] ...) (.getUpdateCounts exception)))

-S

Stuart Halloway

unread,
Apr 17, 2011, 8:18:00 PM4/17/11
to cloju...@googlegroups.com
In the specific case of c.c.except and c.c.seq, we should unwind the helper libs -- they haven't proven enough value to move forward, beyond the parts of seq that already did.

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.
>

Sean Corfield

unread,
Apr 17, 2011, 8:39:50 PM4/17/11
to cloju...@googlegroups.com
On Sun, Apr 17, 2011 at 5:06 PM, Stuart Sierra
<the.stua...@gmail.com> wrote:
> `throwf` is never necessary. As it's used in c.c.sql, it can be replaced by:
>
>     (throw (Exception. (str "some message: " ...))))

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?).

Sean Corfield

unread,
Apr 17, 2011, 8:53:49 PM4/17/11
to cloju...@googlegroups.com
On Sun, Apr 17, 2011 at 5:39 PM, Sean Corfield <seanco...@gmail.com> wrote:
>>     (doseq [[index count] (indexed (.getUpdateCounts exception))] ...)
>> should be replaced with the equivalent:
>>     (dorun (map-indexed (fn [count i] ...) (.getUpdateCounts exception)))

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))

Kevin Downey

unread,
Apr 18, 2011, 2:15:35 AM4/18/11
to cloju...@googlegroups.com
(throw (Exception. (format "..." ...))) or (throw (Exception. (str
...))) are very common, would be nice to support something that makes
it less of an eyeful

> --
> 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?

Phil Hagelberg

unread,
Apr 18, 2011, 2:39:32 PM4/18/11
to cloju...@googlegroups.com
On Sun, Apr 17, 2011 at 11:15 PM, Kevin Downey <red...@gmail.com> wrote:
> (throw (Exception. (format "..." ...)))  or (throw (Exception. (str
> ...))) are very common, would be nice to support something that makes
> it less of an eyeful

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

Stuart Halloway

unread,
Apr 19, 2011, 8:00:00 AM4/19/11
to cloju...@googlegroups.com

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

Alex Miller

unread,
Apr 19, 2011, 2:52:24 PM4/19/11
to cloju...@googlegroups.com, Stuart Halloway
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

Phil Hagelberg

unread,
Apr 19, 2011, 4:44:38 PM4/19/11
to cloju...@googlegroups.com
On Tue, Apr 19, 2011 at 11:52 AM, Alex Miller <al...@puredanger.com> wrote:
> 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).

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

Sean Corfield

unread,
Apr 19, 2011, 7:51:18 PM4/19/11
to cloju...@googlegroups.com
On Tue, Apr 19, 2011 at 1:44 PM, Phil Hagelberg <ph...@hagelb.org> wrote:
> ;; 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.

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).

Stuart Halloway

unread,
Apr 19, 2011, 8:26:57 PM4/19/11
to cloju...@googlegroups.com
Thanks to Phil and Alex and everyone else who helped out documenting actual use!

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

Kevin Downey

unread,
Apr 19, 2011, 9:12:05 PM4/19/11
to cloju...@googlegroups.com
what is clojure.io.incubator? what is its relationship with
clojure.java.io? do we really need a whole new namespace for a single
function? why is to-byte-array going in clojure.io.incubator and not
clojure.java.io? did someone take minutes at your meeting with rich?

> --
> 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.
>
>

--

Stuart Halloway

unread,
Apr 19, 2011, 9:21:15 PM4/19/11
to cloju...@googlegroups.com
> what is clojure.io.incubator?

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

Kevin Downey

unread,
Apr 19, 2011, 9:29:54 PM4/19/11
to cloju...@googlegroups.com
On Tue, Apr 19, 2011 at 6:21 PM, Stuart Halloway
<stuart....@gmail.com> wrote:
>> what is clojure.io.incubator?
>
> 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.

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]

Stuart Halloway

unread,
Apr 19, 2011, 10:21:48 PM4/19/11
to cloju...@googlegroups.com
Alex Miller et al,

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"]))

Ryan Senior

unread,
Apr 20, 2011, 9:09:22 AM4/20/11
to cloju...@googlegroups.com
I think it would cover how error-kit is currently being used at Revelytix.

-Ryan

Nate Young

unread,
Apr 20, 2011, 9:47:25 AM4/20/11
to cloju...@googlegroups.com
I agree with Ryan that this covers our current usage of error-kit in
our codebase. However, we're only exercising a small subset of
error-kit's functionality, and that's (I believe) completely
overlapping with functionality that try/catch provides.

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

Baishampayan Ghose

unread,
Apr 20, 2011, 9:57:36 AM4/20/11
to cloju...@googlegroups.com
On Wed, Apr 20, 2011 at 7:17 PM, Nate Young <you...@gmail.com> wrote:
> 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

Constantine Vetoshev

unread,
Apr 20, 2011, 11:47:49 AM4/20/11
to cloju...@googlegroups.com
On Wed, Apr 20, 2011 at 6:47 AM, Nate Young <you...@gmail.com> wrote:
> tl;dr `add-handler` if added to core, could replace our current
> error-kit usage, but I want restarts

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)?

Stuart Halloway

unread,
Apr 20, 2011, 7:37:20 PM4/20/11
to cloju...@googlegroups.com
Having written that page, and discussed it endlessly over the past several months, I am unconvinced that solving (whatever we think the problem is here) is a high priority. That said, there is plenty of discussion to build on, and if somebody wants to lead a discussion through to a design, we can make a contrib incubator for it.

Stuart Halloway
Clojure/core
http://clojure.com

Reply all
Reply to author
Forward
0 new messages