Re: Closure for object pattern? A good idea?
Logan's point about being able to add new functions on a stopwatch is valid. That's often the argument to why protocols are better then classic OO. Though I still feel like in some scenarios, I think this is a good pattern, and can serve us better, the stopwatch being one good example. Nothing in the pattern necessitate this to be mutable either, though I guess this pattern does seem to have some of its advantages from when you need mutability for some reason. Then I like how it isolates the mutable data behind the functionality. It feels like a lighter weight version of both OO and protocols/records. I'm curious to benchmark it against records, which is what I would have used before for something like a stopwatch. I think this could come in handy when doing libraries with options. My current pattern was to have a function create an options, and then the user would need to manage the options map, and pass it to all my library functions. Or I would use a var instead the library to store the options map, and offer it as a binding so users could rebind their own options. The problem with the latter is that you can't run the library with two different option set at the same time, while the former forces you to have to manage an options map and pass it around everywhere. So I feel there's something I could do here, with wrapping everything in this pattern, and having the options be captured in the closure. On Friday, 9 December 2016 23:47:34 UTC-8, Didier wrote: > > I'm wondering what everyone thinks of using closures to mimic a simplistic > object system in Clojure? I'm not sure what to think of it yet, but the > idea is that you wrap object fields inside a closed function, and it > returns a map of methods that operates over those fields. > > Here's an example of using this pattern to implement a StopWatch: > > (import [java.lang System]) > (defn new-stopwatch [] > (let [start-time (atom nil) > elapsed (atom 0)] > {:start (fn [] > (when (nil? @start-time) > (reset! start-time (System/currentTimeMillis > :stop (fn [] > (when-not (nil? @start-time) >(reset! elapsed >(+ @elapsed > (- (System/currentTimeMillis) @start-time))) >(reset! start-time nil)) > @elapsed) > :reset (fn [] > (reset! start-time nil) > (reset! elapsed 0) > @elapsed) > :elapsed (fn [] > (if-not (nil? @start-time) > (- (System/currentTimeMillis) @start-time) > @elapsed))})) > > (let [sw1 (new-stopwatch) > sw2 (new-stopwatch)] > ((:start sw1)) > ((:start sw2)) > (Thread/sleep 100) > ((:reset sw1)) > ((:start sw1)) > (println (str "Elapsed for SW1: " ((:elapsed sw1 > (println (str "Elapsed for SW2: " ((:elapsed sw2 > (Thread/sleep 100) > (println (str "SW1: " ((:stop sw1 > (println (str "SW2: " ((:stop sw2) > > I find for certain things, like a stopwatch, this pattern is actually > pretty nice. I can't think of any alternative way to do this in Clojure > that I'd like better actually. > > What are your thoughts? > -- 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: ava.lang.SecurityException: class "org.apache.poi.POIXMLDocumentPart"'s signer information does not match signer information of other classes in the same package
Not sure how to exclude an imported Java class? lein deps :tree Possibly confusing dependencies found: [lein-checkall "0.1.1"] -> [jonase/eastwood "0.0.2"] -> [org.clojure/tools.namespace "0.1.2"] overrides [lein-checkall "0.1.1"] -> [lein-kibit "0.0.8"] -> [jonase/kibit "0.0.8"] -> [org.clojure/tools.namespace "0.2.1"] and [lein-checkall "0.1.1"] -> [lein-bikeshed "0.1.3"] -> [org.clojure/tools.namespace "0.2.3"] Consider using these exclusions: [lein-checkall "0.1.1" :exclusions [org.clojure/tools.namespace]] [lein-checkall "0.1.1" :exclusions [org.clojure/tools.namespace]] Retrieving org/clojure/tools.nrepl/0.2.12/tools.nrepl-0.2.12.pom from central Retrieving clojure-complete/clojure-complete/0.2.4/clojure-complete-0.2.4.pom from clojars Retrieving org/clojure/tools.nrepl/0.2.12/tools.nrepl-0.2.12.jar from central Retrieving clojure-complete/clojure-complete/0.2.4/clojure-complete-0.2.4.jar from clojars [clj-stacktrace "0.2.7"] [clj-time "0.6.0"] [joda-time "2.2"] [clojure-complete "0.2.4" :exclusions [[org.clojure/clojure]]] [com.taoensso/timbre "4.3.1"] [com.taoensso/encore "2.36.2"] [com.taoensso/truss "1.1.1"] [org.clojure/tools.reader "0.10.0"] [io.aviso/pretty "0.1.23"] [dire "0.5.4"] [org.clojure/core.incubator "0.1.3"] [robert/hooke "1.3.0"] [expectations "2.0.9"] [junit "4.8.1"] [javax.xml.stream/stax-api "1.0-2"] [me.raynes/fs "1.4.4"] [org.apache.commons/commons-compress "1.4"] [org.tukaani/xz "1.0"] [org.apache.poi/poi-ooxml "3.9"] [dom4j "1.6.1"] [org.apache.poi/poi-ooxml-schemas "3.9"] [org.apache.xmlbeans/xmlbeans "2.3.0"] [stax/stax-api "1.0.1"] [org.apache.poi/poi "3.9"] [commons-codec "1.5"] [org.clojure/clojure "1.7.0"] [org.clojure/data.xml "0.1.0-beta1"] [org.clojure/test.check "0.9.0"] [org.clojure/tools.nrepl "0.2.12" :exclusions [[org.clojure/clojure]]] [org.eclipse.birt.runtime "4.2.2"] [commons-cli "1.0"] [commons-lang "1.0"] [commons-logging "1.0"] [milyn/flute "1.3"] [org.eclipse.birt.runtime.3_7_1/Tidy "1"] [org.eclipse.birt.runtime.3_7_1/com.lowagie.text "2.1.7"] [org.eclipse.birt.runtime.3_7_1/derby "10.5.101"] [org.eclipse.birt.runtime.3_7_1/javax.wsdl "1.5.1"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.bridge "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.css "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.dom.svg "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.dom "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.ext.awt "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.parser "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.pdf "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.svggen "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.transcoder "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.util.gui "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.util "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.batik.xml "1.6.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.commons.codec "1.3.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.xerces "2.9.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.xml.resolver "1.2.0"] [org.eclipse.birt.runtime.3_7_1/org.apache.xml.serializer "2.7.1"] [org.eclipse.birt.runtime.3_7_1/org.mozilla.javascript "1.7.2"] [org.eclipse.birt.runtime.3_7_1/org.w3c.css.sac "1.3.0"] [org.eclipse.birt.runtime.3_7_1/org.w3c.dom.smil "1.0.0"] [org.eclipse.birt.runtime.3_7_1/org.w3c.dom.svg "1.1.0"] [org.eclipse.birt.runtime/com.ibm.icu "4.4.2.v20110823"] [org.eclipse.birt.runtime/javax.xml.stream "1.0.1.v201004272200"] [org.eclipse.birt.runtime/org.apache.commons.logging "1.0.4.v201101211617"] [org.eclipse.birt.runtime/org.eclipse.core.contenttype "3.4.200.v20120523-2004"] [org.eclipse.birt.runtime/org.eclipse.core.expressions "3.4.401.v20120912-155018"] [org.eclipse.birt.runtime/org.eclipse.core.filesystem "1.3.200.v20130115-145044"] [org.eclipse.birt.runtime/org.eclipse.core.jobs "3.5.300.v20120912-155018"] [org.eclipse.birt.runtime/org.eclipse.core.resources "3.8.1.v20121114-124432"] [org.eclipse.birt.runtime/org.eclipse.core.runtime "3.8.0.v20120912-155025"] [org.eclipse.birt.runtime/org.eclipse.datatools.connectivity.apache.derby.dbdefinition "1.0.2.v201107221459"] [org.eclipse.birt.runtime/org.eclipse.datatools.connectivity.apache.derby "1.0.103.v201212070447"] [org.eclipse.birt.runtime/org.eclipse.datatools.connectivity.console.profile "1.0.10.v201109250955"] [org.eclipse.birt.runtime/org.eclipse.datatools.connectivity.db.generic "1.0.1.v201107221459"] [org.eclipse.birt.runtime/org.eclipse.datatools.connectivity.dbdefinition.genericJDBC "1.0.1.v201107221459"] [org.eclipse.birt.runtime/org.eclipse.datatools.connectivity.oda.consumer "3.2.5.v201109151100"]
ava.lang.SecurityException: class "org.apache.poi.POIXMLDocumentPart"'s signer information does not match signer information of other classes in the same package
I've never worked much with Java, so dealing with stuff like Maven is the stuff I understand least about Clojure. I've added these 3 items to the dependencies that I list in project.clj [org.apache.poi/poi "3.9"] [org.apache.poi/poi-ooxml "3.9"] [org.eclipse.birt.runtime/org.eclipse.birt.runtime "4.2.2"] When I run "lein uberjar" I get this: java.lang.SecurityException: class "org.apache.poi.POIXMLDocumentPart"'s signer information does not match signer information of other classes in the same package How do I get around this? -- 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: "lein uberjar" gives me java.lang.OutOfMemoryError:
I seem to get around this by increasing: :jvm-opts ["-Xms300m" "-Xmx300m" "-XX:-UseCompressedOops"]) Is that possible? I didn't realize that effected "lein uberjar" I thought it only effected my app when my app was running. On Saturday, December 10, 2016 at 11:37:44 PM UTC-5, larry google groups wrote: > > I had a small app that was compelling, and then I added in a java class, > and now when I run "lein uberjar" I get java.lang.OutOfMemoryError. > > I'm working on my MacBook Pro, 16 gigs of memory > > Dependencies were: > > > :dependencies [ > [org.clojure/clojure "1.7.0"] > [com.taoensso/timbre "4.3.1"] > [dire "0.5.4"] > [slingshot "0.12.2"] > [clj-time "0.6.0"] > [org.clojure/test.check "0.9.0"] > [me.raynes/fs "1.4.4"] > [clj-stacktrace "0.2.7"] > [sax/sax "2.0.1"] > [xml-apis/xml-apis "2.0.2"] > [javax.xml.stream/stax-api "1.0-2"] > [overtone/at-at "1.2.0"] > [org.clojure/data.xml "0.1.0-beta1"] > > [org.apache.poi/poi "3.9"] > [org.apache.poi/poi-ooxml "3.9"] > ] > > And the above compiled, but then I added: > > [org.eclipse.birt.runtime/org.eclipse.birt.runtime > "4.2.2"] > > And that was about when things fell apart. > > In my project.clj I also have: > > :source-paths ["src/clojure"] > :java-source-paths ["src/java"] > > And I have added one Java file to src/java: > > package com.heddy.excel_to_csv; > > > import java.io.InputStream; > import java.util.Iterator; > import java.util.LinkedHashMap; > import java.util.Map; > > import org.apache.poi.openxml4j.opc.PackageAccess; > import org.apache.poi.xssf.eventusermodel.XLSX2CSV; > import org.apache.poi.xssf.eventusermodel.XSSFReader; > import org.apache.poi.xssf.model.SharedStringsTable; > import org.apache.poi.xssf.usermodel.XSSFRichTextString; > import org.apache.poi.openxml4j.opc.OPCPackage; > import org.xml.sax.Attributes; > import org.xml.sax.ContentHandler; > import org.xml.sax.InputSource; > import org.xml.sax.SAXException; > import org.xml.sax.XMLReader; > import org.xml.sax.helpers.DefaultHandler; > import org.xml.sax.helpers.XMLReaderFactory; > > > public class SheetHandler extends DefaultHandler { > private SharedStringsTable sst; > private String lastContents; > private boolean nextIsString; > private SheetHandler(SharedStringsTable sst) { > this.sst = sst; > } > public void startElement(String uri, String localName, String name, > Attributes attributes) throws SAXException { > // c => cell > if(name.equals("c")) { > // Print the cell reference > System.out.print(attributes.getValue("r") + " - "); > // Figure out if the value is an index in the SST > String cellType = attributes.getValue("t"); > if(cellType != null && cellType.equals("s")) { > nextIsString = true; > } else { > nextIsString = false; > } > } > // Clear contents cache > lastContents = ""; > } > public void endElement(String uri, String localName, String name) > throws SAXException { > // Process the last contents as required. > // Do now, as characters() may be called more than once > if(nextIsString) { > int idx = Integer.parseInt(lastContents); > lastContents = new > XSSFRichTextString(sst.getEntryAt(idx)).toString(); > nextIsString = false; > } > > // v => contents of a cell > // Output after we've seen the string contents > if(name.equals("v")) { > System.out.println(lastContents); > } > } > > public void characters(char[] ch, int start, int length) > throws SAXException { > lastContents += new String(ch, start, length); > } > } > > I have never used a Java file like this before, so I wasn't sure how to > proceed. I invented the "package" name, which could be all wrong. > > I've stolen the Java code from here: > > > https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java > > Any thoughts why I would get an OutOfMemory? > > > > > > > -- 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
"lein uberjar" gives me java.lang.OutOfMemoryError:
I had a small app that was compelling, and then I added in a java class, and now when I run "lein uberjar" I get java.lang.OutOfMemoryError. I'm working on my MacBook Pro, 16 gigs of memory Dependencies were: :dependencies [ [org.clojure/clojure "1.7.0"] [com.taoensso/timbre "4.3.1"] [dire "0.5.4"] [slingshot "0.12.2"] [clj-time "0.6.0"] [org.clojure/test.check "0.9.0"] [me.raynes/fs "1.4.4"] [clj-stacktrace "0.2.7"] [sax/sax "2.0.1"] [xml-apis/xml-apis "2.0.2"] [javax.xml.stream/stax-api "1.0-2"] [overtone/at-at "1.2.0"] [org.clojure/data.xml "0.1.0-beta1"] [org.apache.poi/poi "3.9"] [org.apache.poi/poi-ooxml "3.9"] ] And the above compiled, but then I added: [org.eclipse.birt.runtime/org.eclipse.birt.runtime "4.2.2"] And that was about when things fell apart. In my project.clj I also have: :source-paths ["src/clojure"] :java-source-paths ["src/java"] And I have added one Java file to src/java: package com.heddy.excel_to_csv; import java.io.InputStream; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.xssf.eventusermodel.XLSX2CSV; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.apache.poi.openxml4j.opc.OPCPackage; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; public class SheetHandler extends DefaultHandler { private SharedStringsTable sst; private String lastContents; private boolean nextIsString; private SheetHandler(SharedStringsTable sst) { this.sst = sst; } public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { // c => cell if(name.equals("c")) { // Print the cell reference System.out.print(attributes.getValue("r") + " - "); // Figure out if the value is an index in the SST String cellType = attributes.getValue("t"); if(cellType != null && cellType.equals("s")) { nextIsString = true; } else { nextIsString = false; } } // Clear contents cache lastContents = ""; } public void endElement(String uri, String localName, String name) throws SAXException { // Process the last contents as required. // Do now, as characters() may be called more than once if(nextIsString) { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); nextIsString = false; } // v => contents of a cell // Output after we've seen the string contents if(name.equals("v")) { System.out.println(lastContents); } } public void characters(char[] ch, int start, int length) throws SAXException { lastContents += new String(ch, start, length); } } I have never used a Java file like this before, so I wasn't sure how to proceed. I invented the "package" name, which could be all wrong. I've stolen the Java code from here: https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java Any thoughts why I would get an OutOfMemory? -- 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: Closure for object pattern? A good idea?
You don't need mutability to represent a stopwatch. (defn start [stopwatch] (assoc stopwatch ::start-time (System/currentTimeMillis))) (defn elapsed-since-started [stopwatch] (- (System/currentTimeMillis) (::start-time stopwatch))) (defn stop [stopwatch] (-> stopwatch (dissoc ::start-time) (update ::elapsed (fnil + 0) (elapsed-since-started stopwatch (defn elapsed [stopwatch] (::elapsed (stop stopwatch) 0) (defn reset [stopwatch] (dissoc stopwatch ::start-time ::elapsed)) Mutability is typically only necessary for two reasons: 1. Communication across threads 2. Performance - James On 10 December 2016 at 07:47, Didierwrote: > I'm wondering what everyone thinks of using closures to mimic a simplistic > object system in Clojure? I'm not sure what to think of it yet, but the > idea is that you wrap object fields inside a closed function, and it > returns a map of methods that operates over those fields. > > Here's an example of using this pattern to implement a StopWatch: > > (import [java.lang System]) > (defn new-stopwatch [] > (let [start-time (atom nil) > elapsed (atom 0)] > {:start (fn [] > (when (nil? @start-time) > (reset! start-time (System/currentTimeMillis > :stop (fn [] > (when-not (nil? @start-time) >(reset! elapsed >(+ @elapsed > (- (System/currentTimeMillis) @start-time))) >(reset! start-time nil)) > @elapsed) > :reset (fn [] > (reset! start-time nil) > (reset! elapsed 0) > @elapsed) > :elapsed (fn [] > (if-not (nil? @start-time) > (- (System/currentTimeMillis) @start-time) > @elapsed))})) > > (let [sw1 (new-stopwatch) > sw2 (new-stopwatch)] > ((:start sw1)) > ((:start sw2)) > (Thread/sleep 100) > ((:reset sw1)) > ((:start sw1)) > (println (str "Elapsed for SW1: " ((:elapsed sw1 > (println (str "Elapsed for SW2: " ((:elapsed sw2 > (Thread/sleep 100) > (println (str "SW1: " ((:stop sw1 > (println (str "SW2: " ((:stop sw2) > > I find for certain things, like a stopwatch, this pattern is actually > pretty nice. I can't think of any alternative way to do this in Clojure > that I'd like better actually. > > What are your thoughts? > > -- > 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: Index of an element in a vector of vectors
Don't know what you mean about "swapping", but here's a solution that generalizes to a tree of any finite depth, where each node is either a leaf element or a seqable (say, a vector) of any length: (defn coord-of ([elems target] (coord-of elems target [])) ([elems target indexes] (first (keep-indexed (fn [i x] (cond (= x target) (conj indexes i) (seqable? x) (coord-of x target (conj indexes i elems Then, for example, cljs.user=> (coord-of [[] 11 [1 2 3] [4 5 6]] 5) [3 1] cljs.user=> (coord-of [[] 11 [1 2 3] [4 5 6]] 55) nil -- 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: Closure for object pattern? A good idea?
I feel like you would be better off separating functions from the data they operate on here. In this case, you could represent the state of a stopwatch with a map containing the start time and the time elapsed, and have functions `stop`, `reset`, `start`, etc that take the stopwatch data structure as an argument and compute an answer or return a new stopwatch data structure as needed. If you need to share the state of the stopwatch you can always put that map in an atom when you need to. This has the additional benefit that you can implement new functions on the stopwatch without changing the implementation stopwatch data structure itself, while in the case of the closure you need to change the implementation of `new-stopwatch` if you want to be able to do anything else with the stopwatch data - sort of the same rationale for clojure.core's extensive use of functions that operate on seqs instead of many specialized data structures. You don't gain much by storing the state in a closure unless you need to guarantee that the user of your code can't access it, which with immutable data structures isn't often necessary. -Logan On Saturday, December 10, 2016 at 2:47:34 AM UTC-5, Didier wrote: > > I'm wondering what everyone thinks of using closures to mimic a simplistic > object system in Clojure? I'm not sure what to think of it yet, but the > idea is that you wrap object fields inside a closed function, and it > returns a map of methods that operates over those fields. > > Here's an example of using this pattern to implement a StopWatch: > > (import [java.lang System]) > (defn new-stopwatch [] > (let [start-time (atom nil) > elapsed (atom 0)] > {:start (fn [] > (when (nil? @start-time) > (reset! start-time (System/currentTimeMillis > :stop (fn [] > (when-not (nil? @start-time) >(reset! elapsed >(+ @elapsed > (- (System/currentTimeMillis) @start-time))) >(reset! start-time nil)) > @elapsed) > :reset (fn [] > (reset! start-time nil) > (reset! elapsed 0) > @elapsed) > :elapsed (fn [] > (if-not (nil? @start-time) > (- (System/currentTimeMillis) @start-time) > @elapsed))})) > > (let [sw1 (new-stopwatch) > sw2 (new-stopwatch)] > ((:start sw1)) > ((:start sw2)) > (Thread/sleep 100) > ((:reset sw1)) > ((:start sw1)) > (println (str "Elapsed for SW1: " ((:elapsed sw1 > (println (str "Elapsed for SW2: " ((:elapsed sw2 > (Thread/sleep 100) > (println (str "SW1: " ((:stop sw1 > (println (str "SW2: " ((:stop sw2) > > I find for certain things, like a stopwatch, this pattern is actually > pretty nice. I can't think of any alternative way to do this in Clojure > that I'd like better actually. > > What are your thoughts? > -- 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: Thoughts on clojure.spec
I would certainly welcome and use an `overinstrument` function if added to schpec (or another library). One reason spec is great because it provides "a la carte" validation: a can add an appropriate amount of validation to the parts of my code that would most benefit from it. In my experience using spec so far, optionally running `fn` and `ret` specs during instrumentation would give me more options to pick the correct amount of validation. For instance, since side-effecting functions are harder to unit test (and difficult to test generatively), I would like to spec the functions and then run integration tests. Running `ret`/`fn` specs would help me detect errors closer to their source and also confirm the specs are accurate, which improves the value specs as documentation. In my current project, I have been avoiding writing `ret` specs for side-effecting functions because I worry they'll get out-of-sync and mislead other programmers. Also, having `ret`/`fn` specs checked during instrumentation would add value during development when I'm not yet ready to build generative tests. For example, during early development of a function, I might just spec a parameter with `map?` even though it actually requires certain keys. That spec far too vague for generative testing, but immediately adds value when I turn on instrumentation, since it catches bugs where I've passed, say, `nil` as the parameter. When the feature is more stable, I can invest the time in creating a generator and running generative tests. With the current implementation of `instrument`, I find that I've been tempted to over-spec early in development in order to get working generative tests that will confirm my `ret` and `fn` specs are correct. I understand Rich and Alex have thought all this through and have provided a detailed rationale for the current behavior. But in my own workflow, being able to turn on `ret`/`fn` specs during instrumentation would be a big help, and I'd very much like to see this feature added to schpec. I'm happy to look at this when my schedule allows (not this week or next due to travel). Perhaps the best approach is to add an `over-instrument` function that has options for turning on/off `args`, `fn`, and `ret` specs (enabling all by default) and see how people use it in practice? Thanks to everyone who have worked so hard on all aspects of spec! Ben On Tuesday, December 6, 2016 at 4:42:44 PM UTC-7, Brandon Bloom wrote: > > I was just very surprised to discover my :ret specs were not being checked > via instrument. I've read the rationale above, but I'm not yet convinced. > While of course I can (and will) use spec/assert from a post condition, I > lose the nice selective instrumentation features. > > I'd also like to make a counter-point to this reasoning: > > >> Running return-value instrument-style checking on whatever few >> hand-written tests you might have isn’t going to give you better coverage >> than a simple (even hardwired) generator that captures similar ranges. > > > In my case, I was already testing the root-level return value, but this > function is deeply recursive. A small non-conforming value deep in the > evaluation stack was yielding non-conformance at a path deep in the root > return value. I was confused by why the :ret check wasn't finding it > earlier. By relying on the top-level check rather than inline checks > per-call (as per instrument or :pre/:post) I lost access to the call stack. > Adding the post condition pin-pointed the problem instantly. > -- 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.
[ANN] Odin 0.2.0 - Query DSL for Clojure
I just released the first official version of Odin ( https://github.com/halgari/odin). Odin is a declarative, extensible query DSL for Clojure that leverages transducers to provide a high amount of generality while still maintaining acceptable performance. One of the biggest features of Odin is its ability to rapidly index and query "normal" Clojure data structures. Here is a quick example of this feature in practice: (let [orders [{:customer/name "Sam" :customer/id 3411} {:customer/id 3411 :order/items {1212 3}} {:customer/id 3411 :order/items {2232 2 4242 3}} {:item/id1212 :item/price 40.0} {:item/id2232 :item/price 100} {:item/id4242 :item/price 1.99}]] (->> (o/for-query (o/and (d/query orders ?customer :customer/name "Sam") (d/query orders ?customer :customer/id ?id) (d/query orders ?order :customer/id ?id) (d/query-in orders ?order [:order/items ?item-id] ?qty) (d/query orders ?item :item/id ?item-id) (d/query orders ?item :item/price ?price)) (* ?qty ?price)) (reduce + 0))) ;; => 325.97 In this example we are given a vector of maps, we are then finding a customer by name, then walking a path through the data to find all the items that customer ordered, the total price is then calculated via the normal multiply and sum. There are several other features supported by Odin, including transformation of data (based on a query), tabling, Datomic support, and much more. I also did a video series on the development process of Odin if anyone is interested: (https://www.youtube.com/watch?v=JyKySmcTR4g) -- 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: Spec of conform of spec
This is exactly my use case as well. I want to provide the user a nice DSL but make it easy to automatically generate input. The idea I had was the user could write things in the DSL and for automatic generation you could just generate the conformed structure. The other thing it's made me notice is that we really need a library to make errors clearer in large nested data structures. /j On Saturday, December 10, 2016 at 3:09:24 AM UTC+1, Leon Grapenthin wrote: > > Alex, I thought about this and it appears to be a convenience problem. > Spec is e. g. excellent to parse a e. g. a Query DSL (which is my current > side project) via conform. But then you have that large data structure that > you want to break down and operate on in several functions. So you need to > have the specs for the conformed structure built by spec. > >> -- 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.