#clojure log - Mar 09 2016

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0:27 TEttinger: TimMc: you have no idea how often I use toBinaryString and toHexString, haha

0:27 I use a lazybot as a calculator and any binary stuff needs that

0:58 ilevd: Hi, I find strings like "{{#list}}" "{{#render}}" in Java project html files, what's that framework or lib?

1:08 rhg135: Mustache

1:12 ilevd: Thanks a lot!

1:36 AndreasO: (run :dispose), what does it do?

1:40 ilevd: It depends on library, where is this used?

1:47 AndreasO: In a seesaw example.

1:52 TEttinger: AndreasO: depends on what run is

1:54 in all the examples I see that's commented out, AndreasO

1:55 it looks like defexample defines the run fn https://github.com/daveray/seesaw/blob/master/test/seesaw/test/examples/example.clj

1:58 AndreasO: TEttinger: strange, I found an example here it wasn't commented out

1:59 TEttinger: it looks like (run :dispose) will run the example, and when the example is closed it calls whatever fn is assigned to :dispose in the defexample

2:00 that's only in the examples

2:13 AndreasO: https://github.com/juliangamble/clj-seesaw-examples/blob/master/src/seesaw/test/examples/clock.clj

2:13 There it is, not commented out.

2:56 ilevd: Are you happy with Clojure?

2:58 opqdonut: it's nice enough

2:58 ridcully_: for the larger part

3:00 TEttinger: yes

4:15 prohobo: clojure is hard yo

5:04 anyone know how to dynamically add a field to the frame using seesaw?

5:18 hello?

5:18 clojurebot: BUENOS DING DONG DIDDLY DIOS, fRaUline prohobo

5:21 prohobo: god damn you clojurebot

5:21 saureb: lol

5:24 krl: is there any way to see where clojure looks for java .class files to import? I'm getting class not found, even though the .class i'm including seems to be in the right place, (pointed to by :java-source-paths)

5:25 (in lein)

5:30 Empperi: it uses the classpath declaration

5:30 which is passed for java on startup

5:32 krl: can you dump it somehow from the repl?

5:34 Empperi: (System/getProperty "java.class.path")

6:45 amoe_: anyone know how to move files using raynes.fs library? It seems to have support for moving things, but I don't know how to get access to the 'move' function that is used by these tests. https://github.com/Raynes/fs/blob/master/test/me/raynes/core_test.clj#L425

6:58 jonathanj: amoe_: according to the source, that function is only available if you're running java 7+

7:04 amoe_: jonathanj: I am indeed running java 7

7:08 jonathanj: amoe_: Looks like that function isn't in 1.4.6, which is the latest stable release: https://github.com/Raynes/fs/blob/1.4.6/src/me/raynes/fs.clj

7:09 rather, it's the version the README says to use

7:09 looks like it was added quite a long time ago: https://github.com/Raynes/fs/commit/fdab09a711f6fd457bcdf13d213c6dea79c31241

7:10 amoe_: oh, that makes sense, thanks! I will find a workaround.

7:11 jonathanj: maybe file an issue about releasing a new version?

7:11 amoe_: jonathanj: yup, I will do so.

7:12 oh, actually one already exists https://github.com/Raynes/fs/issues/102

7:13 it's funny, since starting to work with clojure half the issues I hit are open and resolved in the last ~2 months or so... seems the ecosystem is buzzing

7:32 prohobo_: im not getting any closure on my seesaw issue

7:33 i am emotionally exhausted

7:41 amoe_: prohobo_: maybe paste the code?

7:42 prohobo_: nah, its okay

7:42 im too tired to deal with it today

8:21 amoe_: I wonder is there any way to use the arrow syntax to immediately create a binding with the result, I want to write something like (-> (large-operation) (bind var (do-something var) (do-something-else var)))

8:21 I know that's basically a function but I'd like to avoid making another function as it's in a test

8:23 Kneiva: There is nothing wrong in making a function just for a test.

8:24 amoe_: Kneiva: just my taste but I prefer to keep test code as flat as possible

8:43 TMA: amoe_: you can use unnamed functions: ((fn [var] (do-something var) (do-something-else var)) (large-operation)) or a (let [var ...] ...)

9:00 Malnormalulo: amoe_: If you reeeeeally want to avoid non-test namespace-accessible artifacts, you could always just make liberal use of `letfn`

9:01 which can, itself, contain test defs, so that your tests become closures

9:06 TimMc: amoe_: Is the issue that your tests :use the ns under test, and you don't want to risk testing a test fn of the same name as a var from the original ns?

9:15 zenoli: l.*

9:15 Whoops, sorry.

9:56 RedNifre: Clojure newbie here. So someone mentioned this nice pattern matching library yesterday. I guess I can figure out how to use it in a leiningen project but how can I test it in the REPL? https://clojars.org/defun/defun

9:57 egli: RedNifre: maybe with lein-try


9:58 https://github.com/rkneufeld/lein-try

10:05 RedNifre: Thanks, but that link gives me other ideas. It mentions a project.clj in ~/lein that I don't have... I guess I'll learn more about lein before customizing it further.

10:05 Bookmarked for later, thanks egli.

10:05 * RedNifre treads carefully to not fall into rabbit holes all the time.

10:08 RedNifre: I think it was justin_smith who mentioned a mutable map that maps symbols to values or functions (or macros even?), e.g. using (def pi 3) writes to one such map. Are these maps the namespaces? Or are there differences?

10:24 sdegutis: You ever have a day or week where you're like insanely productive compared to every other day?

10:25 RedNifre: sdegutis. Rarely. It's usually the opposite where one problem leads to the next and everything that should be simple is complicated.

10:25 sdegutis: :D

10:27 RedNifre: So what are you being productive about today? :)

10:27 Malnormalulo: "My first build failed this morning so I've just been staring at the stack trace until noon" --me, most days

10:27 sdegutis: RedNifre: using Clojure at work

10:27 Malnormalulo: wait stack trace in a build that doesn't even make sense

10:27 sdegutis: Malnormalulo: haha yes I know that feeling

10:36 RedNifre: Hm, do the dots in namespaces mean anything?

10:40 Malnormalulo: I think, under the covers, in the bytecode, they're the same as dots in Java packages. If that means anything to you

