Fork me on GitHub
#clojure
<
2016-10-25
>
sophiago00:10:42

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?

bfabry00:10:11

@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

bfabry00:10:58

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

sophiago00:10:18

@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

bfabry00:10:49

@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

sophiago00:10:23

it's ok. i'm pretty sure you just mean to import them

bfabry00:10:26

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

bfabry00:10:53

you can do (recordName., which gets expanded to (new recordName) if you import that class name, like you can with other class names

bfabry00:10:59

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

sophiago00:10:00

and i can't use :refer when i require the library either? i need separate import statements?

bfabry00:10:31

you can use :refer to :refer the function ->recordName, but you cannot refer a class name

sophiago00:10:55

yeah none of this is making sense to me

sophiago00:10:14

you're saying in one sentence i can do something and then next i can

sophiago00:10:30

the class is a the record

sophiago00:10:09

defrecord creates a class as far as the error codes are concerned

sophiago00:10:28

so saying i can refer a record, but not a class doesn't make any sense in this situation

sophiago00:10:34

there are no java classes

sophiago00:10:55

only constructors i created with defrecord

bfabry00:10:04

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)

bfabry00:10:19

a record is a class

sophiago00:10:53

what's confusing about your explanation is that "a record" is "clojure stuff"

bfabry00:10:04

defrecord creates a class that inherits some useful functionality, and a bunch of functions for working with objects of that class

sophiago00:10:14

i think i understand what you're saying though

sophiago00:10:45

i'm not doing any java interop

sophiago00:10:48

to be clear

bfabry00:10:56

the syntax Foo. is java interop

sophiago00:10:12

that's just syntax

bfabry00:10:26

yes, it expands to (new Foo) which is java interop

sophiago00:10:42

it's not java tho

bfabry00:10:51

