2016-03-09
| 00:27 | TEttinger | TimMc: you have no idea how often I use toBinaryString and toHexString, haha |
| 00:27 | TEttinger | I use a lazybot as a calculator and any binary stuff needs that |
| 00:58 | ilevd | Hi, I find strings like "{{#list}}" "{{#render}}" in Java project html files, what's that framework or lib? |
| 01:08 | rhg135 | Mustache |
| 01:12 | ilevd | Thanks a lot! |
| 01:36 | AndreasO | (run :dispose), what does it do? |
| 01:40 | ilevd | It depends on library, where is this used? |
| 01:47 | AndreasO | In a seesaw example. |
| 01:52 | TEttinger | AndreasO: depends on what run is |
| 01:54 | TEttinger | in all the examples I see that's commented out, AndreasO |
| 01:55 | TEttinger | it looks like defexample defines the run fn https://github.com/daveray/seesaw/blob/master/test/seesaw/test/examples/example.clj |
| 01:58 | AndreasO | TEttinger: strange, I found an example here it wasn't commented out |
| 01: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 |
| 02:00 | TEttinger | that's only in the examples |
| 02:13 | AndreasO | https://github.com/juliangamble/clj-seesaw-examples/blob/master/src/seesaw/test/examples/clock.clj |
| 02:13 | AndreasO | There it is, not commented out. |
| 02:56 | ilevd | Are you happy with Clojure? |
| 02:58 | opqdonut | it's nice enough |
| 02:58 | ridcully_ | for the larger part |
| 03:00 | TEttinger | yes |
| 04:15 | prohobo | clojure is hard yo |
| 05:04 | prohobo | anyone know how to dynamically add a field to the frame using seesaw? |
| 05:18 | prohobo | hello? |
| 05:18 | clojurebot | BUENOS DING DONG DIDDLY DIOS, fRaUline prohobo |
| 05:21 | prohobo | god damn you clojurebot |
| 05:21 | saureb | lol |
| 05: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) |
| 05:25 | krl | (in lein) |
| 05:30 | Empperi | it uses the classpath declaration |
| 05:30 | Empperi | which is passed for java on startup |
| 05:32 | krl | can you dump it somehow from the repl? |
| 05:34 | Empperi | (System/getProperty "java.class.path") |
| 06: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 |
| 06:58 | jonathanj | amoe_: according to the source, that function is only available if you're running java 7+ |
| 07:04 | amoe_ | jonathanj: I am indeed running java 7 |
| 07: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 |
| 07:09 | jonathanj | rather, it's the version the README says to use |
| 07:09 | jonathanj | looks like it was added quite a long time ago: https://github.com/Raynes/fs/commit/fdab09a711f6fd457bcdf13d213c6dea79c31241 |
| 07:10 | amoe_ | oh, that makes sense, thanks! I will find a workaround. |
| 07:11 | jonathanj | maybe file an issue about releasing a new version? |
| 07:11 | amoe_ | jonathanj: yup, I will do so. |
| 07:12 | amoe_ | oh, actually one already exists https://github.com/Raynes/fs/issues/102 |
| 07:13 | amoe_ | 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 |
| 07:32 | prohobo_ | im not getting any closure on my seesaw issue |
| 07:33 | prohobo_ | i am emotionally exhausted |
| 07:41 | amoe_ | prohobo_: maybe paste the code? |
| 07:42 | prohobo_ | nah, its okay |
| 07:42 | prohobo_ | im too tired to deal with it today |
| 08: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))) |
| 08:21 | amoe_ | I know that's basically a function but I'd like to avoid making another function as it's in a test |
| 08:23 | Kneiva | There is nothing wrong in making a function just for a test. |
| 08:24 | amoe_ | Kneiva: just my taste but I prefer to keep test code as flat as possible |
| 08:43 | TMA | amoe_: you can use unnamed functions: ((fn [var] (do-something var) (do-something-else var)) (large-operation)) or a (let [var ...] ...) |
| 09:00 | Malnormalulo | amoe_: If you reeeeeally want to avoid non-test namespace-accessible artifacts, you could always just make liberal use of `letfn` |
| 09:01 | Malnormalulo | which can, itself, contain test defs, so that your tests become closures |
| 09: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? |
| 09:15 | zenoli | l.* |
| 09:15 | zenoli | Whoops, sorry. |
| 09: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 |
| 09:57 | egli | RedNifre: maybe with lein-try |
| 09:57 | egli | |
| 09:58 | egli | 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 | RedNifre | Bookmarked for later, thanks egli. |
| 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 | Malnormalulo | (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 | RedNifre | 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 | RedNifre | Wait, what does (new Integer) mean in Clojure? |
| 11:24 | RedNifre | (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 | RedNifre | more serious idea: something something foldr / reduce ? |
| 11:37 | narwhal01 | RedNifre, is the better idea? |
| 11:37 | narwhal01 | 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 | RedNifre | mavbozo It's in 3.2 |
| 11:55 | RedNifre | hang on |
| 11:55 | RedNifre | I think I might have missread that. |
| 11:56 | RedNifre | 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 | RedNifre | 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 | MJB47 | 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 | RedNifre | ,(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 | RedNifre | Is Integer.MIN_INT -1 also called an "overflow"? |
| 12:59 | justin_smith | RedNifre: maybe underflow, but I think it throws OverflowError |
| 12:59 | justin_smith | ,(dec Integer/MIN_VALUE) |
| 12:59 | clojurebot | -2147483649 |
| 12:59 | justin_smith | err |
| 12:59 | justin_smith | ,(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 | justin_smith | 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 | justin_smith | one moment |
| 13:01 | justin_smith | ,(/ (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 | RedNifre | Hm. |
| 13:01 | RedNifre | So no underflow exception there... |
| 13:01 | justin_smith | RedNifre: Math/ulp gives the closest non-equal value to a given double |
| 13:01 | justin_smith | RedNifre: that's not an underflow |
| 13:02 | justin_smith | 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 | justin_smith | underflow is about small numbers, not low negative numbers |
| 13:02 | justin_smith | d'oh |
| 13:03 | justin_smith | 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 | justin_smith | haha |
| 13:04 | justin_smith | 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 | RedNifre | I guess an Integer can overflow at both ends then, but never underflow. |
| 13:06 | justin_smith | yeah, that sounds right |
| 13:07 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | RedNifre | It's also homoiconic, so the call object will contain the AST of what was passed as parameters. |
| 13:15 | RedNifre | 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 | RedNifre | 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 | justin_smith | 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 | amalloy | (def size :size) ... (size the-map) |
| 13:23 | amalloy | 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 | RedNifre | 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 | RedNifre | ,(: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 | justin_smith | 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 | RedNifre | (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 | mmastic | Thank you everybody ^^ much appreciated. |
| 13:34 | RedNifre | Hang on.. Ruby has something called an ostruct. |
| 13:34 | RedNifre | That sounds like what you want. |
| 13:34 | RedNifre | You can add arbitrary keys to it, but when you try to retrieve an undefined one you get an error (I think). |
| 13:34 | RedNifre | Maybe something like that exists for Clojure? |
| 13:35 | justin_smith | RedNifre: this is what records do |
| 13:35 | justin_smith | except for the error part |
| 13:35 | justin_smith | ,(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 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | RedNifre | mmastic but why do you need a getter function if not for compiler checks? |
| 13:43 | mmastic | Yeah, they are. |
| 13:43 | mmastic | 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 | justin_smith | 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 | TimMc | (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 | justin_smith | 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 | justin_smith | ,: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 | justin_smith | mmastic_: I already demonstrated that above |
| 13:59 | justin_smith | RedNifre: ahh, sorry, misunderstood |
| 13:59 | justin_smith | 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 | justin_smith | mmastic_: plus the ability to implement interfaces and protocols, yes |
| 14:00 | justin_smith | 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 | TimMc | and of course if you implement protocols everything goes haywire with code reloading, but you already get that with protocols |
| 14:02 | TimMc | (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 | justin_smith | 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 | justin_smith | ,@(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 | justin_smith | ,#'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 | justin_smith | ,'#'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 | justin_smith | so the above expansions via ' help? |
| 14:07 | RedNifre | ehm |
| 14:07 | justin_smith | RedNifre: #'foo is a shortcut for (var foo) |
| 14:07 | justin_smith | @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 | RedNifre | 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 | RedNifre | 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 | justin_smith | without looking it up in the namespace map every time |
| 14:13 | justin_smith | 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 | justin_smith | 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 | hiredman | 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 | hiredman | 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 | hiredman | 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 | RedNifre | 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 | hiredman | 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 | hiredman | 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 | hiredman | 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 | hiredman | so when the function is running, it never does a map lookup |
| 14:29 | hiredman | it can find all the values it needs just by dereferencing the vars |
| 14:30 | hiredman | derefencing the vars is a simpler operation than a map lookup, so the jvm's jit is better able to optimize it |
| 14:30 | hiredman | (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 | hiredman | (let [x (resolve 'a)] (fn [] (Vector. @x @x @x))) |
| 14:33 | hiredman | 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 | justin_smith | *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 | hiredman | 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 | justin_smith | 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 | hiredman | 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 | 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 | matt______ | 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 | hiredman | 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 | hiredman | 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 | RedNifre | 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 | hiredman | 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 | RedNifre | 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 | justin_smith | 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 | RedNifre | 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 | justin_smith | 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 | RedNifre | 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 | justin_smith | RedNifre: I think I was playing with clojurebot and being a dumbass, not sure |
| 15:01 | justin_smith | "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 | justin_smith | 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 | matt______ | 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 | matt______ | 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 | justin_smith | 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 | justin_smith | (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 | justin_smith | ,(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 | TimMc | ,(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 | justin_smith | RedNifre: the namespace also holds metadata, but only about itself |
| 15:18 | justin_smith | ,(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 | amalloy | 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 | justin_smith | 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 | justin_smith | 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 | RedNifre | 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 | justin_smith | 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 | TimMc | Check out http://clojure.org/reader, it's called a reader macro. (No, you can't really define your own.) |
| 15:33 | TimMc | ,'#(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 | RedNifre | ,#'+ |
| 15:34 | clojurebot | #'clojure.core/+ |
| 15:34 | RedNifre | That # is completely unrelated to #( right? |
| 15:35 | TimMc | who reads the reader |
| 15:36 | TimMc | 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 | RedNifre | ,(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 | amalloy | ,(: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 | RedNifre | 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 | amalloy | ,(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 | RedNifre | Hang on, if the namespace is already called "sandbox" why does it say #'sandbox/content? Isn't that kinda redundant? |
| 15:49 | RedNifre | (sandbox/content) |
| 15:49 | RedNifre | ,(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 | RedNifre | ,(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 | RedNifre | ,(.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 | RedNifre | Anyway, how to list the public member variables and methods of objects, e.g. vars? |
| 16:01 | RedNifre | 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 | sdegutis | 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 | sdegutis | 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 | sdegutis | Good day everyone. |
| 16:08 | sdegutis | 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 | RedNifre | A bit like when you inspect the current namespace |
| 16:09 | RedNifre | ,(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 | matt______ | ,(.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 | matt______ | ,(.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 | amalloy | 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 | RedNifre | type gives java.lang.Class, how can I poke it some more? |
| 16:15 | RedNifre | "clojure_two" is the lein project's name in which's folder I started the REPL. |
| 16:18 | matt______ | amalloy: nice. |
| 16:19 | matt______ | 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 | sdegutis | RedNifre: and it's been a huge productivity boost. |
| 16:22 | sdegutis | 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 | sdegutis | You? No. Unless you write the same 80 lines I wrote. |
| 16:24 | sdegutis | 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 | sdegutis | 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 | sdegutis | 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 | amalloy | 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 | justin_smith | because meta on def would be weird otherwise |
| 17:07 | amalloy | would it? def could just replace the var wholesale |
| 17:07 | amalloy | but i guess that would break other code that depends on this namespace |
| 17:07 | amalloy | who are hanging onto Var objects |
| 17:07 | justin_smith | it could at least, yeah |
| 17:08 | justin_smith | 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 | matt______ | 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 | justin_smith | 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 | justin_smith | 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 | justin_smith | matt______: or just make sure all the arrays are arrays of Object I guess :) |
| 18:27 | justin_smith | ,(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 | matt______ | 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 | matt______ | 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 | matt______ | 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 | ddellacosta | > |
| 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 | madmax88 | 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 | madmax88 | found the problem: I needed to call `(shutdown-agents)` |
| 21:07 | TimMc | yuuup |
| 21:07 | TimMc | 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 | amalloy | in cljs the protocols are a la mode |
| 21:15 | amalloy | a la carte |
| 21:15 | amalloy | 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 | matt______ | 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 | matt______ | (that was news to me. maybe you even told me. :) |
| 21:21 | amalloy | right, more is rest, and next is next |
| 21:21 | amalloy | as i recall |
| 21:23 | matt______ | still interesting to see the differences. |