Skip to end of metadata
Go to start of metadata


We need an interface to type information that:

  • encapsulates Java reflection
  • returns Clojure data not Java's reflection objects 
  • supports ASM in addition to reflection
    • ASM offering type info without loading classes
  • supports ClojureCLR

Users will be compilers and tools, as well as REPL users through an interactive wrapper interface.

Design Decisions

  • using Clojure symbols to represent class and method names
    • pro: matches Clojure's use of symbols, easy literal rep
    • con: requires [] to <> conversion (but this conversion is already in place elsewhere in Clojure!)
    • also considered keywords and a new datatype. 
      • rejected keywords as they have the same cons as symbols, and feel less idiomatic
      • rejected new datatype as too much pain for not enough gain. Literal rep is a huge advantage
  • get the data out as quickly as possible
    • APIs convert reflection/asm APIs into Clojure data before doing anything else
    • gives you the entire Clojure data API to manipulate
    • simplest to implement
    • will be less performant for the case where you only want a tiny bit of info, but I don't have a use case needed that perf
  • create my own table of java access bitflags (flag-descriptors), instead of using constants from reflection or ASM
    • at first glance the existing constants might seem fundamental, but the spec actually dominates
    • the existing constants don't capture all the information (different flags apply to different types)
    • existing flags can't change, and if new ones emerge the code would have to change even if I was using the existing constants
  • use defrecords for constructor, field, method
    • wanted types for polymorphic dispatch for printing
    • the print dispatch is not general, I still want map-ish printing through pprint (note Rich questions this below)
  • keep fields/methods/records in a set
    • they are logically a set (no order imposed by spec)
    • they have a lot in common (flags, name, etc.)
    • considered three separate sets for fields/methods/constructors, but given that no choice is ideal for all API consumers decided to keep it simple. Classes have members of different types.
  • two levels of reflection: class, or class-plus-ancestors
    • does not correspond to Java reflection's distinction of declared here vs. visible-from-here
    • I have always believed Java had this wrong: visible from here is a derived fact. Class or class+ancestors reflects the reality of the data, while visible-from-here is driven by a single use case
    • that said, the compiler will want visible-from-here, so when the compiler starts using this API we will need to derive it
  • reflection is parameterized by Reflector protocol
    • there will be one or more implementations per platform
    • reflection is scoped to Reflector's notion of how to find classes
      • toyed with making this implicit in some way, scarily complex for no benefit
    • considered dynamic scope for default reflector
      • bad idea: just creates more stateful magic
      • defaulting to platform reflecting by arity provides ease-of-use without the complexity of dynamic scope


Note, this list is primarily RH's notes on Stu's patch. Stu's initial replies inline

  • hrm, the predicate language in describe thinking about this** always and/every?
      • single pred would allow arbitrary logic
    • Explore query-by-example, i.e. user provides partial data in same shape as returned
  • reflect-impl bad name for fn
    • prefer things like do-reflect, still a verb
    • I hate overloading "do" because it already means "force". Come to think about it, it's too bad doall isn't force-all. :-)
    • understand the problems with -impl, don't have a better word yet
  • typeref->name - typename ok
  • typeref->sym - typesym ok** typeref->* implies things of type typeref, we don't want to reify protocol like that
    • ditto - typepath
  • are we exposing the descriptor, internal-name confusion by having these helpers public, with no better docs than we complain about?
    • the easiest way to explain these is be enumerating a few examples (which the tests do)
    • this is a place where I want the tests inline (which doesn't work with our CI harness) or a well-known convention of looking to the tests for examples (like Ioke does)
    • if I am forced to repeat myself in tests and documentation I will just make these private to avoid having to answer the bigger questions. :-)
  • defrecord Constructor/Method/Field
    • make sure distinguishing these by type adds value only value is in reflection-specific pprint. Still undecided, let's discuss.
    • much pain today in writing generic reflection code due to unequal treatment of members
      • i.e. ctors are glorified static methods
    • I'd prefer a first cut with maps and see where that is inadequate
      • perhaps already done, notes?
  • defrecord JavaReflector/AsmReflector ok** unlike Contrstructor/Method/Field, these are plainly not information but are programming constructs and should be deftypes
  • describe's built in pprint
    • can we not get pprint to print the data structures nicely? I don't want to (see my design notes above). What I really thought I wanted was context-specific pprint.
    • giving the user a bunch of printout they can't lift and use as data isn't that great
      • may be more useful to enhance pprint
      • the thing that I don't like about existing pprint in this scenario is the verbosity of enumerating keys that are obvious from context. I don't have a solution.