This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-10-25
Channels
- # aws (1)
- # bangalore-clj (9)
- # boot (97)
- # capetown (1)
- # cider (4)
- # clara (1)
- # cljs-dev (2)
- # cljsrn (109)
- # clojure (258)
- # clojure-finland (3)
- # clojure-greece (2)
- # clojure-italy (1)
- # clojure-russia (33)
- # clojure-spec (41)
- # clojure-uk (46)
- # clojurescript (57)
- # component (17)
- # core-async (6)
- # datomic (13)
- # devcards (10)
- # dirac (2)
- # euroclojure (1)
- # figwheel (1)
- # funcool (1)
- # hoplon (472)
- # luminus (17)
- # off-topic (1)
- # om (16)
- # onyx (40)
- # pedestal (14)
- # proton (12)
- # re-frame (27)
- # reagent (15)
- # ring-swagger (2)
- # specter (5)
- # testing (4)
- # untangled (258)
- # vim (4)
if i'm requiring a library with a defrecord and aliasing it is there any reason (alias/recordName. foo bar) would throw a "Unable to resolve classname" error?
@sophiago defrecord creates a class named recordName, and a couple of functions ->recordName etc. the class is a java class, referenced the normal java way, so doesn't get nice namespaces and aliases etc
so if you want to use the java interop constructor recordName. then you need to import the class. but you can use the generated functions, ->recordName and map->recordName through their namespace aliases etc
@bfabry i'm not sure i understood all that. are you saying i can just use import or do i need to actually use java interop functions... because the latter would obviously be horrible
@sophiago generally I'm pretty bad at explaining this stuff, so you may want to seek out some documentation on defrecord. the short story of it is you do not need to use java interop for defrecords, because you can use the automatically generated functions. alias/->recordName will do what you expect alias/recordName. to do
you cannot use alias/recordName., because that's java interop sugar, imagine it gets expanded to (new alias/recordName), which doesn't make sense, because you can't alias class names
you can do (recordName., which gets expanded to (new recordName) if you import that class name, like you can with other class names
personally, I would strongly recommend just using the automatically generated functions, so that you get the nice aliases etc and all the goodness that namespaces provide, and don't need to deal with interop land
and i can't use :refer when i require the library either? i need separate import statements?
you can use :refer to :refer the function ->recordName, but you cannot refer a class name
so saying i can refer a record, but not a class doesn't make any sense in this situation
the stuff in require works on clojure stuff, basically. functions. so you can alias/refer the functions ->recordName
and map->recordName
. you cannot do anything with classes in require. so you cannot refer recordName.
or (new recordName)
. if you want to use a class, which is what recordName is, then you need to either use its fully qualified package and class name, or you need to import it and use just the bare class name (normal java rules)
defrecord creates a class that inherits some useful functionality, and a bunch of functions for working with objects of that class
you can use :refer to :refer ->recordName
and map->recordName
, if you want to reference the class recordName
directly then you must use :import
also even if i use import i'm unclear on how to qualify it so as not to use the full ns the whole time
same as java, you must either use a fully qualified classname, or import the class from the package and use the bare classname
so, given that require statement you can use (sym/->Rational arg arg arg)
and (sym/map->Rational {:arg1 arg1 :arg2 arg2})
or, you could add the :import (:import (symbolic_algebra.core Rational))
and use (Rational. arg arg arg)
wait.... this whole time you were just trying to tell me i could use that arrow syntax instead?
the arrow isn't syntax, when you define a record you automatically get two functions created in that namespace, ->Rational
and map->Rational
for creating records of that type. and yes I was 🙂
sorry yes I didn't pay attention to the definition. substitute in the right amount of args you need
if I wanted to change how a record prints I would override print-method for that object type
right now it's just printing the whole library name and i can barely read the list output
user=> (defrecord Foo [bar]
#_=> Object
#_=> (toString [self] (str "A[" bar "]")))
user.Foo
user=> (->Foo "blah")
#user.Foo{:bar "blah"}
user=> (defmethod print-method Foo [v ^java.io.Writer w] (.write w (str "A[" (:bar v) "]")))
#object[clojure.lang.MultiFn 0x7e0ba804 "clojure.lang.MultiFn@7e0ba804"]
user=> (->Foo "blah")
A[blah]
user=>
it's just boilerplate really. the print-method needs to take a writer rather than just returning a string, so that it can work efficiently if you're writing many objects to a file or whatever. the ^java.io.Writer bit is just there to tell the compiler the type of that object so that it doesn't need to figure it out at runtime (slow), and write
is just the method on the writer that takes a string
haha, which docs? I agree with the print-method stuff. tracking that down was tricker than I expected
@bfabry ok, i realized i have to declare a defmethod with print-method in addition to defrecord...i was just putting it inside the defrecord
ah sorry, yes they're different things. defmethod is adding a method to the multi-method print-method (try saying that 10x fast)
well, i realized because i found this: http://stackoverflow.com/questions/15179515/pretty-printing-a-record-using-a-custom-method-in-clojure
it's an argument list for the method, you can name them whatever you want. it's their order that determines what they are
what they have will work too... they're calling the print-method multimethod again, this time with the first argument being a String, so it will dispatch to the print-method definition meant for handing strings
basically i have a bug in code that uses this library i can't even diagnose until i get it to pretty print!
the default printing behaviour won't work in the meantime? I think you'll want (.write w (str (:numerator v) "%" (:denominator v)))
when i have a whole list of a dozen of those it makes it hard to diagnose typing errors
seems to work for me
user=> (defrecord Rational [numerator denominator])
user.Rational
user=> (defmethod print-method Rational [v ^java.io.Writer w] (.write w (str (:numerator v) "%" (:denominator v)))
#_=> )
#object[clojure.lang.MultiFn 0x7e0ba804 "clojure.lang.MultiFn@7e0ba804"]
user=> (Rational. 1 2)
1%2
user=>
i mean, it makes sense you wouldn't have an ns in front of it since it's the user repl
user=> (in-ns 'foo)
#object[clojure.lang.Namespace 0x76d36d2d "foo"]
foo=> (user.Rational. 1 2)
1%2
user=> (defrecord Rational [numerator denominator])
user.Rational
user=> (defmethod print-method Rational [v ^java.io.Writer w] (.write w (str (:numerator v) "%" (:denominator v)))
#_=> )
#object[clojure.lang.MultiFn 0x7e0ba804 "clojure.lang.MultiFn@7e0ba804"]
user=> (Rational. 1 2)
1%2
user=> (in-ns 'foo)
#object[clojure.lang.Namespace 0x76d36d2d "foo"]
foo=> (user.Rational. 1 2)
1%2
foo=> (in-ns 'user)
#object[clojure.lang.Namespace 0xc9941a6 "user"]
user=> (defrecord Rational [numerator denominator])
user.Rational
user=> (Rational. 1 2)
#user.Rational{:numerator 1, :denominator 2}
@sophiago: printing works fine for me when I paste that into my repl
@sophiago: here's a way to reproduce what I'm getting
take that file, add (println (Rational. 3 4))
to the bottom of it
then run java -jar ~/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar that-file.clj
ok lemme try that @gfredericks
@gfredericks did you intend for me to put that in a -main?
@sophiago: sure, try that
I only got output if I put it outside the main
@sophiago: and you're running java
just the way I have it above?
that's pretty spooky then
if you point it at a file that just has (println "what")
in it, does that work?
i spent like 45 minutes editing one file in emacs that i thought was in an adjacent directory i had cloned
i should have just changed the name to something totally different, although not sure that would have helped as it would have only been the outer dir
well thanks for the help @gfredericks and @bfabry
not a waste of time more than any other question; presumably trying the most basic thing and having it not work helped you think of alternative causes
is there a way in leiningen to have it move files to target but not add them inside the jar when compiling?
@gfredericks Is there an easy way to make a monadic for
? If not, should there be?
@eraserhd you mean one that magically works for (ha!) any monad?
If you explicitly supply those you can build a for
If you want :when it has to be a MonadPlus I believe
To this day I still wonder: is there a way to pithily express:
(cond
(f x) a
(g x) b))
Is there a standard way to express that without repeating x
? condp
would work if clojure.core
had a call
function, but it doesn’t, as far as I can tell.
It's not amazingly pretty, but shouldn't
(condp #(%1 %2) x
f a
g b)
work?Or
(condp apply [x]
f a
g b)
it forces the first item in coll
, which is presumably a lazy seq
imo if you are calling doall with an n, you are probably in a bad place :)
generally, I am suspicious of any case where you have to know much of a lazy seq is realized
@cigitia you can always macro it to make your own control flow that is as pithy as you like
(defmacro condf
[v & func-rets]
(let [[f r & more-fs] func-rets]
(when f
`(if (~f ~v) ~r (condf ~v ~@more-fs)))))
(condf x f a g b) ;; no repeated x!
(condf 5 pos? :pos zero? :zero neg? :neg)
@alexmiller are you the sort of person that indents function bodies further than the arglist
just copy/paste cruft
okay that's good to know
judge me as you will
thanks alexmiller gfredericks , I'm wrapping langohr's get
function on a queue to take a subset of it, all of it in a macro that cleans up AMQP connection and its channels, so I need to force it
I'm trying to understand why having both filename.clj and filename.cljc (both using the same namespace) does not work. Only the .clj file is compiled as far as I can tell. Is it a limitation of the current implementation or something that should never work? I ask, because as I understand it, Clojure doesn't really care about files, just top level forms. (As if everything was sent to a REPL) So, given that, it seems like you'd compile both files and put the various def's from both files into the namespace.
hey quick question - has anyone found themselves wanting a for-into
as a shortcut for (into X (for …))
? e.g.
(for-into {} [[k v] {1 2 3 4 4 5} :when (even? v)] {(str k) (inc v)}) => {“1” 3 “3” 5}
@grant Clojure and ClojureScript will both use their platform-specific extension first and fall back to cljc as last choice
this allows you to ship a default (cljc) and platform-specific overrides
in what context are you doing compilation?
@mikekap you could use the into transducer for that
(into {} (comp (filter #(even? (val %))) (map #(vector (str (key %)) (inc (val %))))) {1 2 3 4 4 5})
(hurting for a kv variant there)
@alexmiller I tested against lein and boot to see if I got the same behavior from both. In this particular case I was placing things like specs and validation code in .cljc files and client and server specific code in .cljs and .clj files, respectively. I understand I can make it work by either changing filenames and namespaces or putting it all in a .cljc file. It just didn't match my intuition about how it would work, so I was trying to further my understanding and fix my intuition.
you should fix your intuition :)
@alexmiller yea that’s why i was inclined to go with for
- it doesn’t require (fn [[k v]])
. I think I have an aversion to typing fn
:X
when a file is loaded for a namespace, it will load exactly one file, not a union of files
So the correct structure will always be either filename.cljc or filename.clj and filename.clj[sr].
@alexmiller Thanks for the help Alex.
You can have both cljc and clj
Then you can put a portable for all versions in the cljc and an override for just one platform in clj or cljs or cljr