user=> (macroexpand '(Foo.))
(new Foo)

bfabry00:10:05

it is definitely java. the new form expects a class

sophiago00:10:30

i understand what you're saying

sophiago00:10:37

it's just a confusing way of putting it

bfabry00:10:53

sorry, like I said I'm not the best at explaining

sophiago00:10:54

java interop refers to interop with java

sophiago00:10:02

whereas this is purely clojure

sophiago00:10:08

i do understand you tho

sophiago00:10:24

i cannot use :refer right?

sophiago00:10:29

only import?

bfabry00:10:18

you can use :refer to :refer ->recordName and map->recordName, if you want to reference the class recordName directly then you must use :import

sophiago00:10:08

ok, that part i still don't understand

sophiago00:10:34

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

sophiago00:10:59

why don't i just use code examples

bfabry00:10:14

same as java, you must either use a fully qualified classname, or import the class from the package and use the bare classname

sophiago00:10:17

(defrecord Rational [numerator denominator])

sophiago00:10:24

so that's one of my classes

sophiago00:10:09

and so far i'm requiring the library like this:

sophiago00:10:17

(:require [symbolic-algebra.core :as sym])

sophiago00:10:27

inside my ns obviously

sophiago00:10:03

so the errors were from trying to be like : sym/Rational.

sophiago00:10:09

i know now why that doesn't work

bfabry00:10:10

😆 I think I can see where this is going and you're going to be annoyed

sophiago00:10:21

no i think it's ok

sophiago00:10:31

i can either use refer or import

sophiago00:10:42

i would just prefer to not be like this:

sophiago00:10:53

symbolic-algebra.core/Rational.

sophiago00:10:57

every time!

bfabry00:10:11

so, given that require statement you can use (sym/->Rational arg arg arg) and (sym/map->Rational {:arg1 arg1 :arg2 arg2})

bfabry00:10:44

you can also use (symbolic_algebra.core.Rational. arg arg arg)

sophiago00:10:02

the arrow syntax?

bfabry00:10:15

or, you could add the :import (:import (symbolic_algebra.core Rational)) and use (Rational. arg arg arg)

sophiago00:10:39

wait.... this whole time you were just trying to tell me i could use that arrow syntax instead?

bfabry00:10:06

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 🙂

sophiago00:10:41

and you're using extra args... that's a mistake right?

sophiago00:10:47

mine is just dyadic

bfabry00:10:02

sorry yes I didn't pay attention to the definition. substitute in the right amount of args you need

sophiago00:10:13

ok just wanted to be sure

sophiago00:10:18

wow after all that!

sophiago00:10:26

ok lemme try it to be certain

sophiago00:10:53

it worked! thanks!

sophiago00:10:01

i never realized that about records

sophiago00:10:21

<-not a /Java coder

sophiago00:10:48

of course now i have other errors, but i'll figure them out

sophiago00:10:05

oh, because i need to do this with other records

sophiago00:10:05

oh, when it prints tho...it shows up with the full ns, which is quite long

sophiago00:10:12

i suppose that's a reason to alias it 😕

bfabry00:10:35

when it prints the object? mm yes

sophiago00:10:49

if i add that to my require it will change how it prints?

bfabry00:10:05

I'm actually not sure

bfabry00:10:23

if I wanted to change how a record prints I would override print-method for that object type

sophiago00:10:47

oh...how do i do that?

sophiago00:10:57

or could i do that for the whole library?

sophiago00:10:23

right now it's just printing the whole library name and i can barely read the list output

bfabry00:10:53

actually sorry, I mean toString

bfabry00:10:17

I really don't know much about the clojure printing ecosystem

sophiago00:10:16

docs say toString is for deftype not defrecord

sophiago00:10:23

ah ok, i was just going to say i think i found how to do it 🙂

bfabry01:10:10

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=>

bfabry01:10:30

so the toString stuff doesn't work, adding a print-method does

sophiago01:10:24

woah, i never would have figured this java io stuff out

sophiago01:10:05

seems you just substitute in whatever string you want tho

bfabry01:10:55

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

sophiago01:10:14

and it's always v and then w?

bfabry01:10:26

the v is the value passed in, in this case the instance of Foo

bfabry01:10:38

sorry I copypasted, I should've given them better names

sophiago01:10:55

oh. i just assumed that was boilerplate

bfabry01:10:59

[record ^java.io.Writer writer] would be better

bfabry01:10:47

that's how I got the value "blah" out of the object. (:bar v)

sophiago01:10:05

the docs aren't very helpful 😛

bfabry01:10:41

haha, which docs? I agree with the print-method stuff. tracking that down was tricker than I expected

sophiago01:10:43

ha, i guess they're no docs

sophiago01:10:05

and i'm talking about user created docs on the cheatsheet

sophiago01:10:30

there is a link to read about the reader

sophiago01:10:50

if i was less tired and looking for a quick fix i suppose

sophiago01:10:48

@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

bfabry01:10:34

ah sorry, yes they're different things. defmethod is adding a method to the multi-method print-method (try saying that 10x fast)

sophiago01:10:13

but the implementation there seems off

sophiago01:10:33

instead of .write it just repeats print-method?

sophiago01:10:44

and uses a key instead of a string?

sophiago01:10:32

still doesn't seem to matter what variable you match between them tho

sophiago01:10:47

x... v... whatever?

bfabry01:10:28

it's an argument list for the method, you can name them whatever you want. it's their order that determines what they are

sophiago01:10:50

and i assume .write with a string is what i want, not what's in that SO question...

bfabry01:10:19

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

sophiago01:10:51

i think i'll do it the docs way

sophiago01:10:34

hmm...no errors but not working in the repl

sophiago01:10:35

@bfabry it's like this?

sophiago01:10:42

(defrecord Rational [numerator denominator])

sophiago01:10:52

(defmethod print-method Rational [v ^java.io.Writer w] (.write v "%"))

sophiago01:10:54

basically i have a bug in code that uses this library i can't even diagnose until i get it to pretty print!

sophiago01:10:07

but i'm testing it from the library repl itself

bfabry01:10:47

the default printing behaviour won't work in the meantime? I think you'll want (.write w (str (:numerator v) "%" (:denominator v)))

sophiago01:10:16

the problem right now is it prepends the ns

sophiago01:10:28

so output is:

sophiago01:10:30

#symbolic_algebra.core.Rational{:numerator 3, :denominator 4}

sophiago01:10:02

when i have a whole list of a dozen of those it makes it hard to diagnose typing errors

sophiago02:10:47

hmm...behavior is the same

sophiago02:10:26

it's like it doesn't even recognize the defmethods at all

bfabry02:10:03

how are you printing the values?

sophiago02:10:48

oh...does this just apply to print and println and such?

sophiago02:10:55

this is in the repl

sophiago02:10:20

(add (Rational. 1 2) (Rational. 1 4))

bfabry02:10:21

it should work in the repl. but it won't work with pprint

sophiago02:10:28

no, i never use pprint

bfabry02:10:26

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=>

sophiago02:10:19

this is near the top of my code too 😕

sophiago02:10:16

i mean, it makes sense you wouldn't have an ns in front of it since it's the user repl

sophiago02:10:33

my thing is being able to get rid of that

bfabry02:10:55

user=> (in-ns 'foo)
#object[clojure.lang.Namespace 0x76d36d2d "foo"]
foo=> (user.Rational. 1 2)
1%2

sophiago02:10:33

i don't know what could be doing this. i get:

sophiago02:10:38

#symbolic_algebra.core.Rational{:numerator 1, :denominator 2}

bfabry02:10:17

have you defined the record more than once in the same repl session?

bfabry02:10:20

there's known issues with that

sophiago02:10:36

no, i just exited to be sure

sophiago02:10:34

i do have a def-protocol

bfabry02:10:54

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}

sophiago02:10:57

and use extend-type with those

bfabry02:10:17

(the class id on the Rational changes because it was def'd again)

sophiago02:10:30

but like i said, i exited

bfabry02:10:43

do you want to post your code in a gist somewhere?

gfredericks02:10:22

@sophiago: printing works fine for me when I paste that into my repl

bfabry02:10:42

yeah that looks fine

gfredericks02:10:08

@sophiago: here's a way to reproduce what I'm getting

gfredericks02:10:27

take that file, add (println (Rational. 3 4)) to the bottom of it

gfredericks02:10:42

then run java -jar ~/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar that-file.clj

sophiago02:10:22

hold on one sec

bfabry02:10:14

sorry I gotta grab some lunch

sophiago02:10:22

@gfredericks did you intend for me to put that in a -main?

sophiago02:10:38

because otherwise i get no output except the warnings for overridden built-ins

sophiago02:10:53

i could just put it in the -main and use lein run?

gfredericks02:10:02

I only got output if I put it outside the main

sophiago02:10:33

i get no output either way tho...

sophiago02:10:49

which is odd because i should be getting output at least

gfredericks02:10:51

@sophiago: and you're running java just the way I have it above?

sophiago02:10:28

well, i replaced that-filed with the filename...

sophiago02:10:51

but otherwise yes

gfredericks02:10:52

that's pretty spooky then

sophiago02:10:19

this is not good

gfredericks02:10:22

if you point it at a file that just has (println "what") in it, does that work?

sophiago02:10:49

i do regularly print things

sophiago02:10:53

the reader works on my system

sophiago02:10:17

i'm trying to think what else could be causing this

sophiago02:10:26

something stupid

sophiago02:10:41

git branches

sophiago02:10:47

fuck hold on

sophiago02:10:20

idk what the lesson is here even

sophiago02:10:31

naming convention something something i guess?

sophiago02:10:57

i spent like 45 minutes editing one file in emacs that i thought was in an adjacent directory i had cloned

sophiago02:10:06

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

sophiago02:10:08

yikes...sorry for wasting everyone's time

sophiago02:10:09

well thanks for the help @gfredericks and @bfabry

sophiago02:10:20

time for me to sleep i think 😛

bfabry03:10:48

no worries, glad you got it sorted

gfredericks03:10:02

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

candiedcode13:10:06

is there a way in leiningen to have it move files to target but not add them inside the jar when compiling?

yonatanel13:10:32

Does anyone here have experience with OrientDB?

eraserhd16:10:59

@gfredericks Is there an easy way to make a monadic for? If not, should there be?

gfredericks17:10:29

@eraserhd you mean one that magically works for (ha!) any monad?

eraserhd17:10:59

Perhaps just that I supply bind and return?

eraserhd17:10:32

e.g. (make-for bind-fn return-fn).

eraserhd17:10:11

(and get :let)

gfredericks17:10:02

If you explicitly supply those you can build a for

gfredericks17:10:24

If you want :when it has to be a MonadPlus I believe

eraserhd17:10:35

ah, yeah. I've just realized that my use case isn't quite right, though.

cigitia20:10:52

To this day I still wonder: is there a way to pithily express: (cond (f x) a (g x) b))

cigitia20:10:48

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.

programmancer21:10:32

It's not amazingly pretty, but shouldn't

(condp #(%1 %2) x
  f a 
  g b)
work?

programmancer21:10:39

Or

(condp apply [x]
  f a
  g b)

blkt21:10:57

could anyone explain me what should the form (doall 1 coll) do?

gfredericks21:10:32

it forces the first item in coll, which is presumably a lazy seq

Alex Miller (Clojure team)21:10:24

imo if you are calling doall with an n, you are probably in a bad place :)

