Anyone spent time with Kawa Scheme?
I've recently come across Kawa Scheme and am very intrigued by it. It's Java integration is superb like Clojure and it's very fast. Has anyone here used it to build something? So far I've only tried it with small toy programs. Things I like about it: - Starts up very quickly - Java method notation lends itself to auto-complete (instance:method param1 param2) - Can pre-compile and use it on Android - Repl has line numbers so compilation errors on repl forms have source lines Maybe Kawa fits into a niche that Clojure leaves open with its heavier runtime? Maybe I'm just trying toy programs and those toy programs are fast? :-) One thing that intrigues me here though since java integration is so easy with Kawa is the notion of using Clojure's immutable data structures from Kawa -- maybe even making a clojure "core" library for use from Kawa. -lc -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Anyone spent time with Kawa Scheme?
Thank you for posting these video links along with the time markers. I thought I'd enjoyed all of Rich Hickey's presentations before but I actually hadn't seen his "Clojure for Lisp Programmers". Clojure is the only lisp I "know" (still relatively a beginner) but have been fortunate enough to use full-time for the last few years -- given my Java background, I naturally had started with his "Clojure for Java Programmers". I did not intend to suggest that Clojure should have been a library to a Scheme or Common Lisp. I love the language as it is and not having a prior lisp background, absolutely appreciated watching the "Clojure for Lisp Programmers" (as now having some lisp experience, I could more fully appreciate some of Clojure's roots). I've dabbled with toy programs in both ABCL/SBCL as well as Kawa mostly out of curiosity. My reasons for asking my questions about other people's use of Kawa is that the performance characteristics of its runtime made me think maybe it may be applicable to some areas where Clojure may be a tougher choice (Android, CLI utilities). I think Clojure startup time correlates with how many vars defined, and startup time of my projects increases with var counts. I'm curious if any more thought has gone into this topic on the wiki: https://dev.clojure.org/pages/viewpage.action?pageId=950293. I can't give up writing software in an immutable/functional style after using Clojure for a couple of years, and was starting to think about what a program using Kawa could look like using Clojure's immutable data structures and STM. What I've settled into doing for using Clojure for CLI utilities thus far has been to just leave an instance running a socket repl on my machine always running and connect to it via rlwrap and socat (only using it interactively though): rlwrap socat STDIN TCP4:localhost: Anyhow, thanks again for the video link, always a treat to watch a Rich Hickey Clojure talk that I hadn't seen before. ‐‐‐ Original Message ‐‐‐ On April 4, 2018 3:23 AM, 'André' via Clojure wrote: > They maybe relevant too: > > https://www.youtube.com/watch?v=2V1FtfBDsLU, around 1h4min > > On 04/03/2018 05:29 PM, 'André' via Clojure wrote: > >> Rich has covered some of the motivation of why not extending existing >> Lisp->Java integrations, like Kawa and ABCL: >> >> https://www.youtube.com/watch?v=cPNkH-7PRTk, around 3:25 >> >> On 04/02/2018 05:53 PM, 'somewhat-functional-programmer' via Clojure wrote: >> >>> I've recently come across Kawa Scheme and am very intrigued by it. It's >>> Java integration is superb like Clojure and it's very fast. Has anyone >>> here used it to build something? >>> >>> So far I've only tried it with small toy programs. Things I like about it: >>> - Starts up very quickly >>> - Java method notation lends itself to auto-complete >>> (instance:method param1 param2) >>> - Can pre-compile and use it on Android >>> - Repl has line numbers so compilation errors on repl forms have source >>> lines >>> >>> Maybe Kawa fits into a niche that Clojure leaves open with its heavier >>> runtime? Maybe I'm just trying toy programs and those toy programs are >>> fast? :-) >>> >>> One thing that intrigues me here though since java integration is so easy >>> with Kawa is the notion of using Clojure's immutable data structures from >>> Kawa -- maybe even making a clojure "core" library for use from Kawa. >>> >>> -lc >>> >>> -- >>> 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 >>> --- >>> You received this message because you are subscribed to the Google Groups >>> "Clojure" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to clojure+unsubscr...@googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send
Re: Anyone spent time with Kawa Scheme?
Appreciate the response -- grench looks like a great way for me to continue to use my always-on repl in actual scripts and not just interactively. I've lately ironically become more interested in Clojure startup time now than when I started developing with it because I'm starting to accumulate enough valuable snippets of code that I'd love to expose functions here and there from the command line. What I'd started to move towards was interactively using the Clojure repl as more of a command shell than I'd ever had before (not just as a development support/workflow). Grench looks perfect for driving things from bash/cron. Also could be cool to deploy it with server side apps for O&M functionality -- peer into a running web app for instance and print out metrics for instance... ‐‐‐ Original Message ‐‐‐ On April 4, 2018 10:43 AM, Gary Trakhman wrote: > If you're looking for fast CLI utilities, ocaml can be a good fit, or > grenchman for loading clojure code, in this particular case (written in > ocaml): https://github.com/technomancy/grenchman > > You don't really need persistent data structures for those use-cases, do you? > But it does have seqs and async pipes (like channels) etc. My employer uses > Jane St's core/async libs which bundle all that in a semi-coherent fashion. > > Any of those options might be a tradeoff for mindshare and cases covered, but > common lisp might also be a good choice. > > On Wed, Apr 4, 2018 at 12:35 AM 'somewhat-functional-programmer' via Clojure > wrote: > >> Thank you for posting these video links along with the time markers. I >> thought I'd enjoyed all of Rich Hickey's presentations before but I actually >> hadn't seen his "Clojure for Lisp Programmers". Clojure is the only lisp I >> "know" (still relatively a beginner) but have been fortunate enough to use >> full-time for the last few years -- given my Java background, I naturally >> had started with his "Clojure for Java Programmers". >> >> I did not intend to suggest that Clojure should have been a library to a >> Scheme or Common Lisp. I love the language as it is and not having a prior >> lisp background, absolutely appreciated watching the "Clojure for Lisp >> Programmers" (as now having some lisp experience, I could more fully >> appreciate some of Clojure's roots). I've dabbled with toy programs in both >> ABCL/SBCL as well as Kawa mostly out of curiosity. >> >> My reasons for asking my questions about other people's use of Kawa is that >> the performance characteristics of its runtime made me think maybe it may be >> applicable to some areas where Clojure may be a tougher choice (Android, CLI >> utilities). I think Clojure startup time correlates with how many vars >> defined, and startup time of my projects increases with var counts. I'm >> curious if any more thought has gone into this topic on the wiki: >> https://dev.clojure.org/pages/viewpage.action?pageId=950293. >> >> I can't give up writing software in an immutable/functional style after >> using Clojure for a couple of years, and was starting to think about what a >> program using Kawa could look like using Clojure's immutable data structures >> and STM. >> >> What I've settled into doing for using Clojure for CLI utilities thus far >> has been to just leave an instance running a socket repl on my machine >> always running and connect to it via rlwrap and socat (only using it >> interactively though): >> >> rlwrap socat STDIN TCP4:localhost: >> >> Anyhow, thanks again for the video link, always a treat to watch a Rich >> Hickey Clojure talk that I hadn't seen before. >> >> ‐‐‐ Original Message ‐‐‐ >> On April 4, 2018 3:23 AM, 'André' via Clojure >> wrote: >> >>> They maybe relevant too: >>> >>> https://www.youtube.com/watch?v=2V1FtfBDsLU, around 1h4min >>> >>> On 04/03/2018 05:29 PM, 'André' via Clojure wrote: >>> >>>> Rich has covered some of the motivation of why not extending existing >>>> Lisp->Java integrations, like Kawa and ABCL: >>>> >>>> https://www.youtube.com/watch?v=cPNkH-7PRTk, around 3:25 >>>> >>>> On 04/02/2018 05:53 PM, 'somewhat-functional-programmer' via Clojure wrote: >>>> >>>>> I've recently come across Kawa Scheme and am very intrigued by it. It's >>>>> Java integration is superb like Clojure and it's very fast. H
Re: Anyone spent time with Kawa Scheme?
Appreciate the pointer towards Lumo and Planck -- I've tried Lumo though not Planck. I have used Clojurescript at work (not for scripting but for webapps) and it's been more challenging for me only because I am not as familiar with the Javascript ecosystem as I am the Java ecosystem. What I've been hoping to do though is leverage a lot of the JVM Clojure code I've written in small CLI utilities. I find that the library overlap between my Clojure and Clojurescript code in my usage is mainly of the plumbing/infrastructure variety (which is most useful) -- like EDN/transit/Sente/Timbre/Specter rather than the meat of what my apps are actually doing server-side. As I write this it's dawning on me I could just expose my JVM Clojure code as services and figure out how to use Clojurescript from node.js... it just sounds so much more complicated to me at the moment than something like the previously mentioned grench or even just interactive repl use (for simply exposing a function that say translates CSV data to something else) (and annoying if I'm trying to specify a local file reference etc). I've been fairly content with my own interactive repl use for these things (convert this CSV file etc), but I don't think it translates to non-clojure developers and when I hand over instructions/procedures to folks I work with I'd like to give them something simple they can run from bash etc. That's really where a lot of the startup costs are killer, you give something with a 10-20 second startup time over to other teams and it only justifies their hatred of the JVM (I'd never tell them it was Clojure then the cat would be out of the bag :-)). Anyhow I appreciate the response -- thanks! ‐‐‐ Original Message ‐‐‐ On April 4, 2018 5:48 PM, Gary Johnson wrote: > If you haven't given it a try yet, Clojurescript is really the goto for a lot > of Clojure programmers when it comes to cover the CLI and Android use cases. > > Lumo and Planck are awesome Clojurescript runtimes that start up virtually > instantaneously and make great choices for writing scripts. > > Clojurescript + React Native can create apps for Android, iOS and Windows. > > Have fun and happy hacking! > Gary > > -- > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Anyone spent time with Kawa Scheme?
Thanks -- I had seen some Clojure startup benchmarks in relation to Java 9: https://mjg123.github.io/2017/10/04/AppCDS-and-Clojure.html. I did try these on one of my projects that uses a lot of Clojure library deps and I went from ~11 second startup to ~5 (both were AOT/direct linking compiled). I appreciate the discussion. I think it's helped me think a little more clearly about what my goals/requirements are. I started thinking about why I've chosen to use any JVM language over just plain Java. After all, no JVM language is going to execute faster or have more support behind it than Java itself. I won't enumerate all the reasons writing Java code is more painful than code as the reasons are mostly personal per developer, and I'm guessing that most people here in this particular forum have already come to the same conclusion. I'd love to know why people here have chosen Clojure. Everyone chooses it for persistent data structures and functional programming, as Clojure essentially forces you to use them. I've found structuring my code that way seems less prone to bugs and more reusable and compose-able. However, with Java now having lambda functions it's possible to get *some* of the same advantages there. For me the selling point of Clojure was the learning a lisp. My motivation for wanting to learn a lisp, and the fact that Clojure was so perfectly practical I could potentially use it professionally (JVM!) started me down the path. Where I hoped I would end up is leveraging macros. I've always done a lot of code generation in my Java projects... from things like using templating languages to generate java source files to using annotations to generate additional java code at compile time. What I've found with Clojure and macros is -- it's so much easier to do those same things. I know there's a huge emphasis in the Clojure community (and maybe all lisps) of not over-using macros... and I'm not disagreeing with that. But to me that's the heart of why I would ever use a lisp. So finally full circle (back to Kawa)... *my* primary benefit of Clojure could be summarized as "JVM + Macros" (which to me is orthogonal to the immutable/functional benefit - as it is possible to program this way in other languages, and I'd argue writing in Clojure/ usually limits projects to small teams of experts and on those types of teams it would be possible to be disciplined enough to do so in a language that doesn't force it). Kawa has "JVM + Macros" (though at the moment I find scheme macros much less approachable than CL or Clojure macros). It also has different development trade-offs, but the things I like: - Little to no overhead over plain Java - I think this would make it sell-able in the enterprise world for *libraries* or *part* of a project. Could a couple of experts using Kawa replace a lot of the code I used to generate in far more awful ways than macros (templates or annotation processors)? If Kawa easily compiles to Java and has good code completion (i.e., not IFn passing Objects but actual static method definitions with types)... I bet "regular" Java-based software projects wouldn't mind consuming libraries written in Kawa. And if there wasn't a 10-20 second startup penalty for using the library... (even though I know, in "situated" programs this really doesn't matter at all -- but it does from a language adoption standpoint. I think I couldn't convince a project to let me write a library in Clojure if it took 20 seconds to load the library). - Still has macros and sexps - I prefer Clojure's syntax to scheme (maybe just because I'm used to it). But it's really the same argument people have against using Clojure (parenthesis :-)). Other low overhead JVM languages like Scala don't have macros. - I could still use Clojure's data structures and even STM from Kawa - Clojure's runtime is very approachable and a beautiful piece of software (I don't even mind the Java source formatting -- reminds of C# actually -- why indent *everything* when the language says you must have a top level "form" (namespace in C# / class in Java? :-)). Using its data structures and even STM would be very straightforward. My motivations in writing here is to get people's feedback about using Kawa / other lisps when their main motivation is to stay in the JVM ecosystem. I'd love to see both Kawa and Clojure be so easy to intertwine into a larger Java project that they could be used even within large enterprise-y Java projects (for some portion of the project). My interest in that is mostly personal :-). I think using them in this manner would be a real benefit to both those projects and to developers on them. That's what gets me excited about Kawa -- I think I maybe I could sell it's use as a library in a large corporate project simply because there's no runtime overhead. ‐‐‐ Original Message ‐‐‐ On April 5, 2018 4:00 AM,
Prototype code for enhanced CIDER code completion for Java methods
I'd like to share an idea and prototype code for better Java code completion in CIDER. While my main development environment is CIDER, the small modifications I made to support this idea were both to cider-nrepl and compliment -- which are both used by other Clojure tooling besides CIDER -- so maybe this is immediately more widely applicable. In an effort to make it easier on the tooling, I'm using a slightly different syntax for calling Java methods. My inspiration is Kawa scheme, and the notation is very similar: (String:charAt "my-string" 0) => \m (Integer:parseInt "12") => 12 (possibly.fully.qualified.YourClassName:method this args) For this syntax to be properly compiled of course it needs to be wrapped in a macro: One form: (jvm (String:charAt "my-string" 0)) Any number of forms: (jvm (lots of code) (JavaClass:method ...) (more code) (AnotherJavaClass:method ...)) The jvm macro will transform any symbol it finds in the calling position of a list that follows the ClassName:method convention. I was thinking maybe of limiting it to just a particular namespace to absolutely prevent any name collisions with real clojure functions, something like: (jvm/String:charAt "my-string" 0) This will also work with the one-off test code I'm including here for folks to see what they think. I actually like the syntax (though I wish I didn't have to wrap it in a jvm macro -- though if this actually idea was worth fully implementing, I'd imagine having new let or function macros so you don't even have to sprinkle "jvm" macros in code much at all). There is one additional advantages to this style of Java interop besides the far better code completion: - The jvm macro uses reflection to find the appropriate method at compile time, and as such, you get a compile error if the method cannot be found. - This is a downside if you *want* reflection, but this of course doesn't preclude using the normal (.method obj args) notation. You could even use this style for syntactic sugar for Java method handles: - Though not implemented in my toy code here, you could also pass String:charAt as a clojure function -- assuming there were no overloads of the same arity. So, I'm hoping you will try this out. Two things to copy/paste -- one is a boot command, the other is the 100-200 lines of clojure that implements a prototype of this. This command pulls the necessary dependencies as well as starts up the rebel-readline repl (which is fantastic tool, and it also uses compliment for code completion): # Run this somewhere where you can make an empty source directory, # something fails in boot-tools-deps if you don't have one # (much appreciate boot-tools-deps -- as cider-nrepl really needs to #be a git dep for my purpose here since it's run through mranderson for its normal distro) mkdir src && \ boot -d seancorfield/boot-tools-deps:0.4.6 \ -d compliment:0.3.6 -d cider/orchard:0.3.1 \ -d com.rpl/specter:1.1.1 -d com.taoensso/timbre:4.10.0 \ -d com.bhauman/rebel-readline:0.1.4 \ -d nrepl/nrepl:0.4.5 \ deps --config-data \ '{:deps {cider/cider-nrepl {:git/url "https://github.com/clojure-emacs/cider-nrepl.git"; :sha "b2c0b920d762fdac2f8210805df2055af63f2eb1"}}}' \ call -f rebel-readline.main/-main Paste the following code into the repl: (require 'cider.nrepl.middleware.info) (ns java-interop.core (:require [taoensso.timbre :as timbre :refer [log trace debug info warn error fatal report logf tracef debugf infof warnf errorf fatalf reportf spy get-env]] [clojure.reflect :as reflect] [clojure.string :as s :refer [includes?]] [com.rpl.specter :as sp] [orchard.java :as java])) (defn specific-class-member? [prefix] ;; NOTE: get a proper java class identifier here (when-let [prefix (if (symbol? prefix) (name prefix) prefix)] (and (not (.startsWith prefix ":")) (not (includes? prefix "::")) (includes? prefix ":" (def select-j-path (sp/recursive-path [] p (sp/cond-path #(and (seq? %) (specific-class-member? (first %))) [(sp/continue-then-stay sp/ALL-WITH-META p)] map? (sp/multi-path [sp/MAP-KEYS p] [sp/MAP-VALS p]) vector? [sp/ALL-WITH-META p] seq? [sp/ALL-WITH-META p]))) (defmacro j [[s & [obj & args]]] ;; FIXME: Add better error checking later ;; FIXME: Java fields can have the same name as a method (let [[clazz-str method-or-field & too-many-semis] (.split (name s) ":") method-or-field-sym (symbol method-or-field) clazz-sym (symbol clazz-str)] (if-let [{:keys [flags return-type]} (first (filter #(= (:name %) method-or-field-sym) (:members (reflect/reflect
Re: Prototype code for enhanced CIDER code completion for Java methods
I apologize for diving into a solution in my first email -- let me give a little more of the background as to what I am trying to accomplish. I'm proposing an additional syntax for Java interop for the purpose of allowing support for more precise code-completion of Java fields and methods in Clojure tooling. The new syntax proposal is why I'm emailing this list rather than directly going to the project owners of the projects I've modified to support this. If there is high resistance to any additional syntax for Java interop, there's not much reason to try to convince the project owners of cider-nrepl and compliment to support something just for my personal use :-). Note also that when I say "propose additional syntax" I do not mean "please add this to clojure lang" -- I've implemented this as a couple of macros which should be the way the language normally gets extended. I just want feedback and am trying to gauge interest, because if no one wants this then it's not worth any of the additional effort to "publish" it -- I'll just manage it as a utility library for myself. So when I say more precise code completion for Java fields and methods, I mean this: - I want my development environment or REPL to know the type of the Java object I'm operating on so it can limit the completion list to fields or methods that are valid for that particular type. - For example, when typing: (.get I'd somehow like my environment to know that I want code completion for a Java object of type "this.is.AType" and as such, I would only see methods or fields starting with ".get" for that type What happens for me now, is I see some Java methods and fields starting with ".get" but on a number of Java objects (and not a complete list at that). (I believe the tooling looks through symbols in your namespace, finds Java symbols, and starts pulling methods and fields from any of them). Using only the text "(.get" the environment cannot know what I'm trying to do. Now the tooling could do static code analysis, it could look at the surrounding top-level form, and say, what are the locals, are they type-hinted, and only show me Java methods and fields from locals that have type hints. Even this approach though, which is complex and error prone to implement, still doesn't limit my list to just methods and fields of "this.is.AType" unless I only have one type-hinted local symbol. So... if we had a syntax that looked like: (Type:method obj? args) My tooling becomes drastically simpler. Now my tooling is fed: "Type:method" And code completion simply becomes: - Look up Type in my active namespace symbols (to find out if it's a Java type I've imported) (or it could simply be fully qualified, both are supported) - Use reflection to find a list of candidate fields and methods No static analysis required, simple to implement. It's so simple to implement that I hastily pasted in my proof-of-concept/prototype code in the first message -- which hopefully is easy for folks to just try. I hope that people will try it and think: this would be great if I were writing a lot of Java interop code -- or better yet, give suggestions on how to improve it. So try this by: 1) Install boot (or update it via "boot -u") 2) Make a new temp directory and navigate to it 3) Run the first command from my prior email in bash 4) Paste in the code snippet to the resulting rebel-readline repl 5) Try the limited completion right in rebel-readline 6) Connect using your cider-nrepl based tooling (CIDER, inf-clojure, vim-fireplace, others?), and try it from one of those tools. I've only tested with CIDER -- in my CIDER I get eldoc, help at symbol at point (I wish this displayed javadoc inline), and better code completion. 7) Feedback! :-) I also realize that this stuff is complex enough that there might be some set of CIDER settings that solve this problem that I just simply don't know about or didn't find. Love to hear about how others get better Java interop code completion. Some of my clojure projects involve lots of Java interop and this would have been so nice to have while writing those projects (in my opinion). I think there are other advantages to this style syntax (besides supporting code completion): - Right now I have the jvm macro throw an error if it can't find the java symbol -- so you would get a compile time error rather than just a reflection warning about a non-existent java method. - In addition to making easier to *write* Java interop, I think it makes it easier to *read* Java interop I immediately know the Java type while reading the code, no need to hunt down the type annotations elsewhere. I've been writing Java since Java 1.1 and I still like the reminder of what class a method is from. ‐‐‐ Original Message ‐‐‐ On Tuesday, October 16, 2018 4:23 PM, Timothy Baldridge wrote: > I don't understand why this is needed. Why can't ci
Re: Prototype code for enhanced CIDER code completion for Java methods
Comments inline... ‐‐‐ Original Message ‐‐‐ On Tuesday, October 16, 2018 3:47 PM, 'Tatu Tarvainen' via Clojure wrote: > Nice. I like the syntax, I'll try it out. Thanks -- let me know if the boot command doesn't work... I had to update boot on one of my boxes to get it to work ("boot -u" -- to 2.8.2 I think). > But it seems unlikely to me that the interop forms would be changed in core > at this late stage. I agree -- I probably should have worded "propose new syntax" differently -- this was never intended to be a candidate for clojure lang -- it was always intended to be a macro similar to the prototype code I put in my last message. > As metadata tags can be added to symbols, could we write (^String .charAt > "test-string" 0) > It doesn't look as nice as your proposed syntax, but is possible without > modifications. Interesting -- I don't believe I'd get the full "(^String .prefix" in the place in the compliment library where I made my addition (as the "prefix") -- but I would get the "context" (from some but potentially not all clojure tooling) -- the context being the surrounding top-level form which would include the "^String" -- so in theory it would be possible for some clojure tooling to use this to accomplish the same thing. I think it would look odd for those places where you still had to type hint to avoid reflection: (defn avoid-reflection-warning-by-doing-this [a] (^InputStream .read ^InputStream a)) (The macro on the other hand automatically adds the type hint to avoid reflection) > perjantai 12. lokakuuta 2018 3.22.37 UTC+3 somewhat-functional-programmer > kirjoitti: > >> I'd like to share an idea and prototype code for better Java code completion >> in CIDER. While my main development environment is CIDER, the small >> modifications I made to support this idea were both to cider-nrepl and >> compliment -- which are both used by other Clojure tooling besides CIDER -- >> so maybe this is immediately more widely applicable. >> >> In an effort to make it easier on the tooling, I'm using a slightly >> different syntax for calling Java methods. My inspiration is Kawa scheme, >> and the notation is very similar: >> >> (String:charAt "my-string" 0) => \m >> (Integer:parseInt "12") => 12 >> (possibly.fully.qualified.YourClassName:method this args) >> >> For this syntax to be properly compiled of course it needs to be wrapped in >> a macro: >> >> One form: >> (jvm (String:charAt "my-string" 0)) >> >> Any number of forms: >> (jvm >> (lots of code) >> (JavaClass:method ...) >> (more code) >> (AnotherJavaClass:method ...)) >> >> The jvm macro will transform any symbol it finds in the calling position of >> a list that follows the ClassName:method convention. I was thinking maybe >> of limiting it to just a particular namespace to absolutely prevent any name >> collisions with real clojure functions, something like: >> >> (jvm/String:charAt "my-string" 0) >> >> This will also work with the one-off test code I'm including here for folks >> to see what they think. >> >> I actually like the syntax (though I wish I didn't have to wrap it in a jvm >> macro -- though if this actually idea was worth fully implementing, I'd >> imagine having new let or function macros so you don't even have to sprinkle >> "jvm" macros in code much at all). >> >> There is one additional advantages to this style of Java interop besides the >> far better code completion: >> - The jvm macro uses reflection to find the appropriate method at compile >> time, and as such, you get a compile error if the method cannot be found. >> - This is a downside if you *want* reflection, but this of course >> doesn't preclude using the normal (.method obj args) notation. >> >> You could even use this style for syntactic sugar for Java method handles: >> - Though not implemented in my toy code here, you could also pass >> String:charAt as a clojure function -- assuming there were no overloads of >> the same arity. >> >> So, I'm hoping you will try this out. Two things to copy/paste -- one is a >> boot command, the other is the 100-200 lines of clojure that implements a >> prototype of this. >> >> This command pulls the necessary dependencies as well as starts up the >> rebel-readline repl (which is fantastic tool, and it also uses compliment >> for code completion): >> >> # Run this somewhere where you can make an empty source directory, >> # something fails in boot-tools-deps if you don't have one >> # (much appreciate boot-tools-deps -- as cider-nrepl really needs to >> #be a git dep for my purpose here since it's run through mranderson for >> its normal distro) >> mkdir src && \ >> boot -d seancorfield/boot-tools-deps:0.4.6 \ >> -d compliment:0.3.6 -d cider/orchard:0.3.1 \ >> -d com.rpl/specter:1.1.1 -d com.taoensso/timbre:4.10.0 \ >> -d com.bhauman/rebel-readline:0.1.4 \ >> -d nrepl/nrepl:0.4.5 \ >> deps --config-data \ >> '{:dep
Re: Prototype code for enhanced CIDER code completion for Java methods
Comments inline... I really appreciate you taking the time to look at this. I think I am still imprecise in my language -- I hope the comments below doesn't come across as too tedious :-)... ‐‐‐ Original Message ‐‐‐ On Tuesday, October 16, 2018 7:46 PM, Timothy Baldridge wrote: > As you say, this is a limitation in the code completer. In Cursive this > problem doesn't exist to this extent, when I type `(.get` the completer > responds with a list of methods and classes that could be completed to that > method, starting with classes in the namespace I'm currently editing. I think we are saying the same thing here. I believe compliment (the library CIDER/other clojure tooling uses for code completion) does what we are describing (showing Java methods and fields from multiple Java types that are imported into the namespace currently being edited (or type hinted in locals/function definitions). My point is I want more -- I want the completion list to only include methods and fields from the type I as a developer know that I have. Like a Java IDE: MyType a = new MyType(); Now typing "a." yields just completions valid for MyType, and not 5 other types I've used nearby. > Yes, this takes static analysis, or perhaps some indexing and introspection. > But changing the syntax is never really going to gain traction here, as > manually typing the name of every method just so my editor can produce a list > seems like me conforming to my tool rather than my tool learning to work with > me. Just to make sure I'm completely clear -- I'm *not* advocating a change to clojure lang -- only proposing a macro/library. The prototype macro I wrote simply transforms the (Type:method ...) syntax into the (. instance-expr member-symbol) that (.method ...) macroexpands into anyhow. This is not intended to replace (.method obj args) notation. I'm not sure what you mean by "manually typing the name of every method just so my editor can produce a list". The way this works is, you type "(MyType:" and get presented with a list of completions that are *only* applicable to MyType -- there's no manually typing lists of methods and fields anywhere. And, the way this works for me in CIDER, I type "(My" and I get "(MyType", then I add a ":", and now I get completions just for MyType -- it also shows me the Java signature of the methods as I highlight a potential completion. There's no manually seeding the list anywhere... > The imported classes in the current namespace are stored in the mappings > attribute. It seems like an editor should be able to install hooks into that > and index the methods on the classes to provide this feedback. > https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Namespace.java#L123 Yes I agree -- and I believe that's exactly what the existing tooling already does -- I just want more precision. Some of my motivation has been working with monstrously large class libraries in Java. GIS libraries in Java are notoriously class/method heavy and after importing many of these classes into a namespace, completion that cannot narrow down to the exact type I'm using for the reasons we agree on -- simply is painful to work with. > On Tue, Oct 16, 2018 at 1:26 PM 'somewhat-functional-programmer' via Clojure > wrote: > >> I apologize for diving into a solution in my first email -- let me give a >> little more of the background as to what I am trying to accomplish. >> >> I'm proposing an additional syntax for Java interop for the purpose of >> allowing support for more precise code-completion of Java fields and methods >> in Clojure tooling. The new syntax proposal is why I'm emailing this list >> rather than directly going to the project owners of the projects I've >> modified to support this. If there is high resistance to any additional >> syntax for Java interop, there's not much reason to try to convince the >> project owners of cider-nrepl and compliment to support something just for >> my personal use :-). >> >> Note also that when I say "propose additional syntax" I do not mean "please >> add this to clojure lang" -- I've implemented this as a couple of macros >> which should be the way the language normally gets extended. I just want >> feedback and am trying to gauge interest, because if no one wants this then >> it's not worth any of the additional effort to "publish" it -- I'll just >> manage it as a utility library for myself. >> >> So when I say more precise code completion for Java fields and methods, I >> mean this: >> - I want my development envir
Re: Prototype code for enhanced CIDER code completion for Java methods
I appreciate your detailed response, and you've certainly done great work with Cursive. I always recommend it to any Java programmer who is starting to learn Clojure. I will start to more seriously weigh the pros and consadditional of switching away from emacs. The cult of emacs has had a strong pull on me but your good work may mean I should leave it for Clojure work too (and not just for Java work :-)). Cursive is doing much more in trying to match the Clojure compiler than I believe the compliment library has done to date. Part of me likes the readability of the syntax: (String:charAt my-string 0) over (-> ^String my-string (.charAt 0)) But I realize that is much more subjective than anything else. I have to say, in delving into this even a little -- I appreciate the time you must have spent matching the Clojure compiler. I just remember looking at Kawa's syntax for Java method calls and thinking, wow, I wish Clojure had that -- so much more readable! I like your last example a lot: (foo .method) => getting turned into (.method foo) automatically by the editor. I've actually looked at doing a similar thing with my macro -- basically using it in my editor, and then adding an nREPL middleware to transform it to the much beloved (.method obj args) notation. Since I subjectively like the readability of (String:charAt obj 0) better than (.charAt ^String obj 0) I didn't go that route in this discussion. I'm curious though, why additional macro / slightly differences from "idiomatic" seems so important to avoid. I think something as simple as (String:charAt obj 0) notation would be pretty simple for a third syntax (since we already have two built in ways of doing it) -- and closer to the static method invocation syntax -- so really a third built-in syntax (Integer/parseInt "12"). But that's more a philosophical question I suppose :-). LISP curse anyone? :-) ‐‐‐ Original Message ‐‐‐ On Wednesday, October 17, 2018 8:40 AM, Colin Fleming wrote: > Cursive already allows this with no syntax changes, but it does require > reproducing Clojure's type inference in the editor. Cursive performs this > type inference, so (modulo bugs) it knows the types of basically everything > that the Clojure compiler does (and in fact in some situations can do better, > but I deliberately use just what the compiler knows right now). > > This is used in various ways in completion. All of the cases that Aaron > enumerates above work, since Cursive can correctly propagate the types in > threading forms/doto etc (| is the caret): > > (-> "my-string" > (.ch|)); <- Only String methods here > > (-> (new MyType) > (.|)) ; <- MyType methods here > > (def foo "hello") > > (-> ^String foo > (.to|)); <- String completions here too, because of the type hint. >;Cursive can do better here even though the Clojure > compiler doesn't. >;Currently I restrict this, but completing could e.g. > automagically insert the type hint. > > (let [foo "string"] > (-> foo (.to|)) ; <- No type hint required, since we know the type of foo > > Additionally, Cursive supports the following: > > (let [foo (ArrayList.) > iterator (.iterator foo)] > (.ne|)) ; <- Here, .next will be offered even though Iterator isn't > imported, >;because Cursive knows the types we have in scope at the > caret. > > (let [foo (ArrayList.)] > (foo .i|)) ; <- Here, I've put the receiver first, then I'm completing > the method call. >;Since Cursive knows the type of foo, only ArrayList > methods will be completed. >;When I select a completion, Cursive will swap the two > around, like: > (let [foo (ArrayList.)] > (.iterator foo|)) > > I use this last one all the time, and it basically makes Clojure completion > as good as Java completion. Someone pointed out to me that this should really > use the existing dot syntax, like: > > (let [foo (ArrayList.)] > (. foo it|)) ; <- completes to: > > (let [foo (ArrayList.)] > (.iterator foo|)) > > But I haven't implemented that yet. > > I don't do any of the more tricky stuff that IntelliJ does like transitively > searching across chained method calls based on the type, etc, but that's just > a time issue - there's nothing preventing Cursive from doing that too. Also, > offering completions from classes that are not imported but are in scope > makes a huge difference, even without any switching trickiness. > > Cheers, > Colin > > On Wed, 17 Oct 2018 at 04:34, Didier wrote: > >> How does the new syntax help the tooling figure out the type? >> >> (def var (SomeType.)) >> (.method var) >> >> Or >> >> (jvm (var.method)) >> >> I'm not sure how you narrow down to only the SomeType methods? >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clojure@googlegro
Re: Prototype code for enhanced CIDER code completion for Java methods
It's not really: (jvm (var.method)) but (jvm (JavaType:method var)) Because the completion engines get "JavaType:" as a prefix, they can look up the type via reflection and present a list of methods for *just* that type. ‐‐‐ Original Message ‐‐‐ On Wednesday, October 17, 2018 4:34 AM, Didier wrote: > How does the new syntax help the tooling figure out the type? > > (def var (SomeType.)) > (.method var) > > Or > > (jvm (var.method)) > > I'm not sure how you narrow down to only the SomeType methods? > > --- > > 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 > > > > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Prototype code for enhanced CIDER code completion for Java methods
I appreciate your thoughtful response -- I wish some of the other tooling could do this level of analysis but I can only imagine the time it took Colin to implement :-). Like I mentioned in my response to him -- I'm going to have to seriously consider leaving the cult of emacs not only for Java but maybe Clojure too :-). ‐‐‐ Original Message ‐‐‐ On Wednesday, October 17, 2018 3:56 AM, Aaron Cohen wrote: > This seems like it could be done using threading. > > (-> "my-string" >(.ch<-- completion should give you good results here, for only String > methods > > (-> (new MyType) > (.<-- completion should give you only methods of MyType > > ; One interesting case is the following: > (def foo "hello") > > ; foo's type isn't known, so would need to be hinted > (-> ^String foo > (.to <-- good completions again, because of the type hint > > I think you won't be able to get all the way to your jvm macro, but likely > pretty close, and it's much more idiomatic... > > The doto macro is also useful in a similar way, and often what you want when > using some of the more byzantine java libraries. > > (All of the above works in Cursive, I'm not sure about how it works in CIDER, > but I assume it's equivalent). > > --Aaron > > On Tue, Oct 16, 2018 at 8:30 PM 'somewhat-functional-programmer' via Clojure > wrote: > >> Comments inline... I really appreciate you taking the time to look at this. >> I think I am still imprecise in my language -- I hope the comments below >> doesn't come across as too tedious :-)... >> >> ‐‐‐ Original Message ‐‐‐ >> On Tuesday, October 16, 2018 7:46 PM, Timothy Baldridge >> wrote: >> >>> As you say, this is a limitation in the code completer. In Cursive this >>> problem doesn't exist to this extent, when I type `(.get` the completer >>> responds with a list of methods and classes that could be completed to that >>> method, starting with classes in the namespace I'm currently editing. >> >> I think we are saying the same thing here. I believe compliment (the >> library CIDER/other clojure tooling uses for code completion) does what we >> are describing (showing Java methods and fields from multiple Java types >> that are imported into the namespace currently being edited (or type hinted >> in locals/function definitions). My point is I want more -- I want the >> completion list to only include methods and fields from the type I as a >> developer know that I have. >> >> Like a Java IDE: >> MyType a = new MyType(); >> Now typing "a." yields just completions valid for MyType, and not 5 other >> types I've used nearby. >> >>> Yes, this takes static analysis, or perhaps some indexing and >>> introspection. But changing the syntax is never really going to gain >>> traction here, as manually typing the name of every method just so my >>> editor can produce a list seems like me conforming to my tool rather than >>> my tool learning to work with me. >> >> Just to make sure I'm completely clear -- I'm *not* advocating a change to >> clojure lang -- only proposing a macro/library. The prototype macro I wrote >> simply transforms the (Type:method ...) syntax into the (. instance-expr >> member-symbol) that (.method ...) macroexpands into anyhow. This is not >> intended to replace (.method obj args) notation. >> >> I'm not sure what you mean by "manually typing the name of every method just >> so my editor can produce a list". >> >> The way this works is, you type "(MyType:" and get presented with a list of >> completions that are *only* applicable to MyType -- there's no manually >> typing lists of methods and fields anywhere. And, the way this works for me >> in CIDER, I type "(My" and I get "(MyType", then I add a ":", and now I >> get completions just for MyType -- it also shows me the Java signature of >> the methods as I highlight a potential completion. There's no manually >> seeding the list anywhere... >> >>> The imported classes in the current namespace are stored in the mappings >>> attribute. It seems like an editor should be able to install hooks into >>> that and index the methods on the classes to provide this feedback. >>> https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Namespace.java#L123 >> >> Yes I agree -- and I believe that's exactly wha
Re: Prototype code for enhanced CIDER code completion for Java methods
Comments inline... I appreciate the discussion to date! ‐‐‐ Original Message ‐‐‐ On Saturday, October 20, 2018 10:13 AM, Colin Fleming wrote: >> I'm curious though, why additional macro / slightly differences from >> "idiomatic" seems so important to avoid. > > I can think of a couple of reasons off the top of my head: > > - It won't work with any tooling that's unaware of it, e.g. Cursive. I agree -- my goal here isn't to add work everywhere. I think most Cursive users probably would care less if it isn't added to Cursive, and if there was an actual demand, at least the code to implement would already be done in another library, and a trivial amount of code. One nice thing about cider-nrepl/compliment is that multiple tools use them -- I like having this code complete from rebel-readline for example, and in theory (I say this because I haven't tested it), it should work in vim-fireplace/vim-replant/etc. I like using it from a rebel-readline REPL over SSH for example -- completely outside of emacs/CIDER. I think this "style" of tooling (not my syntax -- but tooling that is always integrated/present in the clojure process) yields this type of benefit -- I can use it from wherever I run my code if I'd like, actually independent of any editor or development environment. > - It's very verbose - it's even worse than Java, because instead of > annotating each variable once where it's declared you have to annotate every > method call, and those annotations remain forever in the code, not just when > you're writing it. This is true even when the type is trivially obvious, e.g. > (String:charAt "my-string" 0).Modern languages are moving towards more > sophisticated type inference for a reason - it's much more comfortable. > > Really, this feature is just to make editors work better. Why not do > something similar to what Cursive does, and allow the user to type > (String:ch|) . Then just show the method completions from String and when the > user selects "charAt" just convert to (.charAt |)? This is really a feature > to aid code writing after all, not reading. Then the feature wouldn't require > macros at all, it could be a purely Emacs thing. I agree -- if I knew more about emacs lisp I would have gone down this route initially. However, my personal opinion is that this syntax does improve readability, at the price of additional verbosity -- a verbosity I personally don't mind while editing/writing because my editor helps me out. The syntax itself is similar to C++/Java lambda method references... Type:method. I love immediately seeing what class a method is from when looking over code where I'm unfamiliar with the Java types being used. But I agree -- this is subjective, and if I had more emacs lisp knowledge/time I would have thought much more about that route. My main goal posting here was: - Hey try this syntax out, it's helped me tremendously with Java interop in CIDER, and hopefully elicit some feedback (and I appreciate yours) I hope it's obvious from the idea of pasting code into a repl to try the feature that this isn't *done/released/supported/warrantied/whatever*, but really is the beginnings of an idea being explored. In fact, since I'm now starting to use this code more in one of my new interop-heavy projects, I've already made a couple of minor changes to it. It took me much longer to find a minimal boot command that used tools/deps/cli and a paste-able code-snippet than writing it in the first place :-). I don't see how this is related to type-inferencing at all. Type-hinting the way we do in clojure is really a type declaration -- it isn't really trying to infer that say, something is a number based on usage (say, by being a participant in the '+' function --- on the contrary, if I want smart numerical "typing", I have to ^long or ^double). Clojure simply casts/boxes to whatever the interop function expects. If you're referring to the new Java syntax of 'var x = new blah();' -- I think that's mainly a reaction to HowStill>>>>... I'd almost argue what we do in Clojure is more like gradual typing -- I start to type for performance/interop reasons (numerical computing or Java interop) but only sparingly. I don't doubt you are doing type inference in Cursive -- sounds like that's precisely how you are getting good completion lists. > On Wed, 17 Oct 2018 at 11:13, 'somewhat-functional-programmer' via Clojure > wrote: > >> I appreciate your detailed response, and you've certainly done great work >> with Cursive. I always recommend it to any Java programmer who is starting >> to learn Clojure. I wil
Re: Prototype code for enhanced CIDER code completion for Java methods
I agree :-). For me the cost/benefit decision is easy -- I'm using it in a new interop-heavy project. I posted it here in case others who used cider-nrepl based tooling may also potentially benefit -- if enough interest maybe I'd take the extra time to publish it as a library. Often times I have had small macros / functions that I imagine would be of use to others but never know how to share them. I personally have a bad reaction against pulling in a named dependency for 1 or 2 functions -- how to share such things? I bet most developers in a lisp start to have their own utility libraries. I've always imagined there would be much for me to learn by seeing those libraries from seasonsed lispers. ‐‐‐ Original Message ‐‐‐ On Friday, October 19, 2018 9:58 AM, Matching Socks wrote: > The cost/benefit is hard to work out. Look ahead 7 years - we would have the > ceremonial (jvm... (MyType:baz...)) in some places and the good old elegant > (.baz ...) in others, and the tooling will work just as well with it. On the > other hand, if you routinely do tons of interop with a wide variety of > classes whose method names are subtly distinct and mostly 40 letters or more, > then (jvm...) will seem like genius! Nonetheless, I hope your work will > inspire code completers to go the extra mile, once and for all. In the > meantime, you could wrap that dreadful interop with a library whose method > names are shorter. > > -- > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Question: How do you organize large clojure projects?
This is somewhat of a retrospective -- so please bear with me. I've had the privilege of working on a clojure project for a couple of years now, and have accumulated some 15-20k lines of clojure code. I'm taking a little time to look back over what has worked for me and what hasn't in terms of code/project organization -- and *I'd love to know what has worked for other people (or hasn't)* for similarly large projects. I knew my project was going to grow to at least as much code as it has now at the start, and my domain problem was fairly well-defined. From the very beginning I organized my code into many (15-20) different clojure 'projects' using lein. Rather than organizing code into these projects *by function area*, I found myself organizing code into projects by their *dependencies*. So any code that used libraries X,Y,Z went into a project that declared those dependencies -- even if a function made sense in a different namespace by name -- if it needed deps that I already had in another project, I moved the function to that project. For example, in the Java GIS world, if you do anything with swing components, you can easily pull in 100s of MBs of dependencies. My project involves GIS work both server-side rest-apis, but it's also nice to pull up a quick swing component showing data on a map for debugging etc. I don't have these things in the same project even though there is some library overlap because the GUI deps are just too many. I think for me on my project, the only reason to separate anything into 'projects' is for reuse based on dependencies -- i.e., to use a function/set of functions I've written again, what's the minimal amount of deps to pull in. It's worked well for me in that sense -- I'm able to create a new 'main' project, include libraries that I want from my project, and not pull in 2,000 dependencies unless I need it. The dependencies I'm mostly concerned with here are Java deps and not clojure deps. I've found a relatively small core set of clojure deps I almost always want available to me (specter, timbre, core.async) -- though even still I have a utility library project where I have a hard rule of zero dependencies (for basic macros like (ignore-exception body-forms)). I've used lein's checkouts and managed dependencies fairly successfully though I still forget to lein install everything before I lein uberjar my final delivery artifacts and end up debugging old code before realizing what happened (and my way of installing everything is a bash for loop :-)). I've found this approach somewhat tedious and have been wondering if there's a better way -- and am very curious what others do. What I've been playing around with lately is a different concept for my own code organization: - What if all my clojure code could go in one place, or one project? (Even if it ended up being 20k+ lines of code) - What if namespaces contained their required dependencies in their metadata? - What if upon namespace creation, a namespace's dependencies were automatically added to the classpath? - What if functions declared in a namespace could also declare additional dependencies? These would be added to the classpath upon first invocation of the function. This is great for my seldom used functions that need many dependencies -- code could live in the namespace that is matches its function instead of squirreled away in a project just to match its deps. I have written a basic library that does these things, and am currently trying it out on a small scale. Concerns I've already been trying to address: - Dynamically adding things to the classpath is generally considered a /bad/ thing to do. - My code reads all pom.xmls on the classpath to determine what libraries are already on the classpath -- and does not re-add libraries that are already on the classpath. I think this alone takes care of a lot of issues with dynamically adding deps to the classpath (multiple versions of libraries on the classpath). - Production deployments should not need to calculate classpaths dynamically - This technique should be able to be used whether the classpath is precomputed (i.e., for production), or dynamically during development. Example namespace loaded deps: (ns test {:dependencies 'com.taoensso/timbre "4.10.0"} (:require [taoensso.timbre :as timbre :refer [info debug error warn spy]])) -or- (ns test {:deps '{[[com.taoensso/timbre {:mvn/version "4.10.0"]]}}} (:require [taoensso.timbre :as timbre :refer [info debug error warn spy]])) Now these namespace deps would be loaded dynamically by aliasing the ns macro for development with one that loads deps dynamically. In production, the metadata is simply attached to the namespace per normal use of the ns form, no deps added dynamically. (defn-deps test-fn-deps "Test Function with optional deps" {:dependencies '[[diffit "1.0.0"]
Re: Prototype code for enhanced CIDER code completion for Java methods
Very cool! By the way, thanks for all the work you have put in to compliment. Sometimes it's hard to know when/how to thank people. I myself am all too often guilty of, "Thanks, can I have a new feature or bug fix?" You, Mr. Emerick, Mr. Batsov -- and many others -- thanks! I'd start a thanksgiving thread for clojure, but I'm afraid my list would be quite long, and sort of sound presumptuous, as if I'd accomplished something worthy of thanking the many folks whose work made it possible. So how about this -- Thanks to all the different folks in the community for sharing your work, whether I've used it or not, I've learned many things from: - Presentations by Rich Hickey - The Joy of Clojure - CIDER - Figwheel and ClojureScript - core.async, manifold, ring, sente, timbre, specter, seesaw, ... ‐‐‐ Original Message ‐‐‐ On Sunday, November 25, 2018 5:53 PM, Alexander Yakushev wrote: > To anyone who's interested in having precise completion for Java classes – a > feature like this is available in the latest CIDER snapshot: > https://twitter.com/unlog1c/status/1066748173094453248. You can get a > filtered completion by prepending a type tag to the next symbol. > > On Friday, October 12, 2018 at 3:22:37 AM UTC+3, > somewhat-functional-programmer wrote: > >> I'd like to share an idea and prototype code for better Java code completion >> in CIDER. While my main development environment is CIDER, the small >> modifications I made to support this idea were both to cider-nrepl and >> compliment -- which are both used by other Clojure tooling besides CIDER -- >> so maybe this is immediately more widely applicable. >> >> In an effort to make it easier on the tooling, I'm using a slightly >> different syntax for calling Java methods. My inspiration is Kawa scheme, >> and the notation is very similar: >> >> (String:charAt "my-string" 0) => \m >> (Integer:parseInt "12") => 12 >> (possibly.fully.qualified.YourClassName:method this args) >> >> For this syntax to be properly compiled of course it needs to be wrapped in >> a macro: >> >> One form: >> (jvm (String:charAt "my-string" 0)) >> >> Any number of forms: >> (jvm >> (lots of code) >> (JavaClass:method ...) >> (more code) >> (AnotherJavaClass:method ...)) >> >> The jvm macro will transform any symbol it finds in the calling position of >> a list that follows the ClassName:method convention. I was thinking maybe >> of limiting it to just a particular namespace to absolutely prevent any name >> collisions with real clojure functions, something like: >> >> (jvm/String:charAt "my-string" 0) >> >> This will also work with the one-off test code I'm including here for folks >> to see what they think. >> >> I actually like the syntax (though I wish I didn't have to wrap it in a jvm >> macro -- though if this actually idea was worth fully implementing, I'd >> imagine having new let or function macros so you don't even have to sprinkle >> "jvm" macros in code much at all). >> >> There is one additional advantages to this style of Java interop besides the >> far better code completion: >> - The jvm macro uses reflection to find the appropriate method at compile >> time, and as such, you get a compile error if the method cannot be found. >> - This is a downside if you *want* reflection, but this of course >> doesn't preclude using the normal (.method obj args) notation. >> >> You could even use this style for syntactic sugar for Java method handles: >> - Though not implemented in my toy code here, you could also pass >> String:charAt as a clojure function -- assuming there were no overloads of >> the same arity. >> >> So, I'm hoping you will try this out. Two things to copy/paste -- one is a >> boot command, the other is the 100-200 lines of clojure that implements a >> prototype of this. >> >> This command pulls the necessary dependencies as well as starts up the >> rebel-readline repl (which is fantastic tool, and it also uses compliment >> for code completion): >> >> # Run this somewhere where you can make an empty source directory, >> # something fails in boot-tools-deps if you don't have one >> # (much appreciate boot-tools-deps -- as cider-nrepl really needs to >> #be a git dep for my purpose here since it's run through mranderson for >> its normal distro) >> mkdir src && \ >> boot -d seancorfield/boot-tools-deps:0.4.6 \ >> -d compliment:0.3.6 -d cider/orchard:0.3.1 \ >> -d com.rpl/specter:1.1.1 -d com.taoensso/timbre:4.10.0 \ >> -d com.bhauman/rebel-readline:0.1.4 \ >> -d nrepl/nrepl:0.4.5 \ >> deps --config-data \ >> '{:deps {cider/cider-nrepl {:git/url >> "https://github.com/clojure-emacs/cider-nrepl.git"; :sha >> "b2c0b920d762fdac2f8210805df2055af63f2eb1"}}}' \ >> call -f rebel-readline.main/-main >> >> Paste the following code into the repl: >> >> (require 'cider.nrepl.middleware.info) >> >> (ns java-interop.core >> (:require >>[taoensso.timb
Re: Question: How do you organize large clojure projects?
Thank you, it does help. I almost went the monorepo route but for some reason thought I'd have one project.clj file with one giant list of dependencies. Having a monorepo but with different dependency sets makes a ton of sense and I think would have been much easier to manage. ‐‐‐ Original Message ‐‐‐ On Thursday, November 15, 2018 7:12 AM, Patrik Sundberg wrote: > I've been happy using a monorepo with boot, and a build.boot with many > building blocks that can be mixed and matched for many deployables (uberjars > in my case). > > In my build.boot I define my internal blocks, but also defs for external deps > like eg postgres and grpc. That way I have one place for these groups of > dependencies to manage, and can merge them into many of my own building > blocks in a flexible and consistent way. > > There are no checkouts, multiple outputs and consistent usage of dependencies. > > If I need different release management/deployment process for different > deployables of my own I tend to use different release branches by deployable > that my ci/CD setup triggers from. > > Hope that helps! > > - > > 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 > > > > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
1.8.0/1.9.0/1.10.0-RC1 -> 1.10.0 regression: Extending protocols with metadata / datafy combined with macros/symbols
I finally moved one of my clojure projects from 1.10.0-RC1 to 1.10.0 and encountered some very strange behaviour. Code that had previously compiled fine under 1.8.0, 1.9.0, and 1.10.0-RC1 no longer compiled under 1.10.0 with the following error: Execution error (IllegalArgumentException) at bug.core$eval7278/ (form-init3641919424619236070.clj:49). No matching ctor found for class clojure.reflect$typesym$fn__11912 Basically, symbols used inside of macros that had the new datafy protocol added to their metadata caused this failure. My use case that lead my to having this issue in the first place: - I use macros in my project to help wrap Java APIs, or convert Java objects to/from clojure data structures. - In these macros I often use clojure.reflect to aid in adding Java type tags to the code I am generating. - New in 1.10.0, the symbols you get back from clojure.reflect now contain a datafy protocol implementation in their metadata. (Note that in 1.10.0-RC1 there was no datafy protocol implementation returned in the metadata) - The strange exception above occurs when the returned symbol from clojure.reflect is used within a macro I narrowed down a minimalist test case to help illustrate what I am saying: (require 'clojure.reflect) ;; returns the symbol int, which now in 1.10.0 includes a datafy protocol implementation in the metadata of the returned symbol (defn example-reflect-type-return [] (->> java.lang.String (clojure.reflect/reflect) (:members) (filter #(= (:name %) 'length)) (first) (:return-type))) ;; this macro fails on 1.10.0, but works in 1.10.0-RC1, 1.9.0, and 1.8.0 (defmacro has-the-bug [] `{:should-have-int-val '~(example-reflect-type-return)}) ;; this macro works in 1.10.0, 1.9.0, and 1.8.0 ;; (Basically I had to manually remove the datafy protocol implementation from the symbol's metadata) (defmacro this-works [] `{:should-have-int-val '~(with-meta (example-reflect-type-return) nil)}) Works under 1.10.0, 1.9.0, and 1.8.0: (this-works) => {:should-have-int-val int} Fails /only/ under 1.10.0: (has-the-bug) Failure error: #error { :cause "No matching ctor found for class clojure.reflect$typesym$fn__11912" :via [{:type java.lang.ExceptionInInitializerError :message nil :at [jdk.internal.reflect.NativeConstructorAccessorImpl newInstance0 "NativeConstructorAccessorImpl.java" -2]} {:type java.lang.IllegalArgumentException :message "No matching ctor found for class clojure.reflect$typesym$fn__11912" :at [clojure.lang.Reflector invokeConstructor "Reflector.java" 288]}] :trace [[clojure.lang.Reflector invokeConstructor "Reflector.java" 288] [clojure.lang.LispReader$EvalReader invoke "LispReader.java" 1317] [clojure.lang.LispReader$DispatchReader invoke "LispReader.java" 853] [clojure.lang.LispReader read "LispReader.java" 285] [clojure.lang.LispReader read "LispReader.java" 216] [clojure.lang.LispReader read "LispReader.java" 205] [clojure.lang.RT readString "RT.java" 1874] [clojure.lang.RT readString "RT.java" 1869] [bug.core$eval7278 "form-init3641919424619236070.clj" 49] [jdk.internal.reflect.NativeConstructorAccessorImpl newInstance0 "NativeConstructorAccessorImpl.java" -2] [jdk.internal.reflect.NativeConstructorAccessorImpl newInstance "NativeConstructorAccessorImpl.java" 62] [jdk.internal.reflect.DelegatingConstructorAccessorImpl newInstance "DelegatingConstructorAccessorImpl.java" 45] [java.lang.reflect.Constructor newInstance "Constructor.java" 488] [java.lang.Class newInstance "Class.java" 560] [clojure.lang.Compiler$ObjExpr eval "Compiler.java" 4996] [clojure.lang.Compiler eval "Compiler.java" 7175] [clojure.lang.Compiler eval "Compiler.java" 7131] [clojure.core$eval invokeStatic "core.clj" 3214] [clojure.core$eval invoke "core.clj" 3210] [clojure.main$repl$read_eval_print__9068$fn__9071 invoke "main.clj" 414] [clojure.main$repl$read_eval_print__9068 invoke "main.clj" 414] [clojure.main$repl$fn__9077 invoke "main.clj" 435] [clojure.main$repl invokeStatic "main.clj" 435] [clojure.main$repl doInvoke "main.clj" 345] [clojure.lang.RestFn invoke "RestFn.java" 1523] [clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__1115 invoke "interruptible_eval.clj" 87] [clojure.lang.AFn applyToHelper "AFn.java" 152] [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic "core.clj" 665] [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1973] [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1973] [clojure.lang.RestFn invoke "RestFn.java" 425] [clojure.tools.nrepl.middleware.interruptible_eval$evaluate invokeStatic "interruptible_eval.clj" 85] [clojure.tools.nrepl.middleware.interruptible_eval$evaluate invoke "interruptible_eval.clj" 55] [clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__1160$fn__1163 invoke "interruptible_eval.clj" 222
Re: Keys spec with :additional-keys boolean option
I assume you are forced to use XML (if you are choosing the format, I wholeheartedly recommend EDN!). If you /do/ control the choice of XML/EDN but want to interoperate with other languages, check out: https://github.com/edn-format/edn/wiki/Implementations - maybe you could use EDN anyhow if you have forgiving consumers (hat tip to Alex Miller who pointed this page out again recently). If you must use XML, have you considered the approach of using a generic XML data structure (which would by definition have the in-memory definition mirror the serialized version)? You could write a transform function to turn it into something you'd rather use from clojure, or simply define accessor functions into your data. I've used data.xml (https://github.com/clojure/data.xml) before along with specter (https://github.com/nathanmarz/specter) to transform/modify/access XML data. Though I have to admit, every time I do, I curse immutable data structures -- they are unwieldy for /modifying/ highly nested structures (XML!). Specter is the best library I've seen for modifying deeply nested structures, and is worth the learning curve (you'll use it everywhere once you get used to it -- it's really fantastic), but still isn't a perfect fit for XML. Here's an example of something simpler I wrote to read out the bits of maven pom files that I cared about: (defn collapse-xml "Collapses xml data in the form from clojure.data.xml (:tag :t :content [\"some whitespace\" {:tag :another-element ...}]) into {:t {:another-element \"value\"}} This works well for many configuration style xml files, but you will lose all textual content surrounding elements. For example: This is some bold text. Is a terrible use case for this, as it will return {:p {:bold \"text\"}} This does work very well for pom files however." [m {:keys [tag content]}] (assoc m tag (if (every? string? content) (let [s (clojure.string/join content)] (if (clojure.string/blank? s) nil s)) (reduce collapse-xml {} (filter map? content) If you are using mainly "configuration" style small XML files like maven pom files, something simple like this could give you an ergonomic /accessor/ clojure data structure (not one suitable for editing and transforming back to an on-disk representation though). Every time I have to use XML from clojure I have yet to find a solution that feels clean. I yearn for xpath and a mutable API (maybe just using a good set of Java APIs via interop is really the best answer here). Given that I can't find a clean solution for XML in clojure, I find the idea of trying to use clojure.spec for validation purposes for XML data even more difficult to imagine than if the serialized representation were simply EDN to begin with. In fact, I think that's the only time I've gotten any value out of clojure.spec in my own projects -- I've used it for verifying serialized EDN and found its validation error message output useful (though /so/ verbose for large specs!). I relentlessly spec'd out my projects' data structures in the beginning when spec was released (I started my clojure journey when 1.9 was in alpha and spec just released), not even looking at plumatic schema or other alternatives since clojure.spec was going to be built into core. However, what I ended up with was pages of attribute specs which mostly looked like int?, or string?, or keyword?, or map key lists (though some regexes and ranges!). From the reader's perspective it was tough to see what the data was actually going to /look/ like. And then, where to actually use the specs? Runtime performance was too slow to use everywhere... My most egregious use of spec was in multimethods or cond forms, essentially trying to dispatch on the /type/ of a map (not knowing in advance what I would get). Needless to say I have stopped using spec as I couldn't manage to figure out a way forward for me where its benefits outweighed its costs. I kept trying to use it as a type system, which I think it is ill-suited for (and even if it were suited to it -- it's too slow to use as such). I have since settled on using truss, a wonderful little library (https://github.com/ptaoussanis/truss) and have never looked back. I highly recommend looking at it -- you get great error messages for essentially run-time type assertions only where you need them (or are currently debugging). That plus typical spy-like macros go a long way (see another great library by same author as truss, timbre (https://github.com/ptaoussanis/timbre) which includes a nice spy macro). I made one that defs the value being spied in the current namespace if an optional condition is met on the data value. I had high hopes I would grok clojure.spec enough to get more value out of it than time I put into it. But as of now, simpler solutions have served me far better. ‐‐‐ Original Message ‐‐‐ On Monday
Re: No matching field found: length for class byte array
These are so old, but I (still) often find them laugh-out-loud amusing :-) https://despair.com/products/apathy No offense is meant :-). This next one is an apt description of me when I was super-obsessed with clojure startup time: https://despair.com/collections/retired/products/stupidity I'm too old for development! I fit into the cranky clojure developer demographic Mr. Hickey discussed in his 10 years of clojure talk. But every once in a while it's good to laugh at perceptions, regardless of however close they are to reality :-). ‐‐‐ Original Message ‐‐‐ On Monday, March 18, 2019 10:38 AM, Matching Socks wrote: > That suggestion of a more humane and helpful error message (", use alength > function for array length") is [Jira ticket > 1448](https://dev.clojure.org/jira/browse/CLJ-1448). > > Back in 2014, it got closed as "declined". But that was before the recent > growth of interest in usable error messages. The proposed mitigation looks > like it would hit the nail on the head. Its only apparent run-time cost > would be on the error path. One nit: this patch may be step down a slippery > slope leading to a more helpful message concerning yet another fake field, > Class.class. (Are there any more?) > > Seems like a clear-cut, useful case to me. Alex, could issue 1448 be > reopened? > > -- > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.