-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Port of clojure.pprint to Basilisp #895
Conversation
0e214e5
to
2285af8
Compare
I put temporary hack in the pprint tests (test_pprint.lpy, contrib/pprint/test_pretty.lpy and contrib/test_cl_format.lpy) because they may be called individually with coverage run (and as such break), instead of |
Hi, I've taken the liberty to concatenate the It is prime for review. Thanks |
4b5f4b4
to
e6bdad4
Compare
e6bdad4
to
a013724
Compare
Hi @chrisrink10, any chance you could review the The commits are build upon each other in case you are interested in reviewing how this involved
Thanks |
Thank you for the PR. I appreciate your continued contributions to the project, but I have some fairly serious misgivings about this changeset which is why I have not moved forward with reviewing it. I apologize for the radio silence for so long, but I have struggled with putting my thoughts to paper. My concerns fall into two broad categories: philosophical and practical. As to the philosophical concerns, I am broadly against importing more code from other repositories due to licensing and copyright claims. This code comes from Clojure which should be license-compatible, but otherwise carries Rich Hickey's copyright claims. We have already taken the It may not be an issue because certainly many portions of I also have 2 practical concerns. First is that this relies on proxies, which are as yet unimplemented. I know you made an attempt to do so in Basilisp (as #818), but it is my preference to actually do this work in the compiler using a special form since I don't prefer to spread the arity-mapping logic across core and the compiler (to the extent that is possible). The second concern is somewhat more selfish, but I'm concerned about importing a large Clojure library (and associated test suite) written in a style that is somewhat messier and more old-school than what I prefer. When changes to core or other libraries affect e.g. the nREPL server tests I often find myself having to dig deep to understand why the error has occurred. I'm concerned this issue will be amplified with a considerably more complex library and test suite. In the absence of a clear path forward here, it may be worthwhile considering publishing this as a separate library which you (and others) can use until I can resolve what to do here. I'm sorry if this is not the answer you were looking for, but I just haven't been able to shake these concerns in the intervening months since you submitted this PR. |
Hi, I completely understand and share your concerns, but unfortunately, I am not able to fully address them. My original intention was to place any ported code under the The critical issue here seems to be the concept of "claim"—specifically, the possibility of someone asserting ownership of the code and making adverse demands regarding its usage, which is indeed concerning. In the case of the I also reviewed the EPL-1.0 license, particularly the sections on derived works, but the legal implications are not obvious from the language, and I didn’t gain much clarity from it. Unfortunately, I'm not any more knowledgeable on this topic after my brief review. My attempt to mitigate the copyright concerns for Given the concerns raised, I think it would be best to publish the library as a separate package. I now feel confident in doing so after having published a couple of packages already. The same approach could be taken with the I will leave the Thanks |
Something that may or may not be appropriate to note here: a lot of the code for pprint comes from the implementation of cl-format, Common Lisp's string format function. Clojure's pprint's basic goal is to pretty print code structures, and I wonder if it would be doable to just write your own version of that functionality first in a more naive way, and port cl-format later (or never cuz it's slow and imo outdated). |
Hi @NoahTheDuke
I agree that I did explore the more self-contained cljs.pprint as a potential source for porting, but I encountered some JavaScript-specific nuances that I wanted to avoid, and it is also relying on The porting of Feel free to start implementing The primary reason I originally wanted Thanks |
@NoahTheDuke @ikappaki what do you consider the fundamental API for As I said above, I think the entire API is quite messy and confusing. I've never needed to use it though aside from occasionally calling |
In my opinion and experience, the fundamental API of clojure.pprint is Looking at the code in Compare with fipp, which is only 1010 lines of code and covers all of the same functionality. Supporting the dynamic variables of The bindings are important because 1) compatibility with all other clojure code, and 2) the API wasn't designed for a context map to be passed along. If The dispatch functions are necessary because the calls are mutually recursive: Given that it was written for 1.2, pprint uses multimethods with Comparison of future cljc code: (defmethod clojure.pprint/simple-dispatch #?(:clj jvmObj :lpy pythonObj) custom-simple-pprint-function)
(defmethod clojure.pprint/code-dispatch #?(:clj jvmObj :lpy pythonObj) custom-code-pprint-function)
;; or
#?(:clj (do (defmethod clojure.pprint/simple-dispatch jvmObj custom-simple-pprint-function)
(defmethod clojure.pprint/code-dispatch jvmObj custom-code-pprint-function))
:lpy (extend-protocol PrettyPrint
pythonObj
(-simple-print [obj] (custom-simple-pprint-function obj))
(-code-print [obj] (custom-code-pprint-function obj)))) |
That makes sense. This is good context. I'm wondering if it's possible to both support the dynamic variables and use a context object and protocol (by capturing the values of the bindings at invocation time if no context object is provided)? I haven't inspect the code myself though, so that may not be possible. |
You'd probably end up with something like, which imo isn't too bad but isn't portable. (defn- default-opts []
{:print-length *print-length*
...})
(defn pprint
([object] (pprint nil object *out*)
([opt-or-object object-or-writer]
(if (instance? java.io.PrintWriter object-or-writer)
(pprint nil opt-or-object object-or-writer)
(pprint opt-or-object object-or-writer *out*)))
([opts object writer]
(let [opts (merge (default-opts) opts)]
...))) |
What do you mean by "portable"? If we still respect the values of the dynamic vars if no context object is provided, then isn't that the same as JVM Clojure (again, making some assumptions w.r.t. where those values are captured and used)? |
By portable, I mean "Does this work without using reader conditionals?" |
I am just imagining adding the non-compatible args either as the final argument in a new arity or just creating a new function that I'll take a look at some point and see if this is possible. |
Hi, I don't have much to add to @NoahTheDuke's excellent analysis and suggestions above. Personally, I'm a moderate user of I'd also like to highlight that there are some core variables that influence Thanks |
Hi,
can you please review patch to port
clojure.pprint
to Basilisp. It addresses #513The approach taken aimed at minimizing modifications to the original code. There are two commits in this PR, the first is the original code taken from
clojure.pprint
, the second has all the necessary changes I've made to make it work in Basilisp.The code spans across seven files loaded into the
pprint
namespace. I've organized them underbasilisp.contrib.pprint
to denote that this is a contributed package, rather than something we've implemented from scratch. However, I don't have a specific preference for the location of these files.Since these files are
load
'ed at runtime rather than being required or imported, they inevitably cause noticeable delays when the namespace is initially imported, in line with the constraints outlined by #878. Two potential solutions come to mind to necessitate these files at compile time:Transform them into regular namespaces that are
require
d by the primary pprint namespace, as suggested. However, I would then need to figure out a way to integrate these variables into the top-levelpprint
namespace. I'm not sure there is a superuse
like form that will not only bring them into thebasilisp.pprint
namespace but also export them as public variables from there?Merge the files into a single extensive
pprint.lpy
file.What do you think?
The
pprint
tests follow the same approach and also need to be reorganized as above.The list of changes over the original implementations are
pprint.lpy
*warn-on-reflection*
since it is not applicable in Basilisp *warn-on-reflection* support #881utilities.lpy
array-map
under a hash map (order not preserved), Sorted sets, sorted maps, array maps #416defstruct
support using records, Missing core functions/macros #375proxy
support, taken from latest draft at Proxies #425lift-ns
andstrip-ns
fn, taken from Clojure verbatim.java.io.Writer
, required by pprint.column-writer.lpy
pprint_base
*print-sort-unordered-colls*
var, to order keys inmap, useful for the testing phase.
cl_format.lpy
seq
cannot be used as a field in a record (renamed to seqn), issue whendefrecord
field names have the same names as internal method names #758fractions/Fraction
as the type equivalent forclojure.lang.Ratio
num
fn (boxing numbers in java):params-keys
entry to store the order of the mockarray-map
.dispatch.lpy
*print-sort-unordered-colls*
var, so that prinout map output is predictable for testingagent
print out support, Agents #413clojure.lang.IPending
print out support (not sure what that is).isArray
support (not sure if this is relevant/supported?)basilisp.lang.interfaces/PersistentQueue
dispatch method, since it is not availableprint_table.lpy
tests
`test_helper.lpy
platform-newlines
test_cl_format.lpy
pr
to print out characters and thus are output as strings rather than characters.Thanks