On Jun 12, 12:16 pm, Chouser <chou...@gmail.com> wrote:
> On Thu, Jun 11, 2009 at 3:35 AM, Wrexsoul<d2387...@bsnow.net> wrote:
>
> > On a side note, I've noticed a few issues with clojure
> > that could use a bit of sprucing up, no disrespect
> > intended:
>
> > * If REPL code goes into infinite loop, only escape is to
> >   reset the REPL,  which loses everything. Perhaps make
> >   ctrl-C interrupt and return to  prompt? It could throw
> >   InterruptedException into the running code, or  Error,
> >   or something.
>
> See 'clojure.contrib.repl-utils/add-break-thread!'

user=> (doc clojure.contrib.repl-utils/add-break-thread!)
#<CompilerException java.lang.Exception: Unable to resolve var:
clojure.contrib.repl-utils/add-break-thread! in this context
(NO_SOURCE_FILE:1)>

Must need a third-party library for that, one that i don't have.

> > * No apparent way to change imports on-the-fly in REPL,
> >   have to  recompile all dependencies, close REPL, and
> >   reopen REPL. Tedious.
>
> I'm not sure what you mean by this.
>
> user=> (File. "/tmp")
> java.lang.IllegalArgumentException: Unable to resolve classname: File
> (NO_SOURCE_FILE:31)
>
> user=> (import 'java.io.File)
> java.io.File
>
> user=> (File. "/tmp")
> #<File /tmp>

Eh. That works. I tried (import java.io.File) and (import java.io/
File), as well as (import (java.io File)), mimicking the syntax
of :import in ns.

That's another of the problems -- some things, like import, are very
tersely documented at present, so the form the argument is to take is
not clear. My own preference when writing macros of making them quote
arguments for you that should probably be quoted might be part of it
-- see with-global-if-exists, which has (quote ~arg) in it for
precisely the reason that you will not want that argument evaluated.

> > * Compiler diagnostics could use some improvement. Many are cryptic,
> >   not clearly indicating the nature of the original
> >   problem. Line number isn't always given if a REPL
> >   expression triggered the exception, even  if the actual
> >   error is in a .clj file. Given many functions and
> >   expressions on some lines, column number would be useful
> >   too.
>
> Feel free to suggest specific improvements to specific error
> messages.  It would be most helpful if such reports included
> an example to generate the message and maybe a suggestion
> for what the message should be.

As I said, the most useful thing would be a) always having an accurate
line number if the problem was not in REPL-submitted code but in
a .clj file, even if it was a REPL-submitted expression that triggered
the exception, and b) a better message specifically for unquote/
unquote-splicing unbound.

> > * One especially cryptic error: undefined symbol
> >   clojure.core/unquote  (or unquote-splicing). This looks
> >   like library misconfiguration but  comes from forgetting
> >   the back-tick in some macro somewhere.
>
> This is actually pointing you toward a feature! :-)   You
> can define unquote yourself.  This can be useful for
> creating your own DSLs.

My point was that the message is not very helpful in the majority of
cases because the error is generally something else (missing back-
tick) than what it suggests (missing import/wrong namespace/missing
files/classpath problems).

> I'm glad you found defonce.  Since it *is* a documented API,
> it may be worth figuring out how to use it instead of
> .hasRoot().

I only resorted to .hasRoot because defonce had odd side effects. In
particular,

user=> foo
#<CompilerException java.lang.Exception: Unable to resolve symbol: foo
in this context (NO_SOURCE_FILE:0)>
user=> (ns-resolve *ns* 'foo)
nil
user=> (let [x (ns-resolve *ns* 'foo)]
         (if x
           (defonce foo nil)))
#'user/foo
user=> foo
nil

So it looks like when the compiler expands defonce, it actually
evaluates a def right then and there, rather than the def only being
evaluated when the expansion of the defonce macro is evaluated. This
is the only explanation for the second-to-last form evaluating to
anything but nil, let alone for foo getting defined.

My code avoided that, on the assumption that in some case conditional
behavior OTHER than defining the global might be desired.

> A couple other comments on your code:
>
> > (defmacro thread [& body]
> >  `(Thread. (proxy [Runnable] [] (run [] ~...@body))))
>
> Clojure functions already implement Runnable, so can be
> written:
>
> (defmacro thread [& body]
>   `(Thread. (fn [] ~...@body)))

That's convenient. Another bit that might have been more usefully/
prominently documented. :)

> > (defmacro do-asynch-periodically [nm interval & body]
> >  `(defdaemon ~nm
> >     (loop []
> >       (Thread/sleep (* 1000 ~interval))
> >       ~...@body
> >       (recur))))
>
> The 'recur' will loop to the enclosing function if no 'loop'
> is given, so in this case you could leave out the 'loop'.

Yeah, but I prefer to put the recur-point and the recur together in
the same place. Consider what would happen if we had

(defmacro foo [arg & body]
  `(do-something-with arg (fn [] ~...@body))

(defn bar [arg]
  (foo arg
    (if (doit-with arg)
      nil
      (do
        (Thread/sleep 1000)
        (recur)))))

(say, to wait on a state change in an atom somewhere?) and later the
macro was redefined:

(defmacro foo [arg & body]
  `(do-something-with arg (fn [] (fiddlesticks) ~...@body))

The call to (fiddlesticks) that's been added is probably meant to
occur only once each time the fn is called, but it will get called
every time around the loop in bar, which wouldn't happen if bar had
its own loop.

In other words, using loop explicitly makes the code less sensitive to
changes in the macro that calls it. It reduces the potential for
innocent changes later to cause unexpected, difficult-to-track-down
logic errors.

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to