10:41 (And if you're using the JVM implementation of Clojure)

10:42 RedNifre: Ah, so I could :require many things at once by doing (:require [clojure.*]) ?

10:45 Malnormalulo: That...sounds plausible. I've never tried it.

10:46 prohobo_: damn, clojure. you scary

10:49 mavbozo: RedNifre, you require many things at once by doing (:require [foo.bar :refer [fun1 fun1 fun3 var1 var2]])

10:49 RedNifre: u-huh... So the dots in the namespace name are less important in clojure, they are more informal?

10:50 mavbozo: the dots in the namespace are important to separate namespace segment

10:52 luma: if you want to require multiple namespaces with the same prefix, you can do (:require (foo.bar baz bloo)), which would require both foo.bar.baz and foo.bar.bloo

10:52 RedNifre: Ah, I see.

10:53 luma: and the usual tricks work there as well: (:require (foo.bar [baz :refer [fn1 fn2]] bloo))

11:01 RedNifre: Hm, the JoC book just warned me about java boolean objects i.e. (Boolean. "false"). It says the safe way is (Boolean/valueOf "false"). How exactly does that work? Is Clojure's false a java Boolean object? Or the primitive? Or is there autoboxing?

11:02 mavbozo: ,(type false)

11:02 clojurebot: java.lang.Boolean

11:02 RedNifre: ,(type nil)

11:02 clojurebot: nil

11:02 wink: RedNifre: https://clojurebridge.github.io/community-docs/docs/clojure/truthiness/

11:03 RedNifre: Thanks wink. I'm currently reading about truthiness.

11:03 mavbozo: ,(class false)

11:03 clojurebot: java.lang.Boolean

11:04 RedNifre: So the only falsey things are nil and false, where nil is Java's null and false is Java's Boolean object for false. Do the primitive java booleans show up in Clojure as well or do they always get autoboxed to Boolean objects before showing up in Clojure?

11:12 Now JoC says that my functions should expect to be called with nil if they expect collections and that I should use seq to be sure. That advice seems strange to me, I would have thought that treating nils as empty collections (instead of as bugs) would obfuscate bugs elsewhere in the code. Why is that a good idea?

11:22 bermraj: good morning, is there a dirrerence in using (Integer.) compare to (new Integer)?

11:23 RedNifre: Yes, the JVM caches the first 255 Integers. I guess it doesn't do that when calling the constructor.

11:23 Wait, what does (new Integer) mean in Clojure?

11:24 (Newbie here. I just learned that (Integer.) calls the constructor so I wonder what (new Integer) means)

11:32 rcassidy: ,(new Integer)

11:32 clojurebot: #error {\n :cause "No matching ctor found for class java.lang.Integer"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: No matching ctor found for class java.lang.Integer, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.IllegalArgumentException\n :message "No matching ct...

11:34 narwhal01: hi guys

11:34 mavbozo: ,(new Integer 1)

11:34 clojurebot: 1

11:34 mavbozo: ,(class (new Integer 1))

11:34 clojurebot: java.lang.Integer

11:34 RedNifre: ,(= 1 (new Integer 1))

11:34 clojurebot: true

11:34 narwhal01: ,(clojure.string/join " " ["I" "'m" "sorry"])

11:34 clojurebot: "I 'm sorry"

11:35 RedNifre: heya

11:35 narwhal01: how can i join with condition if the word "'m" don't join with space else join with space

11:36 rcassidy: ,(Integer. 3)

11:36 clojurebot: 3

11:36 RedNifre: narwhal01 funny idea: join with space and then replace " '" with "'"?

11:37 more serious idea: something something foldr / reduce ?

11:37 narwhal01: RedNifre, is the better idea?

11:37 RedNifre, reduce ?

11:38 RedNifre: yeah, reduce with a string builder I think.

11:38 narwhal01: ah ok

11:50 mavbozo: RedNifre, in what chapter in JoC book there is a advice that "my function should expect to be called with nil if the function expect collections"?

11:53 RedNifre: mavbozo hang on, let me go back...

11:54 mavbozo It's in 3.2

11:55 hang on

11:55 I think I might have missread that.

11:56 Oh right, it says "you shouldn't assume seq has been called on your collection arguments, but instead call seq in the function itself." So it means I'll receive empty collections and shouldn't check them for truthiness without calling seq.

11:57 thanks mavbozo

11:59 rcassidy: ,(seq nil)

11:59 clojurebot: nil

12:00 mavbozo: ,(seq '())

12:00 clojurebot: nil

12:00 RedNifre: ,(seq ())

12:00 clojurebot: nil

12:01 MJB47: does anyone know why people dont use empty?

12:01 other than its 3 chars longer

12:01 RedNifre: The books says it's because you would have to type "(when-not (empty?" instead of "(when (seq".

12:02 mavbozo: that's 7 chars longer

12:03 RedNifre: ,(vec [])

12:03 clojurebot: []

12:03 RedNifre: Hm, so no nil here...

12:04 ,(vec (seq []))

12:04 clojurebot: []

12:08 mavbozo: the comprehensive explanations on sequence is in chapter 5.1 in JoC book

12:10 RedNifre: I'll get there eventually.

12:56 cortexman__: oooo\\\\\/

12:57 RedNifre: Hm, JoC says that "underflow" means a floating point becoming zero. I thought it meant substracting from a negative int and getting a positive one as a result.

12:57 Is Integer.MIN_INT -1 also called an "overflow"?

12:59 justin_smith: RedNifre: maybe underflow, but I think it throws OverflowError

12:59 ,(dec Integer/MIN_VALUE)

12:59 clojurebot: -2147483649

12:59 justin_smith: err

12:59 ,(dec Long/MIN_VALUE)

12:59 clojurebot: #error {\n :cause "integer overflow"\n :via\n [{:type java.lang.ArithmeticException\n :message "integer overflow"\n :at [clojure.lang.Numbers throwIntOverflow "Numbers.java" 1501]}]\n :trace\n [[clojure.lang.Numbers throwIntOverflow "Numbers.java" 1501]\n [clojure.lang.Numbers dec "Numbers.java" 1851]\n [sandbox$eval49 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval49 invoke "NO_SOURCE_FIL...

12:59 justin_smith: yeah, it calls it an overflow though it's an underflow technically

13:00 https://en.wikipedia.org/wiki/Arithmetic_underflow

13:00 RedNifre: Can you divide the double that is closest to zero by two for me?

13:00 justin_smith: RedNifre: oooh

13:00 one moment

13:01 ,(/ (Math/ulp 0.0) 2)

13:01 clojurebot: 0.0

13:01 RedNifre: okay, the wikipedia article calls both the integer thing and the float becomes zero thing an "underflow" where the JoC book claims that only dividing a float and getting zero is called an underflow.

13:01 Hm.

13:01 So no underflow exception there...

13:01 justin_smith: RedNifre: Math/ulp gives the closest non-equal value to a given double

13:01 RedNifre: that's not an underflow

13:02 it's a precision failure, but IEEE floats don't throw on precision errors

13:02 RedNifre: ,(Math/ulp 0.0)

13:02 clojurebot: 4.9E-324

13:02 RedNifre: Right, I was surprised as well, but both JoC and the Wikipedia article call those underflows.

13:02 justin_smith: RedNifre: oh wait I'm wrong

13:02 underflow is about small numbers, not low negative numbers

13:02 d'oh

13:03 RedNifre: yeah, JoC is right, not me

13:03 RedNifre: Now you're agreeing with the book, but the wikipedia article says that low negative numbers also underflow.

13:03 justin_smith: now I am double confused, time for my morning coffee

13:03 haha

13:04 RedNifre: reading more closely, the wikipedia article is talking about negative digits on the exponent, not about negative numbers of high magnitude per-se

13:05 RedNifre: Oh right.

13:05 I guess an Integer can overflow at both ends then, but never underflow.

13:06 justin_smith: yeah, that sounds right

13:07 RedNifre: I don't know if anyone else replied about namespaces with mutable maps but the namespace owns a mutable map of symbols to vars (and each var is a mutable container holding a single value), but the namespace also has a map of referred bindings belonging to other namespaces, and probably some other junk too

13:08 eg. the stuff that makes require and use and import work

13:08 RedNifre: Ah, so a namespace is a bundle of several maps where each map has a different purpose?

13:10 justin_smith: yeah - it would probably be informative to check out the java code for this

13:11 RedNifre: I hope I'll understand Clojure as deeply as I understand Io (A dead language, the Lisp of the OOP world).

13:11 justin_smith: I remember Io, I never played with it though

13:11 what about smalltalk, that isn't the Lisp of OOP?

13:12 faxmodem: for all I know Io is a moon

13:12 RedNifre: In Io, everything is an object, the commands you type in the REPL are method calls on the REPL object, Objects are basically maps from Strings to other objects, when you do obj.bla = 5 you are really doing obj.setSlot("bla", 5) etc.

13:13 justin_smith: RedNifre: aha in smalltalk the equivalent of obj.bla = 5 sends a message of [set blah 5] to obj (everything is a message)

13:14 but for some reason at some point in programming history people decided OO was more about inheritence than it was about messages

13:15 RedNifre: Yeah, but in Io, when a method gets called instead of receiving its parameters in can choose to receive a call object instead.

13:15 It's also homoiconic, so the call object will contain the AST of what was passed as parameters.

13:15 This is basically as powerful as macros.

13:15 justin_smith: cool

13:16 RedNifre: And there's an operator table that you can inspect and modify.

13:16 It's both simple and brilliant. Unfortunately it's a dead language and I prefer FP over OOP these days so I'm looking at Clojure now.

13:17 alisdair: Io was great, it's a shame it never took off

13:20 RedNifre: Yeah. You can even turn Clojure syntax into valid Io syntax by defining a method with an empty name that transforms the passed AST before executing. You know, like this: https://gist.github.com/RedNifre/50a98c5ab07b526ca891

13:20 mmastic: What's the idiomatic way to create getters for maps? I'm finding myself making lots of stuff like `(def x (partial :x))'. I thought about a macro but I figured that if this was the way for such a common thing then it would surely be part of the core library.

13:20 justin_smith: mmastic: the idiomatic thing is to not use getters for things that are immutable

13:21 RedNifre: why not just :x?

13:21 justin_smith: exactly, what RedNifre said

13:21 with mutable things, that layer of information hiding can be very important, with immutable ones, it's much less useful

13:22 mmastic: I don't want plain keyword because it bit me in the ass earlier x_x it makes it impossible to change the map without breaking something.

13:22 amalloy: mmastic: def the keywords you want to use

13:23 (def size :size) ... (size the-map)

13:23 then if you change the name of the key, the compiler will know when you forget to update a use

13:23 RedNifre: Ah.

13:24 Maybe using records instead of maps would provide that type of security?

13:24 mmastic: It's very repetitive and boilerplate-y though, don't you think? and usually changing the name of the key isn't the issue, it's different structuring and such.

13:25 justin_smith: mmastic: my solution to that is typically to use prismatic/schema at system boundaries

13:25 mmastic: Yeah I thought about records, but I want to be able to extend on the fly.

13:25 justin_smith: mmastic: you can add any key to a record

13:25 RedNifre: that sounds like contradicting requirements.

13:26 mmastic: Prismatic/schema? what do you mean?

13:26 RedNifre: "prismatic" sounds like lenses and prisms...?

13:26 ,(:not-there {})

13:26 mmastic: Oh, it does RedNifre :P what I mean is that I'm still molding my structure but I want to keep the solid part solid.

13:26 clojurebot: nil

13:27 justin_smith: mmastic: RedNifre: prismatic (which changed names recently) has a library called schema

13:27 it allows checking arbitrary facts about the shape of data, as a kind of dynamic type checking

13:28 mmastic: Ah libraries, okay. Hmm tbh that sounds like a bit of an overkill. Perhaps I should resort to macros anyway :P?

13:31 RedNifre: I would use maps as long as you can remember the keywords and switch to a record (or type?) when you get bitten :)

13:31 (Disclaimer: I have never used maps, types, records so far, I'm just starting out. Don't believe anything I say!)

13:33 mmastic: Hehe fair enough :P thank you. I might do that when I get more far ahead in the evolution of the data.

13:33 Thank you everybody ^^ much appreciated.

13:34 RedNifre: Hang on.. Ruby has something called an ostruct.

13:34 That sounds like what you want.

13:34 You can add arbitrary keys to it, but when you try to retrieve an undefined one you get an error (I think).

13:34 Maybe something like that exists for Clojure?

13:35 justin_smith: RedNifre: this is what records do

13:35 except for the error part

13:35 ,(defstruct Foo [a])

13:35 clojurebot: #error {\n :cause "Unable to resolve symbol: a in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: a in this context"\n ...

13:36 justin_smith: ,(defrecord Foo [a])

13:36 clojurebot: #error {\n :cause "clojure.lang.Var cannot be cast to java.lang.Class"\n :via\n [{:type java.lang.ClassCastException\n :message "clojure.lang.Var cannot be cast to java.lang.Class"\n :at [clojure.lang.Namespace referenceClass "Namespace.java" 129]}]\n :trace\n [[clojure.lang.Namespace referenceClass "Namespace.java" 129]\n [clojure.lang.Namespace importClass "Namespace.java" 158]\n [clojure....

13:36 RedNifre: huh?

13:36 justin_smith: that error is weird...

13:36 RedNifre: huh? about which part?

13:37 RedNifre: Also, I take back what I said about ostruct, it just returns nil when you query something that's not inside.

13:37 justin_smith: ,(defrecord Bar [a])

13:37 clojurebot: sandbox.Bar

13:37 justin_smith: ,(assoc (Bar. 0) :b 1)

13:37 clojurebot: #sandbox.Bar{:a 0, :b 1}

13:37 justin_smith: that's it, that's what records do

13:38 RedNifre: ,(:a (Bar. 0))

13:38 clojurebot: 0

13:38 RedNifre: ,(:c (Bar. 0))

13:38 clojurebot: nil

13:38 mmastic: Okay so I'll just use defs for now and worst case scenario I'll write a macro. Thanks again ^^

13:39 justin_smith: ,(:c (assoc (Bar. 0) :c 2))

13:39 clojurebot: 2

13:39 RedNifre: yeah, but mmastic's problem is that she/he wants a compiler check to catch that.

13:39 justin_smith: ,(:c (map->Bar {:a 0 :c 2}))

13:39 clojurebot: 2

13:39 RedNifre: ,(:i-cantt-type (assoc (Bar. 0) :i-cant-type "huh"))

13:39 clojurebot: nil

13:40 justin_smith: right

13:40 that's why I was saying prismatic/schema, it's the right thing in the clojure world for checking those sorts of things

13:41 that or core.typed, but core.typed is a little trickier to integrate with

13:42 mmastic: Oh I don't care for a compiler check. I just want getters without boilerplate ^^ I basically want something to write the getter functions for me.

13:42 RedNifre: Are keywords getter function or is there some hidden macro that turns (:bla someMap) into (get someMap :bla)?

13:42 mmastic but why do you need a getter function if not for compiler checks?

13:43 mmastic: Yeah, they are.

13:43 And an associative (such as a map) is also a function that takes a key and does the same thing.

13:43 RedNifre: Are keywords variadric functions that when called without arguments return themselves, otherwise call (get param self) ?

13:44 justin_smith: yeah, keywords are getters, and schema allows making assertions about which keywords are present (and the type / shape of the values under those keywords)

13:44 RedNifre: they have no way of returning themselves, though in the reader they are self-evaluating (but that is not the same as returning self when called)

13:45 hiredman: no

13:45 justin_smith: they do have an optional not-found argument when invoked though (the same not-found that get allows)

13:45 hiredman: ,(:foo)

13:45 clojurebot: #error {\n :cause "Wrong number of args passed to keyword: :foo"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Wrong number of args passed to keyword: :foo"\n :at [clojure.lang.Keyword throwArity "Keyword.java" 97]}]\n :trace\n [[clojure.lang.Keyword throwArity "Keyword.java" 97]\n [clojure.lang.Keyword invoke "Keyword.java" 110]\n [sandbox$eval208 invokeStatic "NO_SOURCE_F...

13:48 mmastic: Hmm perhaps I'll explain what actually happened to me. I'm writing a graphical framework. An object in this system is a map, and it has a map assoced with :position which is a map with :x and :y. Then I introduced a physics engine, and the (-> object :position :x) turned into (-> object :physics :position :x). A caller that relied on the initial version broke, as you can imagine. So I thought to make getters. But now getters are boil

13:50 TimMc: mmastic: Cut off at "boil"

13:51 (IRC has message length limits)

13:53 RedNifre: ,::sandbox

13:53 clojurebot: :sandbox/sandbox

13:54 RedNifre: Just to be sure, that's a totally normal keyword named "sandbox/sandbox", right? The part that looks like a namespace is only informal to help programmers, it has no function whatsoever, right?

13:54 justin_smith: mmastic_: have you considered a protocol with a get-x method? that way you can extend the protocol for any object that should have an x coordinate, and the lookup of the actual property is defined in one place per Class

13:55 RedNifre: yeah, the namespace part is useful (eg. helps track who would be interested in that part of the data) but doesn't effect much - the namespace of the keyword doesn't even need to exist

13:55 ,:akldjfalkdsjflakdsjfladskjflkadsjf/foo

13:55 clojurebot: :akldjfalkdsjflakdsjfladskjflkadsjf/foo

13:56 RedNifre: Yeah, so in the technical sense it's a regular keyword that just happens to have a slash in the middle.

13:56 mmastic_: Yeah I did but I'm not sure how would that be implemented. Would I reify instances or just extend maps? Hmm I actually just considered reifying which didn't sound good, but extending maps should work, I suppose, right? or am I missing something?

13:56 justin_smith: ,(namespace :akldjfalkdsjflakdsjfladskjflkadsjf/foo)

13:56 clojurebot: "akldjfalkdsjflakdsjfladskjflkadsjf"

13:57 justin_smith: mmastic_: you would use a record, which is just a map that allows arbitrary protocols / interfaces to be implemented

13:57 RedNifre: so... what would I do with the namespace of a symbol?

13:57 justin_smith: ,(namespace 'foo/bar)

13:57 clojurebot: "foo"

13:58 RedNifre: I meant keyword.

13:58 mmastic_: But I can't arbitrarily assoc new keys without going back and forth, right? that's a concern for me.

13:58 justin_smith: RedNifre: I just did that above

13:58 RedNifre: Yeah, I was asking what I can do with that.

13:58 justin_smith: mmastic_: false, you can associate any keys you want to a record

13:58 mmastic_: I already demonstrated that above

13:59 RedNifre: ahh, sorry, misunderstood

13:59 RedNifre: you might want to go through a map or set and collect keys matching a certain namespace

13:59 mmastic_: Oh really? damn, I got records wrong all along then :P I'll revisit them. So semantically they're just maps where some keys are specialized?

13:59 justin_smith: or remove them, or update them, etc.

14:00 mmastic_: plus the ability to implement interfaces and protocols, yes

14:00 they are very useful

14:00 TimMc: A word of warning, they can interfere with interactive development.

14:01 mmastic_: Omg that sounds amazing. Home come they can interfere?

14:01 justin_smith: (not= (defrecord Foo [a]) (defrecord Foo [a])) - they have the same name and slots, but are different classes

14:02 TimMc: If you make an instance, reload your code, then ask "is this object an instance of this record?" it will say "no", but it will still be of a class with the same name.

14:02 and of course if you implement protocols everything goes haywire with code reloading, but you already get that with protocols

14:02 (who makes wire out of hay anyhow)

14:02 justin_smith: my common approach to this is to put the record and protocol definitions in tiny namespaces that contain no logic that I never reload

14:03 but yes, these things are annoying to be sure

14:03 RedNifre: ,(def a-symbol 'some-symbol)

14:03 clojurebot: #'sandbox/a-symbol

14:03 RedNifre: ,a-symbol

14:03 clojurebot: some-symbol

14:03 mmastic_: Oh I see. I'll revisit records right now. Thank you!

14:03 RedNifre: ,(resolve a-symbol)

14:03 clojurebot: nil

14:04 RedNifre: ,(resolve 'a-symbol)

14:04 clojurebot: #'sandbox/a-symbol

14:04 RedNifre: What exactly does the "#'" at the start mean?

14:04 justin_smith: ,(def some-symbol "found it")

14:04 clojurebot: #'sandbox/some-symbol

14:04 justin_smith: ,@(resolve 'a-symbol)

14:04 clojurebot: some-symbol

14:04 justin_smith: ,@(resolve 'some-symbol)

14:04 clojurebot: "found it"

14:05 justin_smith: ,@(resolve @(resolve 'some-symbol))

14:05 clojurebot: #error {\n :cause "java.lang.String cannot be cast to clojure.lang.Symbol"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.String cannot be cast to clojure.lang.Symbol"\n :at [clojure.core$ns_resolve invokeStatic "core.clj" 4239]}]\n :trace\n [[clojure.core$ns_resolve invokeStatic "core.clj" 4239]\n [clojure.core$ns_resolve invokeStatic "core.clj" 4229]\n [clojure.core$re...

14:05 justin_smith: ergh

14:05 ,@(resolve @(resolve 'a-symbol))

14:05 clojurebot: "found it"

14:05 justin_smith: haha

14:05 RedNifre: What's with the @ again? And what's with the # in the output?

14:05 justin_smith: RedNifre: watch

14:05 ,#'foo

14:05 clojurebot: #error {\n :cause "Unable to resolve var: foo in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve var: foo in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve var: foo in this context"\n ...

14:05 justin_smith: oops

14:06 ,'#'foo ; I meant this

14:06 clojurebot: (var foo)

14:06 RedNifre: Oh, is that the lambda again?

14:06 justin_smith: ,'@#'foo ; I meant this

14:06 clojurebot: (clojure.core/deref (var foo))

14:06 justin_smith: nope, anything starting with # is a reader-macro, and you can see the expansion by using '

14:06 so the above expansions via ' help?

14:07 RedNifre: ehm

14:07 justin_smith: RedNifre: #'foo is a shortcut for (var foo)

14:07 @foo is a shortcut for (deref foo)

14:08 RedNifre: ,(resolve 'a-symbol)

14:08 clojurebot: #'sandbox/a-symbol

14:09 RedNifre: Okay, so clojurebot means (var sandbox/a-symbol) ?

14:09 justin_smith: right

14:10 RedNifre: hang on

14:10 I had to look up var :)

14:11 matt______: hey, all. i've used clojure for some time now, and i've always known that vectors are not seqs, but i've never understood why. when you call first on a vector, it calls RT's first, which turns it into a seq and then calls seq's first. can anyone explain or point me to an explanation?

14:11 TimMc: ~colls and seqs

14:11 clojurebot: Cool story bro.

14:11 TimMc: hmm

14:11 RedNifre: Well, (def x 42) creates a var... but I don't understand that. Hm.

14:11 TimMc: ~seqs and colls

14:11 clojurebot: seqs and colls is http://www.brainonfire.net/files/seqs-and-colls/main.html

14:11 TimMc: matt______: ^ I wrote this up a while back

14:12 matt______: TimMc: nice, thanks. checking it out now.

14:12 justin_smith: RedNifre: namespaces contain a hash-map from symbols to vars, each var is a mutable container holding a single value (with optional metadata)

14:12 TimMc: Summary: Seqs are views into collections.

14:12 RedNifre: I thought that (def x 42) adds an "x" entry to the namespace's map that points to 42. Where does (var 42) come in?

14:12 ah. why is that extra indirection needed?

14:12 justin_smith: RedNifre: because we want to hold onto the var and see the new value later

14:13 without looking it up in the namespace map every time

14:13 it's a thing that makes interactive development work as expected

14:13 matt______: TimMc: quick other question: ISeq also has a more function that no one seems to talk about. any reasoning behind that? deprecation via ignoring?

14:14 hiredman: inlining through a hashmap lookup is complicated, inlining a var deref is simpler

14:14 RedNifre: Oh, you mean if I do (def a "a") (def b a) (def a "not-a"), then b will return "not-a"?

14:14 hiredman: no

14:14 justin_smith: no, but inside a function that uses a, it would see the new a

14:14 hiredman: a is derefed and the value is stored in b

14:14 justin_smith: so (def b [] a) would work as you described

14:14 err, (defn b [] a)

14:15 RedNifre: You mean (def b a) checks the namespace map for a and finds a variable, takes the string out ouf that variable, creates a new variable and puts the string in it and then puts that newly created variable in the namespace map under b?

14:16 hiredman: you are mingling what happens at compile time, and what happens at runtime

14:17 RedNifre: I'm trying to understand what (var "bla") is. I don't understand why (def a "a") doesn't just put the string in the namespace map.

14:17 hiredman: what I said re: inlining

14:18 RedNifre: I don't understand the point about inlining.

14:18 hiredman: with a var, the lookup only needs to happen once, to get the mutable var cell, with a direct map lookup, you would need to do a map lookup for ever function call

14:19 RedNifre: just imagine the var is a inline cache for the map value you would lookup (it isn't, but whatever)

14:19 RedNifre: Hm. I guess def replaces not the content of the var but the var itself?

14:19 hiredman: no

14:20 vars are interned, and def will intern a new one if it does exist, but it reuses an existing one if it already does

14:21 RedNifre: If I do (def a "a") (def b a), what exactly is in b? The way I understand it a and b would point to the same var. But if I do (def a "x") a will point to a newly created var containing "x" where b will still point to the old var containing "a"?

14:21 hiredman: no

14:22 RedNifre: What exactly happens in this code then? (def a "a") (def b a) (def a "x") b ?

14:22 hiredman: (def b a) in that scenario, creates a new var b, then derefs the var a, and puts that value in b

14:22 b will be "a" in that scenario

14:24 RedNifre: Okay, so every def creates a new var, but the (def a "x") would change the content of the already existing var that is pointed to by a from "a" to "x"?

14:24 I meant every def that introduces a new ... symbol ... name ...thingy.

14:24 TimMc: matt______: Oh, I don't know about the more method, lemme see...

14:24 hiredman: a simplified version of the semantics for symbol evalution for clojure is something like: to evaluate the symbol a, if a names a local, it evalautes to the value of that local, if a names a var, deref the var

14:25 RedNifre: no, def produces a var

14:25 justin_smith: TimMc: matt______: .more is what rest calls

14:25 RedNifre: hiredman in my example, what exactly does (def a "x") do?

14:25 hiredman: RedNifre: vars generally are named by symbols (not always, but you'll likely never run in to an anonymous var)

14:26 TimMc: ah yeah, here's LazySeq's impl: https://github.com/clojure/clojure/blob/3748127f440a39d6003e94733da70c2704e385f2/src/jvm/clojure/lang/LazySeq.java#L84

14:26 RedNifre: Does (def a "a") (def a "x") change the content of the var or does it create a new var and puts it in the namespace map?

14:26 hiredman: RedNifre: it looks for a var in the namespace bound to *in-ns* named a, creates it if it doesn't exist, and sets its value to "x"

14:26 RedNifre: it changes the value of the var

14:27 RedNifre: Okay. Let's see if I understand inlining then...

14:27 hiredman: RedNifre: vars are global references by the way, local bindings of names to values (via let, or function application) are locals not vars

14:27 RedNifre: If I do [a a a a], does it fetch the var from the namespace map and then kinda replaces the code with [$var $var $var $var] before continuing?

14:28 hiredman: no

14:28 RedNifre: Can you give me an example for inlining?

14:28 matt______: hm, well more doesn't call rest there. it's the same except it returns an empty list when empty.

14:28 hiredman: the compiler finds the var in the namespace map, and emits code that says "construct such and such a var

14:28 whoops

14:29 matt______: next in RT doesn't call more, either. next calls next, more calls more.

14:29 hiredman: generate java byte code effectively has a reference to the var

14:29 so when the function is running, it never does a map lookup

14:29 it can find all the values it needs just by dereferencing the vars

14:30 derefencing the vars is a simpler operation than a map lookup, so the jvm's jit is better able to optimize it

14:30 (where it gets inlined away or not is sort of complicated)

14:31 RedNifre: Hm... I don't know much about bytecode, I guess that the Clojure code [a a a a] kinda turns into bytecode that says new Vector(Namespace.a, Namespace.a, Namespace.a, Namespace.a);?

14:31 hiredman: no

14:31 RedNifre: dammit

14:32 hiredman: (let [x (resolve 'a)] (Vector. @x @x @x))

14:32 justin_smith: matt______: no, I said rest calls .more

14:32 hiredman: really it is more like

14:32 (let [x (resolve 'a)] (fn [] (Vector. @x @x @x)))

14:33 like, if you had a function like (defn f [] (inc a))

14:33 justin_smith: matt______: next calls .next, more and next are alternatives to one another

14:33 *rest and next that is

14:33 hiredman: (let [x (resolve 'a)] (def f (fn [] (inc @x))))

14:33 RedNifre: Hmm, I think it's getting clearer.

14:34 hiredman: so you see, the resolution of 'a happens once, and then ever after whenever you call the function f, it just reads the value from the resolved var

14:36 matt______: justin_smith: thanks. seems a bit confusing, but i see it fitting together now.

14:36 RedNifre: So if I write the pseudo bytecode as java code it might compile to something like Var<Integer> x = fetchFromTheNamespaceMap("a"); Integer f() { return inc(x.get()); } ?

14:37 hiredman: sort of

14:37 if you know java, the var resolution happens as a static init and the var is held in a static field

14:37 RedNifre: Okay, that's how I imagined it.

14:38 matt______: smells like rest, next, and more will behave the same except for the empty case, and that rest is roughly an alias for more in the empty case.

14:38 RedNifre: Does the content of a var ever change?

14:38 justin_smith: matt______: rest is .more (but might change in the future)

14:38 matt______: next is .next

14:38 hiredman: sure

14:39 RedNifre: how? when?

14:39 justin_smith: matt______: this is much clearer if you look at (source next) and (source rest)

14:39 hiredman: if you define a function g that invokes function f, but at some point in the repl decided to define a new f

14:39 g will when executed use the new f

14:39 matt______: justin_smith: i'm looking at it right now at the top of core.clj before defn is available.

14:41 justin_smith: matt______: no, I mean the source actually available at runtime

14:41 * RedNifre is thinking.

14:41 justin_smith: like literally what (source rest) and (source next) return in the repl

14:41 RedNifre: oh god...

14:42 hiredman: that is also what I think of as "standard var linkage mechanics", there are varations for dynamic binding (slight), direct linking (this is new in 1.8, and basically eliminates the var at compile time), and static linking (this is a defunct, sort of a precursor to direct linking, the compiler support for it is deleted or commented out)

14:42 matt______: justin_smith: that returns the exact same thing as shown in core.clj... ?

14:42 https://github.com/clojure/clojure/blob/010864f8ed828f8d261807b7345f1a539c5b20df/src/clj/clojure/core.clj#L57

14:42 RedNifre: I haven't thought this through but it sounds like it works differently for def and defn.

14:42 hiredman: no

14:43 defn is more or less def

14:43 matt______: the calls to (source rest) or (source next) that is.

14:43 hiredman: (the def part is, the fn part is fn of course)

14:43 justin_smith: matt______: oh, right

14:43 RedNifre: ah, never mind. I thought the wrong way...

14:44 hiredman: RedNifre: (def b a) from your ealier example comes out as (let [x (resolve 'a)] (def b @x))

14:44 it is fairly common for people to be confused about the behavior of top level defs liek that

14:44 matt______: justin_smith: just making sure. thanks for the info.

14:45 justin_smith: RedNifre: and people that know they are confused are a step up on those that simply assume wrongly

14:46 RedNifre: Okay, so (def a "a") (def b a) is two separate vars containing the same string. But the function (defn bla [] a) ... fetches the var when it gets created... so when I later do (def a "x"), the CONTENT of the var changes from "a" to "x" which means that calling the bla function will now return "x" but the b value will still return "a"?

14:47 hiredman: yes

14:47 RedNifre: Phew!

14:48 I think I get it now. Thanks for your patience :)

14:52 hiredman: I have this essay I keep meaning to write entitled "Vars, what the hell?"

14:52 RedNifre: When I do (defn bla [] a), the namespace map gets a new entry called bla that points to a newly created var containing (fn [] the-var-that-was-in-a-when-this-function-got-created), right?

14:53 hiredman: more or less, but you don't really talke about the var being in a, a is the name of the var

14:54 a doesn't have a place to store things, it is a name

14:54 justin_smith: RedNifre: that's right, and also if you deleted a with ns-unmap and made a new a, bla would never see the value of the new a

14:54 RedNifre: Well, no, if I do (def a "x") later then the function will still use the now nameless var that can no longer be found in the namespace map?

14:55 hiredman: no

14:55 RedNifre: oh right

14:55 dammit

14:55 justin_smith: RedNifre: you have crossed signals with hiredman because hiredman has had me on his ignore list for years

14:56 RedNifre: you are correct, if you ns-unmap a, then make a new a, bla never sees the new a

14:56 hiredman: (as an aside you can actually create nameless vars, but that is a feature that isn't used ever, outside of the compiler)

14:56 RedNifre: aw, now you two are being intentionally confusing. How am I supposed to chat with people that have each other on their ignore list? :)

14:57 justin_smith: RedNifre: I don't ignore him, it's one way, just telling you he didn't understand what you were saying because he didn't see what I said

14:57 ridcully: but you could tell the one, what the other siad

14:57 RedNifre: Nah, telling one what the other said would be disrespecting the ignore list ;)

14:59 Is this var business only for the REPL? I mean, I wouldn't redefine things in regular code, right?

14:59 justin_smith: RedNifre: there is no such thing as "only for the repl" in clojure

14:59 RedNifre: there's just one compiler

15:00 RedNifre: But (def a "a") (def a "b") would seem weird to me in regular code.

15:00 what did you do to get on the ignore list? :)

15:00 justin_smith: pragmatically, I would call that bad code. But it's legal. There are no special repl-only features or rules in the clojure compiler.

15:00 RedNifre: I think I was playing with clojurebot and being a dumbass, not sure

15:01 "dumbass" probably works as a description, whatever it was

15:01 RedNifre: Yeah, I didn't mean that it would be illegal code outside the REPL, just weird.

15:02 TimMc: justin_smith: Wait, you're on his ignore list too?

15:02 justin_smith: TimMc: yup, it's quite a club we've got isn't it

15:03 TEttinger: the ignoramancer ignores most of the channel apparently

15:04 TimMc: I at least do people the favor of clearing my ignore list periodically...

15:04 RedNifre: Another thing, JoC mentions using keywords like an enum, e.g. :north :west :south :east. That seems strange to me I like the concept of an enum being a finite set of well known values. Am I being oldfashioned? Are there regular enums?

15:05 justin_smith: Java has enums, I think you can create them via interop

15:05 TEttinger: yeah, not sure how you'd make one in Clojure

15:05 justin_smith: but usually we use keywords as if they were enums if we need something like that

15:06 RedNifre: It's all so dynamic... how do you refactor that?

15:07 justin_smith: RedNifre: a lot of clojure idioms are very dynamic, borrowed from the lisp world where compile-time checking isn't really a done thing

15:07 you refactor it by changing things until it doesn't look broken any more (which is the downside of the lisp approach of course)

15:07 matt______: i was linked and read "seqs and colls", and perhaps i'm dense, but i still don't understand why vectors don't implement the seq abstraction.

15:07 you can call first, next, cons on a vector, but it goes through conversions and/or an if-else-if ladder of instanceof calls in RT to get there versus just having a method on the class

15:08 anyone know the rationale?

15:08 justin_smith: matt______: cons doesn't return a vector because vectors have no built in prepend - you need to convert to another type and then back again

15:09 matt______: justin_smith: the same is true for first and rest, right?

15:09 justin_smith: afaik, yes

15:10 matt______: yet all of those will take a vector and take a slower route than just having vectors be seqs an implement the required methods.

15:10 justin_smith: matt______: clojure will kind of steer toward things that are natively apropriate for data types, even at the price of some inconveniences, I think vectors not being a seq is part of this

15:10 like, vector not being a seq reflects the fact that you need to do a type conversion before you can do seq things to it

15:11 (even if that conversion is implicit in most idiomatic code)

15:11 RedNifre: Hm, now JoC explained metadata to me but without examples... when would I use metadata as opposed to putting things into an object? Or is that for annotating data I get from other libraries?

15:12 justin_smith: RedNifre: vars are a greate example here

15:12 ,(meta #'+)

15:12 clojurebot: {:added "1.2", :ns #object[clojure.lang.Namespace 0x7da402f4 "clojure.core"], :name +, :file "clojure/core.clj", :inline-arities #object[clojure.core$_GT_1_QMARK_ 0x2d5dbd31 "clojure.core$_GT_1_QMARK_@2d5dbd31"], ...}

15:12 matt______: justin_smith: ok. yeah, it seems like performance is the reason for not doing it. efficiently adding at the front is not doable, and even rest is... well, i'm not sure of the efficiency of subvec, but will look into it.

15:13 RedNifre: ,(-> (meta #'+) :name type)

15:13 clojurebot: clojure.lang.Symbol

15:14 RedNifre: ,(identical? + (-> #'+ meta :name))

15:14 clojurebot: false

15:14 RedNifre: ,(identical? '+ (-> #'+ meta :name))

15:14 clojurebot: false

15:14 RedNifre: ,(= '+ (-> #'+ meta :name))

15:14 clojurebot: true

15:14 RedNifre: phew

15:14 TimMc: matt______: subvec creates a window

15:15 ,(class (subvec [1 2 3 4 5] 1 2))

15:15 clojurebot: clojure.lang.APersistentVector$SubVector

15:15 matt______: TimMc: i haven't looked at the source yet, but if that's what I think it means, it's quite efficient by saying "just look between index i and j"

15:16 RedNifre: How exactly is metadata connected to things?

15:16 justin_smith: RedNifre: it's a method in IMeta, implemented using a mutable slot in the Object usually

15:16 RedNifre: Does the namespace contain a separate metadata map that has vars as keys that point to vars that point to metadata maps?

15:16 amalloy: justin_smith: no way

15:16 justin_smith: amalloy: no?

15:17 amalloy: there's no mutation for metadata

15:17 justin_smith: oh, OK, right that makes sense, my bad

15:17 amalloy: IObj/withMeta returns a new version of the object with the specified metadata

15:17 TimMc: matt______: Yeah, exactly. But it also holds onto the original, GC-wise, just like substring.

15:17 justin_smith: RedNifre: anyway, a Var implements IMeta and knows how to return its metadata

15:18 RedNifre: the namespace also holds metadata, but only about itself

15:18 ,(meta *ns*)

15:18 clojurebot: nil

15:18 RedNifre: wait, does the metadata sit in the var or in the thing the var points to?

15:18 TimMc: https://github.com/clojure/clojure/blob/clojure-1.7.0/src/jvm/clojure/lang/APersistentVector.java#L528

15:18 justin_smith: or it can, doesn't always have any

15:18 amalloy: sorry justin_smith, 0-2 today

15:18 justin_smith: amalloy: oh, man

15:18 amalloy: ,(instance? clojure.lang.IMeta #'inc)

15:18 clojurebot: true

15:18 amalloy: er

15:18 well

15:19 justin_smith: amalloy: Vars hold their metadata, not their namespaces, I know that much!

15:19 amalloy: i guess it does implement IMeta but not IObj

15:19 TimMc: aha

15:19 amalloy: so there's no with-meta for vars

15:19 justin_smith: got it, I wasn't going that far

15:20 RedNifre: ,(def pi (with-meta 2 {:description "Important number!"}))

15:20 clojurebot: #error {\n :cause "java.lang.Long cannot be cast to clojure.lang.IObj"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IObj, compiling:(NO_SOURCE_FILE:0:0)"\n :at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3657]}\n {:type java.lang.ClassCastException\n :message "java.lang.Long cannot...

15:20 matt______: TimMc: yeah, that makes sense. to me (which doesn't mean much), cons seems like the main hangup for vectors not being seqs.

15:20 justin_smith: RedNifre: 2 is not an IMeta

15:20 amalloy: yeah, i was confused since you were talking abotu IMeta and mutation earlier

15:20 justin_smith: or an IObj for that matter

15:20 RedNifre: What's IMeta and IObj?

15:21 justin_smith: RedNifre: the interfaces you must implement to use metadata in the normal ways

15:21 RedNifre: you might find it informative to look at (source meta) in your repl

15:23 TimMc: RedNifre: Metadata is stored on the object itself, it just isn't used for equality checks.

15:23 backnforth: Can someone else with out with my code.. I have a very basic clojure program thats giving me a, "Exception in thread "main" java.lang.RuntimeException: Map literal must contain an even number of forms". core.clj: http://pastebin.com/AGdXVGxM

15:24 TimMc: RedNifre: Vars are objects in their own right, and store metadata... but they also *point* oto other objects, which may or may not support metadata themselves.

15:24 RedNifre: Okay, so it's not truly that "meta", huh?

15:24 justin_smith: TimMc: just to be a donkey I could define a type right now that uses some external location to store its metadata :)

15:24 backnforth: When the remove the "listRead" function and just keep foo, the "lein run" works fine.

15:24 ridcully: ,{:a :b :c} ; backnforth

15:24 clojurebot: #<RuntimeException java.lang.RuntimeException: Map literal must contain an even number of forms>

15:25 justin_smith: backnforth: what do you think {} does?

15:25 backnforth: based on your indentation, I think you assume it works the way {} does in C/java/javascript

15:25 backnforth: Same as what imperative programs do.

15:25 justin_smith: in clojure it's only used for creating hash-maps

15:26 backnforth: Yes, justin_smith

15:26 justin_smith: ,{:a 0}

15:26 clojurebot: {:a 0}

15:26 justin_smith: backnforth: our closest analog to {} in java is (do) but usually you don't even need to explicitly use do

15:27 backnforth: I love Clojure, but damn can you be complicated sometimes.

15:27 RedNifre: I forgot, why do I have to do (meta #'+) instead of (meta +) again? Was it because (meta +) looks for metadata in a newly created + symbol whereas (meta #'+) looks in the content of the var of the namespace?

15:27 justin_smith: backnforth: this isn't complicated, it's actually simpler than the rules for other languages, just different

15:28 backnforth: justin_smith: I understand

15:28 justin_smith: RedNifre: because somebody attached metadata to the var, but nobody attached metadata to the function, hypothetically either or neither could have metadata

15:29 ridcully: backnforth: you want to find all x in inputList? then maybe filter is what you want here?

15:29 justin_smith: ,(meta (with-meta #() {:has-meta true})) ; RedNifre

15:29 clojurebot: {:has-meta true}

15:29 backnforth: ridcully: What is filter?

15:29 RedNifre: What's #() again?

15:29 ridcully: ,(doc filter)

15:29 clojurebot: "([pred] [pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects. Returns a transducer when no collection is provided."

15:29 justin_smith: ,'#()

15:29 clojurebot: (fn* [] ())

15:29 justin_smith: RedNifre: ^

15:30 RedNifre: gaah

15:30 What's fn* then?

15:30 justin_smith: RedNifre: an implementation detail of fn

15:30 RedNifre: I think my head is getting full.

15:30 justin_smith: fair enough - pretend it is fn, it might as well be in this case

15:30 RedNifre: kudos on the curiosity, btw

15:31 backnforth: ridcully: I'm looking to return the indexs, not the items

15:31 RedNifre: I'm not quite sure about the relation of # and lambdas. I mean #(println "hey") is kinda a lambda. And if #() returns () I would guess that #'+ returns '+ ? Or is that a different # ?

15:32 TimMc: RedNifre: #( is a single piece of syntax

15:32 Check out http://clojure.org/reader, it's called a reader macro. (No, you can't really define your own.)

15:33 ,'#(println "thing:" %) ; RedNifre: See how it just expands to a fn

15:33 clojurebot: (fn* [p1__143#] (println "thing:" p1__143#))

15:33 TimMc: I quoted it so you could see the expansion.

15:34 RedNifre: ,'#()

15:34 clojurebot: (fn* [] ())

15:34 RedNifre: Okay, that one makes sense.

15:34 ,#'+

15:34 clojurebot: #'clojure.core/+

15:34 RedNifre: That # is completely unrelated to #( right?

15:35 * RedNifre reads "The Reader"

15:35 TimMc: who reads the reader

15:36 RedNifre: # is a dispatch character; the next character after it determines what piece of syntax you're using.

15:38 RedNifre: Ah. I thought that #'+ means something like # '+ i.e. there's a quoted + in there, but it's actually #' +

15:39 ,(meta (var +))

15:39 clojurebot: {:added "1.2", :ns #object[clojure.lang.Namespace 0x7b99e11e "clojure.core"], :name +, :file "clojure/core.clj", :inline-arities #object[clojure.core$_GT_1_QMARK_ 0x3286c02d "clojure.core$_GT_1_QMARK_@3286c02d"], ...}

15:40 RedNifre: I think I get it now.

15:40 amalloy: RedNifre: right. i wouldn't be surirised to learn that the #' dispatch was chosen because it looks a bit like a different kind of quote

15:41 ,(:added (meta #'+)) ;; lies

15:41 clojurebot: "1.2"

15:41 RedNifre: The ":name +" part in (var +)'s metadata implies to me that two separate keys in the namespace map will never ever point to the same var. Is that correct?

15:44 It's all getting clearer... how do I print the current namespace's symbol-var-map ?

15:45 amalloy: ,(take 5 (shuffle (ns-publics (the-ns 'clojure.core))))

15:45 clojurebot: #error {\n :cause "clojure.lang.PersistentHashMap cannot be cast to java.util.Collection"\n :via\n [{:type java.lang.ClassCastException\n :message "clojure.lang.PersistentHashMap cannot be cast to java.util.Collection"\n :at [clojure.core$shuffle invokeStatic "core.clj" 6988]}]\n :trace\n [[clojure.core$shuffle invokeStatic "core.clj" 6988]\n [clojure.core$shuffle invoke "core.clj" 6988]\n [...

15:45 amalloy: so much for shuffle

15:45 ,(take 5 (ns-publics (the-ns 'clojure.core)))

15:45 clojurebot: ([primitives-classnames #'clojure.core/primitives-classnames] [+' #'clojure.core/+'] [decimal? #'clojure.core/decimal?] [restart-agent #'clojure.core/restart-agent] [sort-by #'clojure.core/sort-by])

15:46 RedNifre: ,(ns-publics *ns*)

15:46 clojurebot: {}

15:47 RedNifre: ,(def content "have to be quick")

15:47 clojurebot: #'sandbox/content

15:47 RedNifre: ,(ns-publics *ns*)

15:47 clojurebot: {content #'sandbox/content}

15:48 RedNifre: Now it's getting really interesting :)

15:49 Hang on, if the namespace is already called "sandbox" why does it say #'sandbox/content? Isn't that kinda redundant?

15:49 (sandbox/content)

15:49 ,(sandbox/content)

15:49 clojurebot: #error {\n :cause "java.lang.String cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.String cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval215 invokeStatic "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval215 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval215 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang.Compiler eval "Compiler.java...

15:49 RedNifre: ,sandbox/content

15:49 clojurebot: "have to be quick"

15:49 RedNifre: ,content

15:49 clojurebot: "have to be quick"

15:50 RedNifre: Or is that just a feature of the ns-publics function?

15:51 ,(ns-publics *ns*)

15:51 clojurebot: {}

15:54 RedNifre: Are Vars objects? If so, how can I inspect member variables and methods?

15:55 TEttinger: ,(.hashCode +)

15:55 clojurebot: 459507496

15:56 RedNifre: Is that the hashCode of the function or of the var?

15:57 ,(.hashCode (var +))

15:57 clojurebot: 1638383430

15:57 RedNifre: aha

15:58 TEttinger: ,(.hashCode #'+)

15:58 clojurebot: 1638383430

15:58 TEttinger: ,(class #'+)

15:58 clojurebot: clojure.lang.Var

15:59 TEttinger: ,(class +)

15:59 clojurebot: clojure.core$_PLUS_

15:59 TEttinger: gah this is a headache

15:59 RedNifre: Is $_PLUS_ a fake class symbolizing the native operator?

16:00 Anyway, how to list the public member variables and methods of objects, e.g. vars?

16:01 Can I look into the + Var and see a member variable pointing to the _PLUS_ function and another member variable containing a map of the metadata?

16:05 matt______: RedNifre: If you eye up https://github.com/clojure/clojure/blob/clojure-1.7.0/src/jvm/clojure/lang/Var.java ...

16:05 sdegutis: How do you match an alphabetic character of any case using Clojure regex?

16:05 I currently have this monstrosity: #"[a-zA-Z]" but I think that's not ideal.

16:06 matt______: You'll see it has root, sym, and ns fields

16:06 RedNifre: sdegutis #"(?i)[a-z]" ?

16:06 sdegutis: Hmm but isn't there something like \w ?

16:06 matt______: ,(.-ns #'+)

16:06 clojurebot: #object[clojure.lang.Namespace 0xf093f2 "clojure.core"]

16:07 matt______: Or to get what it points to, (.get #'+)

16:07 RedNifre: yeah, that's even better

16:07 sdegutis: No watch, \w matches numbers too.

16:07 Oh well I guess that's fine.

16:07 RedNifre: matt I meant from within clojure.

16:08 ystael: sdegutis: #"\p{L}" matches anything with the Unicode property Letter, I think

16:08 sdegutis: Cool, thanks.

16:08 Good day everyone.

16:08 Good day.

16:08 matt______: That (.get #'+) call is within clojure. perhaps i'm misunderstanding.

16:08 RedNifre: I meant getting a list of all public variables and methods.

16:09 A bit like when you inspect the current namespace

16:09 ,(ns-public *ns*)

16:09 clojurebot: #error {\n :cause "Unable to resolve symbol: ns-public in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: ns-public in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: ns-pu...

16:09 RedNifre: ,(ns-publics *ns*)

16:09 clojurebot: {}

16:09 RedNifre: ,(def resetting "all the time")

16:09 clojurebot: #'sandbox/resetting

16:09 RedNifre: ,(ns-publics *ns*)

16:09 clojurebot: {resetting #'sandbox/resetting}

16:09 matt______: ok, i see. i know what i'd try wouldn't work.

16:10 ,(.getMethods (class (var x)))

16:10 clojurebot: #error {\n :cause "Unable to resolve var: x in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve var: x in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve var: x in this context"\n :at ...

16:10 matt______: Whoops

16:10 ,(.getMethods (class (var +)))

16:10 clojurebot: #object["[Ljava.lang.reflect.Method;" 0x30bb067 "[Ljava.lang.reflect.Method;@30bb067"]

16:10 RedNifre: Yeah, but that's the java way. Is there an idiomatic clojure way?

16:11 matt______: not that i'm aware of, but that doesn't mean there isn't.

16:12 amalloy: see the clojure.reflect namespace

16:12 of course be aware that using reflection to peek inside of objects is taking you well outside documented APIs

16:14 RedNifre: When examining my REPL's namespace I found a clojure_two.core.proxy$java.lang.Object$SignalHandler$d8c00ec7, what's that?

16:14 type gives java.lang.Class, how can I poke it some more?

16:15 "clojure_two" is the lein project's name in which's folder I started the REPL.

16:18 matt______: amalloy: nice.

16:19 RedNifre: that's something repl-related to handling interrupts.

16:19 sdegutis: The past 20 minutes have been wasted trying to parse minified CSS via regular expressions. Let that be a lesson to you.

16:20 RedNifre: "Never touch anything related to CSS or HTML, ever", got it.

16:22 sdegutis: RedNifre: On the contrary, I wrote in about 80 lines a Clojure version of SASS or Less.

16:22 RedNifre: and it's been a huge productivity boost.

16:22 RedNifre: it's the opposite thing that's proving to be a challenge: parsing minified CSS to turn it into Clojure forms.

16:22 RedNifre: "Become a web developer today", got it.

16:22 sdegutis: RedNifre: i like ur style

16:23 RedNifre: So you can now write CSS in edn?

16:23 sdegutis: Me? Sure.

16:23 You? No. Unless you write the same 80 lines I wrote.

16:24 And I get to use everything in clojure.core, too. Yay!

16:25 RedNifre: Uh, why do you turn minified CSS into Clojure?

16:26 sdegutis: RedNifre: Because we didn't always start with Clojurified CSS. In the old days, I actually had to write plain literal CSS by hand.

16:26 RedNifre: Sure, but why is it minified?

16:26 sdegutis: RedNifre: Now I want to convert some of that to my Clojure-CSS data structures, so that I can work more quickly with it.

16:27 RedNifre: because it was minified.

16:27 RedNifre: "Minifying CSS is a destructive process", got it :P

16:27 sdegutis: Oh good point though, maybe I can find my before-minifying version of it in the git history.

16:27 RedNifre: :)

16:27 sdegutis: But that assumes I haven't altered the minified version since minifying it.

16:27 Which I vaguely remember maybe doing possibly.

16:28 RedNifre: Ah, gotta go, my head is full for today.

16:29 sdegutis: :)

16:29 RedNifre: See you guys tomorrow!

16:30 sdegutis: We'll see.

17:05 justin_smith: amalloy: I think you were wrong and the metadata on vars is actually mutable. If I use def to define something, and then cache the var with another def, then define again and add metadata, the old var still equals the var, but the var now has different metadata, and the cached var has the metadata applied now, which makes me think mutation must have happened

17:06 amalloy: oh on vars it is

17:06 and other refs

17:06 justin_smith: amalloy: yeah, maybe I was overgeneralizing before, because I was really thinking about the var case

17:06 because meta on def would be weird otherwise

17:07 amalloy: would it? def could just replace the var wholesale

17:07 but i guess that would break other code that depends on this namespace

17:07 who are hanging onto Var objects

17:07 justin_smith: it could at least, yeah

17:08 eg. running a def again would not change behavior of functions in other namespaces (unlike now), but only when you apply new metadata (which could be a line number change)

18:06 matt______: i'm trying to extend a protocol to hit arrays of any type. the primitives work, but Object[] is not catching things that derive from it. any insights?

18:10 to clarify, I can extend [Ljava.lang.Object, which works fine on (make-array java.lang.Object n), but doesn't work on (make-array java.lang.String n)

18:19 justin_smith: matt______: yeah, I don't think [Ljava.lang.String; extends [Ljava.lang.Object; so the extension won't be inherited

18:20 matt______: But it does. https://docs.oracle.com/javase/7/docs/api/java/lang/String.html

18:20 justin_smith: matt______: what about extending java.util.List instead, and doing the extra steps to get an ArrayList or whatever?

18:21 matt______: String does inherit Object, [Ljava.lang.String; does not extend [Ljava.lang.Object; - arrays are barely if at all OO

18:22 matt______: justin_smith: ah, i see what you're saying about the [L-prefixes now, ok.

18:22 justin_smith: matt______: it's not even a prefix, it's part of the name of a completely different type (that isn't even a class iirc, arrays are not like other things)

18:22 or maybe it is a Class, I forget the details

18:24 matt______: justin_smith: i will probably end up using some sort of j.u.Collection, but was hoping for the extra performance if it wasn't too difficult.

18:27 justin_smith: matt______: maybe check out Arrays/asList which returns a fixed size List that uses the array for the actual data - it's just a thin wrapper, but gives you a List which you can trivially extend with your protocol

18:27 matt______: or just make sure all the arrays are arrays of Object I guess :)

18:27 ,(into-array Object ["a" "b" "c"])

18:27 clojurebot: #object["[Ljava.lang.Object;" 0x449e153b "[Ljava.lang.Object;@449e153b"]

18:29 justin_smith: given this is clojure, you don't lose much by casting to Object anyway, it's not like we are being careful about our types in general.

18:30 matt______: justin_smith: i think you've solved it.

18:30 justin_smith: which, the asList?

18:30 matt______: well, i will look at it, but an array of Object

18:31 justin_smith: ahh, yeah, if you control the creation step of the array, that might just be your guy

18:32 matt______: just trying to make a toy data structure that mocks how clojure's work, but based on protocols and deftypes

18:32 seeing as clojure uses Object[], that seems like the way to go

18:34 justin_smith: cool project, any plans to make a blog post or tutorial out of it?

18:35 matt______: umm, maybe. i wrote up a bit about protocols mostly for my friends the other day, so this will probably grow into that eventually.

18:37 it started as "all these interfaces have 1-3 methods. how hard could it be to write something like clojure's vector in terms of protocols/deftypes?" famous last words.

18:38 justin_smith: haha, nice

18:54 amalloy: well, that's what cljs did already, right?

19:16 matt______: amalloy: yeah, except those aren't toys. :)

19:17 and a bit different, too. js arrays are a bit more flexible that java arrays, but they lose a lot to JS' typing.

19:36 ddellacosta: amalloy: is lazybot down for the count?

19:37 >

20:11 TimMc: yep

20:15 rhg135: dead. deeeeeeeeeeeeeeeead

20:35 madmax88: So has anyone has problems where a jar made with `lein uberjar` isn't writing a file, but when you use `lein run`, the program will?

20:37 My program also writes to a file with `lein trampoline run`. But, when running a jar with `lein uberjar`, the file gets created, but remains blank

20:49 found the problem: I needed to call `(shutdown-agents)`

21:07 TimMc: yuuup

21:07 although... no, I don't understand why it would have that effect

21:10 matt______: interesting: though small, the clj and cljs ISeq interface/protocol differ quite greatly! first, next, more, and cons in clojure compared to just first and rest in cljs.

21:15 amalloy: well in clojure, ISeq inherits methods from parent interfaces

21:15 in cljs the protocols are a la mode

21:15 a la carte

21:15 not covered with ice cream or modern

21:18 matt______: amalloy: sure, but it still adds two methods that need to be implemented and (roughly) renames another compared to the cljs version.

21:19 amalloy: not really. more and next are the same thing, and cons is part of another protocol that every implementation of ISeq will also implement

21:19 matt______: and if you look at the history, cljs did have both next and rest for a hot minute, but never had the oft-forgotten more.

21:20 amalloy: more and next are the same except when they're not. :)

21:20 amalloy: well yes

21:20 matt______: (not= (more (seq [])) (next (seq [])))

21:21 (that was news to me. maybe you even told me. :)

21:21 amalloy: right, more is rest, and next is next

21:21 as i recall

21:23 matt______: still interesting to see the differences.

Logging service provided by n01se.net