Alex Miller (Clojure team)21:10:55

generally, I am suspicious of any case where you have to know much of a lazy seq is realized

Alex Miller (Clojure team)21:10:53

@cigitia you can always macro it to make your own control flow that is as pithy as you like

Alex Miller (Clojure team)21:10:24

(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)

gfredericks21:10:02

@alexmiller are you the sort of person that indents function bodies further than the arglist

gfredericks21:10:39

okay that's good to know

blkt22:10:04

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

grant22:10:53

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.

mikekap22:10:48

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}

Alex Miller (Clojure team)22:10:00

@grant Clojure and ClojureScript will both use their platform-specific extension first and fall back to cljc as last choice

Alex Miller (Clojure team)22:10:28

this allows you to ship a default (cljc) and platform-specific overrides

Alex Miller (Clojure team)22:10:05

in what context are you doing compilation?

Alex Miller (Clojure team)22:10:54

@mikekap you could use the into transducer for that

Alex Miller (Clojure team)22:10:50

(into {} (comp (filter #(even? (val %))) (map #(vector (str (key %)) (inc (val %))))) {1 2 3 4 4 5})

Alex Miller (Clojure team)22:10:19

(hurting for a kv variant there)

grant22:10:58

@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.

Alex Miller (Clojure team)22:10:19

you should fix your intuition :)

mikekap22:10:37

@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

Alex Miller (Clojure team)22:10:37

when a file is loaded for a namespace, it will load exactly one file, not a union of files

grant22:10:43

So the correct structure will always be either filename.cljc or filename.clj and filename.clj[sr].

grant22:10:53

@alexmiller Thanks for the help Alex.

Alex Miller (Clojure team)23:10:37

You can have both cljc and clj

Alex Miller (Clojure team)23:10:31

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

grant23:10:38

But you'd have to put all of the def's that you want in the override file, you can not just have an override file that has one or two additional function in it. Right?

sophiago23:10:30

i just realized the source of a bug i've been experiencing is that gen-class doesn't map with dependencies. should i just simply copy it over in the namespace since it's quite short or is there anything else people do about this?