On Mon, Oct 12, 2009 at 4:21 PM, Greg <g...@kinostudios.com> wrote:

> My only concern, and perhaps John could elaborate on this because he
> touched on it, would be how are Java nested classes protected from
> this? Wouldn't it interfere with them? Or will the delimiters be
> restricted to non-alphanumeric characters?


I thought I mentioned that in my previous post. Oh well.

The string literal starting $x would have to START with $x. A symbol with an
internal $ wouldn't behave differently from now. Nor would the symbol $
(just a dollar sign by itself) other than that you would have to always have
whitespace between it and any following parenthesis or other Clojure
delimiter. Identifiers of multiple characters starting with a $ are the
major backward-compatibility hit, but I think these are (at present)
extremely uncommon to nonexistent.

One way to add backward compatibility would be to make the $x thing only
work inside of (with-verbatim-strings ...) or something similar.

Actually, this suggests a way to allow general user-modifiable read tables
without the problems everyone's worried about: custom read tables can be
defined and associated to a var, but to use them the block of code to which
the custom read table would apply would be wrapped in some macro like
(with-read-table rt ...). Presumably these could be nested, and as the
reader left each of these forms the read table would revert to the previous,
using a stack of some sort with the default Clojure read table at the
bottom. Custom read tables could be in libraries, e.g. (ns foo (require
[package.mysuff :as my])) ... (with-read-table my/fancyrt ...) but would not
affect anything unless desired (e.g. (ns foo (use package.mystuff)) won't
cause fancyrt to magically take effect without further action).

This would require (with-read-table ...) to be a super-special form though,
actually evaluated at read time. This would preclude programmatically
generating a working (with-read-table ...) form in a macro, though not USING
a custom read table in a macro where the read table to use was fixed rather
than known only at macroexpansion time (i.e. was not computed from, or
supplied directly via, one of the arguments); in that case, just use
(with-read-table ...) around the macro or inside it.

The (with-read-table ...) should probably become (do ...) rather than be
stripped out by the reader, so (if (cond) (with-read-table
my-perl-interpreter $#*$&%&# @#*@&$&$%)) will behave as expected, evaluating
both perl expressions in the then branch rather than treating them as the
then and else branches as would occur if the (with-read-table ...)
disappeared entirely from around the wrapped code, or treating the first as
a function to call with the second as argument, as would occur if just the
with-read-table and the symbol name disappeared. There should also be a
function with-read-table in core that errors, to catch cases of macros
outputting the thing.

The big trickiness here is that the reader will have to have access to
certain vars; that is, (defreadtable name ...) would have to be evaluated by
the reader, and (ns ...) and (require ...) and the like to discover any read
tables. I think a multi-pass compilation becomes required: code is read up
to the first (with-read-table ...) and then the reader pauses and
macroexpansion and evaluation is done of all completely-read top-level
forms. If the symbol's still not bound at this point, it's an error. This
adds the restriction that (with-read-table foo ...) only works properly if
foo is imported or defined in a previous top-level form, so (let [x 10]
(defreadtable foo ...) (with-read-table foo ...) won't work, and
redefinitions within a top level form won't take effect until the next one.

More sophisticated would be for a (with-read-table ...) to be read initially
into a kind of place-holder token as a string. When it had to be evaluated,
the token would be lazily read and macroexpanded, and hopefully by then the
read table's name has been bound. This would even allow one-off local read
tables, e.g. (let [x (read-table ...)] (with-read-table x)), or even
(with-read-table (read-table ...) ...). It would also be in the spirit of
Clojure, I think, to use laziness in this way. An additional benefit is that
(read-table ...) can be a normal macro or even a normal function call,
rather than a special form, that returns a suitable data structure.

Allowing (with-read-table ...) to be generated by macros is feasible if we
go a step further and make (with-read-table ...) a nearly-normal special
form with the property that a) it cannot redefine the meaning of
parentheses, so everything after the second subform until the matching ) can
be read as a string, unambiguously, and the form after reading becomes
(with-read-table table-expr "one-big-string-literal"), b) the evaluator of
macro output performs the same transformation, and c) when the form is
evaluated, it recursively invokes the read-macroexpand-eval chain on its
second argument in a context where the first argument is pushed into the
readtable stack.

Disallowing changing the behavior of whitespace and ( and ) in custom reader
macros seems like a good idea anyway, especially if the access is to be
through a lispy syntax resembling (with-read-table foo ...) which requires
the meaning of that last ) and immediately-preceding whitespace, and of
internal parenthesis pairs, to remain normal.

On the other hand, doing so would stop the verbatim-string-literal thing
being added in that way...

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