Feedback on Code Reflection API
Olexandr Rotan
rotanolexandr842 at gmail.com
Fri Sep 13 21:44:12 UTC 2024
Hello to everyone on the mailing list. I would love to share some feedback
with you regarding the Code Reflection API used to implement LINQ in java.
Unfortunately, I found myself in the situation where I don't have much time
to work on a project and probably will not have it in the
foreseeable future, so I will have to speak based on limited
experience using the API. Firstly, I will talk about the problems I
encountered, then mark some positive features and finish with general
thoughts on the direction of the project and jdk in general.
The problems started earlier than expected, particularly on extending the
Quotable interface. When I just built jdk from Babylon and created a new
project, the quoted() method, to my surprise, has been throwing
UnsupportedOperationException. I spent multiple hours trying to figure out
whats wrong, unit finally I stumbled onto following rows in babylon repo:
A subset of code in java.base is copied with package renaming into the
jdk.compiler module.
This gave me a hint to add "requires jdk.compiler" to module-info, and it
finally worked! I am not sure if this is how it intended to work, but if
so, this topic could use more clarification.
Moving to API itself, there are a few points I would like to address. I
would like to emphasize that I am speaking as a person that builds API to
reach out from one high-level language to another, so my feedback is
obviously biased. That said, I found an API containing too many low level
details.I didn't even get to know what is dominatedBy and other methods
related to this "domination". The difference between body and block is also
not clear, I didn't find a case during work on a project where the body
just had one block.
Naming could also use some improvement. Specifically, the uses() method,
due to word meaning both that it uses something and that it is used by
something is unclear to me. capturedValues() name also was really
misleading to me, since it seems like it should return a map of values of
expressions inside the OP, while it, as I understand, just includes some
part underlying ops. It also is really similar to capturedValues() of
LambdaOp which in fact contains captured values. AAnd just generally,
having VarAccessOp to contain its captured value would be really helpful
since it would spare from passing down Map of captured values through a
long chain of methods.
I also did not find a particular use for the transform method. I initially
thought it could be used to translate a tree into another language tree,
but it instead transforms op into another op. I'm not sure if it replaces
one node with another (which would make the tree mutable), or if it just
produces a new one and then I don't really know what's the use of it.
Lastly, what was particularly strange is the fact that composite condition
ops do not contain their operands and are not in their operands() method,
but instead in bodies() method. Not sure if its intended, but for me it was
extremely counterintuitive.
Now let's talk about positive sides. Generally, I really liked that API is
(if all low-level methods are ignored), pretty simple yet powerful. I
managed to get everything that I required using just a few simple methods
like operands(), resolveTOHandle(), result() and other once situatively. By
the way, talking about result(), I didn't find a case where it returns
something other than Op.Result, and I guess for many op types result()
return type could be narrowed.
I also found it really pleasant that Quotable is implemented by default, so
I don't have to do any additional steps to start working with
Quotable-extending interfaces. Though, it would be really helpful if
java.util.function interfaces can become Quotable (unless there is a
conversion between equivalent functional interfaces), so LINQ and other
querying apis could become interchangeable with streams.
And lastly, a few thoughts about the general direction of Babylon
development. I am obviously biased, but I found the API too low level. I
would also argue that most of the use cases for java developers will
interact with code reflection api would involve reaching out to other
high-level languages, so it would make sense to make api a little more
abstracted. Generally speaking, the jdk approach to "shoot in the middle"
seems wrong to me. Generally, some particular use case takes up like 95% of
demand for features. This is not particularly the case here, but
accumulatively high-level languages would be, I guess, the most
common target. Currently, on the other hand, API aims at middle-level
languages (if those even exist), and lowering tree is used for low-level
interactions. I would argue that non-lowered API should aim for high level
languages, while lowered for low level. Middle-level models could be
produced as a high level tree + some details from a lowered one.
That's all for now. I hope in future I could spare some more time and
contribute something more than currently, maybe providing feedback also on
API evolution.
PS: github repo if you are interested: https://github.com/Evemose/linq
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/babylon-dev/attachments/20240914/0df8b6ca/attachment-0001.htm>
More information about the babylon-dev
mailing list