...
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
Issues
Note, this list is primarily RH's notes on Stu's patch.
...