Re: Confusing interplay between macros and metadata

2011-11-09 Thread Marshall T. Vandegrift
Tassilo Horn tass...@member.fsf.org writes:

 I'm facing the same issue.  I have this macro for java interop:

 (defmacro with-traversal-context
   [[g tc]  body]
   `(let [old-tc# (.getTraversalContext ^Graph ~g)]
  (try
(.setTraversalContext ^Graph ~g ^TraversalContext ~tc)
~@body
(finally (.setTraversalContext ^Graph ~g ^TraversalContext old-tc#)

 But the type hints are gone in the macro expansion, thus I have 3
 reflection warnings per macro application, and real, performance
 critical reflection warnings get lost in the shuffle.

What you appear to be having is actually the different, but
conceptually-related problem of the metadata reader macro and unquote
operations interacting in a way which is consistent, but potentially not
optimal.  Fortunately in your sort of situation, you can work around the
problem by replacing the metadata reader macro with explicit metadata
operations.  Something like the following should work:

  (defn assoc-meta [x  kvs]
(with-meta x (apply assoc (meta x) kvs)))

  (defmacro with-traversal-context
[[g tc]  body]
(let [g (assoc-meta g :tag Graph)
  tc (assoc-meta tc :tag TraversalContext)]
  `(let [^TraversalContext old-tc# (.getTraversalContext ~g)]
 (try
   (.setTraversalContext ~g ~tc)
   ~@body
   (finally (.setTraversalContext ~g old-tc#))

-Marshall

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


Re: Confusing interplay between macros and metadata

2011-11-09 Thread Tassilo Horn
Marshall T. Vandegrift llas...@gmail.com writes:

Hi Marshall,

 I'm facing the same issue.  I have this macro for java interop:

 (defmacro with-traversal-context
   [[g tc]  body]
   `(let [old-tc# (.getTraversalContext ^Graph ~g)]
  (try
(.setTraversalContext ^Graph ~g ^TraversalContext ~tc)
~@body
(finally (.setTraversalContext ^Graph ~g ^TraversalContext 
 old-tc#)

 But the type hints are gone in the macro expansion, thus I have 3
 reflection warnings per macro application, and real, performance
 critical reflection warnings get lost in the shuffle.

 What you appear to be having is actually the different, but
 conceptually-related problem of the metadata reader macro and unquote
 operations interacting in a way which is consistent, but potentially
 not optimal.  Fortunately in your sort of situation, you can work
 around the problem by replacing the metadata reader macro with
 explicit metadata operations.

Yes, that would probably do the trick.  But on IRC, Alan already gave me
this recipe (gensyming the given parameter g) which is even a bit
shorter.

--8---cut here---start-8---
(defmacro with-traversal-context
  [[g tc]  body]
  `(let [^Graph g# ~g
 ^TraversalContext old-tc# (.getTraversalContext g#)]
 (try
   (.setTraversalContext g# ~tc)
   ~@body
   (finally (.setTraversalContext g# old-tc#)
--8---cut here---end---8---

-- 
(What the world needs (I think) is not
  (a Lisp (with fewer parentheses))
  but (an English (with more.)))
Brian Hayes, http://tinyurl.com/3y9l2kf

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


Re: Confusing interplay between macros and metadata

2011-11-08 Thread Tassilo Horn
Alan Malloy a...@malloys.org writes:

Hi Alan,

 I want to typehint the return value of f, so I put metadata on the
 form representing a call to it. But if a macro gets involved, there's
 an intervening form that ignores its metadata and returns a new list
 of '(f 10) with no metadata. Thus the compiler has no idea I ever
 wanted to give it a hint about the type.

I'm facing the same issue.  I have this macro for java interop:

--8---cut here---start-8---
(defmacro with-traversal-context
  [[g tc]  body]
  `(let [old-tc# (.getTraversalContext ^Graph ~g)]
 (try
   (.setTraversalContext ^Graph ~g ^TraversalContext ~tc)
   ~@body
   (finally (.setTraversalContext ^Graph ~g ^TraversalContext old-tc#)
--8---cut here---end---8---

But the type hints are gone in the macro expansion, thus I have 3
reflection warnings per macro application, and real, performance
critical reflection warnings get lost in the shuffle.

Is there a way to suppress reflection warnings only in a given scope,
i.e., something like a `do' in whose body no reflection warnings are
issued?

Bye,
Tassilo
-- 
(What the world needs (I think) is not
  (a Lisp (with fewer parentheses))
  but (an English (with more.)))
Brian Hayes, http://tinyurl.com/3y9l2kf

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


Re: Confusing interplay between macros and metadata

2011-10-25 Thread Marshall T. Vandegrift
Alan Malloy a...@malloys.org writes:

 It seems to me that it would be nice to have macros automatically
 include, on their result forms, the metadata from their input
 form. Of course, macros may wish to add metadata as well, so the two
 maps should probably be merged. However, there are certainly some
 problems with this approach: for example if a macro wants to return
 something that can't suppport metadata (like an Integer), the compiler
 needs to be careful not to try to include it. So I'm hoping the
 community can comment on whether this feature would be useful, or
 whether there are fundamental problems with it that I haven't
 foreseen. Is there a reason this can't make it into a future version
 of Clojure?

I think this is an excellent idea.  Overall I believe this reduces the
number of situations in which one needs to be actively aware that a
particular expression will be subject to macro-expansion.  The
alternative-world where the 99% of well-behaved macros returning IMetas
manually forward metadata from form seems like a world with way too
much boilerplate to me.

Forwarding metadata does preclude macros which use metadata applied to
form as parameters and construct new metadata which may not include the
literal values specified in the user-supplied metadata.  I'm not sure
this is a good idea anyway, but this sort of case -- and any others
where metadata should not be forwarded/merged -- could easily be
supported by providing a variation of defmacro with the current
behavior.  Or perhaps by configuring the metadata-forwarding behavior
via metadata on the macro var -- something like:

  (defmacro foo {:forward-meta false} ...) ;; or,
  (defmacro ^:replace-meta foo ...)

If a macro expands to something which doesn't implement IMeta, then I
believe the compiler needs to error out if metadata is applied to it,
just as it does applying metadata to non-IMeta literals.  To do
otherwise would be inconsistent, and result in the same silent data-loss
as macros are yielding today.

This proposal doesn't touch forwarding metadata on forms which become
macro arguments, obviously.  There's still room for inconsistency there,
but I think that's clearly in the court of individual macro authors to
implement the correct behavior.

Are there other contexts where metadata should potentially be forwarded?
I don't know how often this comes up, but:

  (=  (meta ^:foo (quote foo)) (meta (quote ^:foo foo)))
  ;; = false

-Marshall

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


Confusing interplay between macros and metadata

2011-10-24 Thread Alan Malloy
I'm struggling with a basic feature of how macros behave. I understand
how the
problem arises, and I can cobble together my own fix in the specific
places
where it's causing me trouble, but it seems like a prettier, more
general
solution would be desirable. Below is a brief transcript demonstrating
the
problem.

user (defmacro call [f arg] `(~f ~arg))
#'user/call
user (let [f inc] (.intValue (f 10)))
Reflection warning, NO_SOURCE_FILE:1 - reference to field intValue
can't be resolved.
11
user (let [f inc] (.intValue ^Integer (f 10)))
11
user (let [f inc] (.intValue ^Integer (call f 10)))
Reflection warning, NO_SOURCE_FILE:1 - reference to field intValue
can't be resolved.
11

I want to typehint the return value of f, so I put metadata on the
form
representing a call to it. But if a macro gets involved, there's an
intervening form that ignores its metadata and returns a new list of
'(f 10)
with no metadata. Thus the compiler has no idea I ever wanted to give
it a hint
about the type.

There are two solutions that are simple enough for me to apply:

(1) At the call site I can bind the result of (call f 10) to a local
named i and
then put the typehinting metadata on that

(2) I can edit the call macro to return a form with the right
metadata:
(defmacro call [f arg] (with-meta `(~f ~arg) (meta form)))

Both of these work, but they seem awful. If the language specifies
you're
supposed to be able to typehint expressions as well as named bindings,
it's both
unintuitive and quite inconvenient that most macros do not respect
this
behavior by default. And many macros I don't have enough control over
to make
this change. For example, the whole issue arose when I was trying to
hint the
result of a (for ...) as a java.util.List. It ignores my metadata and
returns a
new form; and I certainly can't go edit its source, so instead I have
to bind
the result in a let, for no reason other than to typehint it.

It seems to me that it would be nice to have macros automatically
include, on
their result forms, the metadata from their input form. Of course,
macros may
wish to add metadata as well, so the two maps should probably be
merged. However, there are certainly some problems with this approach:
for
example if a macro wants to return something that can't suppport
metadata (like
an Integer), the compiler needs to be careful not to try to include
it. So I'm
hoping the community can comment on whether this feature would be
useful, or
whether there are fundamental problems with it that I haven't
foreseen. Is there
a reason this can't make it into a future version of Clojure?

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


Re: Confusing interplay between macros and metadata

2011-10-24 Thread Kevin Downey
it's not a macro issue, it's a syntax quote issue

On Mon, Oct 24, 2011 at 11:54 AM, Alan Malloy a...@malloys.org wrote:
 I'm struggling with a basic feature of how macros behave. I understand
 how the
 problem arises, and I can cobble together my own fix in the specific
 places
 where it's causing me trouble, but it seems like a prettier, more
 general
 solution would be desirable. Below is a brief transcript demonstrating
 the
 problem.

 user (defmacro call [f arg] `(~f ~arg))
 #'user/call
 user (let [f inc] (.intValue (f 10)))
 Reflection warning, NO_SOURCE_FILE:1 - reference to field intValue
 can't be resolved.
 11
 user (let [f inc] (.intValue ^Integer (f 10)))
 11
 user (let [f inc] (.intValue ^Integer (call f 10)))
 Reflection warning, NO_SOURCE_FILE:1 - reference to field intValue
 can't be resolved.
 11

 I want to typehint the return value of f, so I put metadata on the
 form
 representing a call to it. But if a macro gets involved, there's an
 intervening form that ignores its metadata and returns a new list of
 '(f 10)
 with no metadata. Thus the compiler has no idea I ever wanted to give
 it a hint
 about the type.

 There are two solutions that are simple enough for me to apply:

 (1) At the call site I can bind the result of (call f 10) to a local
 named i and
 then put the typehinting metadata on that

 (2) I can edit the call macro to return a form with the right
 metadata:
 (defmacro call [f arg] (with-meta `(~f ~arg) (meta form)))

 Both of these work, but they seem awful. If the language specifies
 you're
 supposed to be able to typehint expressions as well as named bindings,
 it's both
 unintuitive and quite inconvenient that most macros do not respect
 this
 behavior by default. And many macros I don't have enough control over
 to make
 this change. For example, the whole issue arose when I was trying to
 hint the
 result of a (for ...) as a java.util.List. It ignores my metadata and
 returns a
 new form; and I certainly can't go edit its source, so instead I have
 to bind
 the result in a let, for no reason other than to typehint it.

 It seems to me that it would be nice to have macros automatically
 include, on
 their result forms, the metadata from their input form. Of course,
 macros may
 wish to add metadata as well, so the two maps should probably be
 merged. However, there are certainly some problems with this approach:
 for
 example if a macro wants to return something that can't suppport
 metadata (like
 an Integer), the compiler needs to be careful not to try to include
 it. So I'm
 hoping the community can comment on whether this feature would be
 useful, or
 whether there are fundamental problems with it that I haven't
 foreseen. Is there
 a reason this can't make it into a future version of Clojure?

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




-- 
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

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