#clojure log - Feb 29 2008

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

0:13 Chouser: Well, that worked. Ugly as sin, but it worked. Bedtime.

0:45 ericthor: anyone having problems with meta data in the latest build?

0:46 (def #^{:a "tag"} f 1)

0:46 (meta f)

0:46 yields nil

5:45 arbscht: is there a clever naming convention for clojure-relevant projects?

5:50 bgeron: something with a J in the middle maybe?

5:50 arbscht: j is worth 8 points in scrabble

5:50 this is not easy to do

14:50 Chouser: clojure is just too much fun

15:05 hoeck_: what are you doing with clojure?

15:20 Chouser: Screen-scraping web pages to generate email notifications.

15:21 But what makes it fun is the ease with which I can invent a task-specific mini-language and use it mixed in with regular clojure code.

15:22 Once I've got the generic HTML/XML parsing and querying, URL parsing, and email functions all set up, the specific task at hand can be written in under 50 lines

15:23 That's navigating through three pages, picking up context as I go, parsing the final page, generating a little report, and sending it off as email.

15:28 anyway, fun.

15:28 :-)

15:29 rhickey_: almost finished with proxies, which will let you derive from a concrete/abstract class

15:29 Chouser: rhickey_: cool! I'll be happy to banish my few lines of Java.

15:31 hoeck_: are there situations in clojure where one will need this?

15:31 Chouser: need to derive from an Java class?

15:31 rhickey_: it's forced by some library designs

15:31 hoeck_: yes

15:32 rhickey_: they fail to use interfaces

15:32 Chouser: I need it in order to use the javax.mail package. I don't think I would ever try to use it in the design of a clojure app.

15:34 hoeck_: oh, luckily, i never touched such a library where i need to subclass something

15:36 Chouser: heh, ew. Is there a better way to do this: (. mystr (replaceAll (str "[ " (char 160) "]+") " "))

15:37 I've got these annoying char 160s I want to treat like whitespace. I think they're  s or something.

15:37 Anyway, the regex \s doesn't match them.

15:54 hoeck_: chouser: you could use \u00A0 in the regex

15:54 nsinghal_: i want to see if m2 is subset of m1.

15:54 (defn subset? [m1 m2]

15:54 (= (select m1 (keys m2)) m2))

15:54 I wanted this to work for any structure passed in, list, vector, maps

15:54 I tried converting it to the sequences and then do the comparison.

15:54 (defn subset? [m1 m2]

15:54 (let [s1 (seq m1)

15:55 s2 (seq m2)]

15:55 (every? #(let [item = %] (some #(= item %) s2)) s1)))

15:55 This function returns REPL:1749: Bad binding form, expected matched symbol expression pairs. What is wrong here?

15:55 rhickey_: item = % is bad syntax

15:56 nsinghal_: sorry let me try agina

15:56 Chouser: hoeck_: ok, that would be a bit better.

15:59 arbscht: \xA0 rather

16:09 nsinghal_: user=> (= {:a 1} {:a 1})

16:09 true

16:09 user=> (= (first s1) (first s2))

16:09 false

16:09 user=> (first s1)

16:09 <:a 1>

16:09 user=> (first s2)

16:09 <:a 1>

16:09 user=> (= (first {:a 1}) (first {:a 1}))

16:10 true

16:10 When i am comparing (= (first s1) (first s2)) it returns false

16:10 (first s1) evaluates to <:a 1> and (first s2) evaluates to <:a 1>

16:17 hoeck_: nsinghal: i guess comparing "< >" is not implemented yet

16:17 Chouser: how are you setting s1 and s2? I used two separate defs, and (= (first s1) (first s2)) returns true for me.

16:18 hoeck_: chouser: i used two literal maps, it returned false

16:18 nsinghal_: (= (first (seq {:a 1})) (first (seq {:a 1})))

16:18 this evaluates to true

16:18 (= (first (seq {:a 1 :b 2})) (first (seq {:a 1 :b 2})))

16:18 this evaluates to false

16:23 Chouser: ok, I see. Pretty squirrley.

16:23 true: (= (first {:a 1}) (first {:a 1}))

16:23 false: (= (first {:a 1 :b 2}) (first {:a 1 :b 2}))

16:28 rhickey: map entries don't have value semantics (yet)

16:29 but you should always be careful with (first amap), unless it's a sorted map

16:30 Chouser: careful in what way?

16:30 nsinghal_: when we convert map to seq each seqeuence can have different order

16:30 rhickey: there's no guaranteed order

16:30 Chouser: I'm not comparing map entries, but I'm using first and rest to iterate

16:30 nsinghal_: but if we cache the seqeunce and perform the match - still returns false for comparison

16:30 (def s1 {:a 1 :b 2})

16:30 (def s2 {:a 1 :b 2})

16:30 (= (first s1) (first s2)

16:30 (= (first s1) (second s2))

16:30 both returns flase

16:31 but you answered that is is not value checking MapEntry

16:31 rhickey: right, not yet

16:31 nsinghal_: (defn subset? [m1 m2]

16:31 (every? #(let [item %] (some #(= item %) (seq m1))) (seq m2)))

16:32 rhickey: I'm not happy with Map.Entry as a base - may switch map entries to pairs

16:32 nsinghal_: nested #() forms is bad style - too hard to read

16:32 hoeck_: rhickey: and the '<>' sharp brackets? are they used for reading map entrys?

16:33 rhickey: no - there is no read syntax for map entries

16:33 yet

16:33 nsinghal_: somehow it is fun to right hard code in Clojure but I will stay away from thius

16:33 thx

16:34 rhickey: as I said, I think I'd rather switch to pairs than elevate map entries to first-class status

16:35 nsinghal_: that will be nice, map entries sound like part of a map while you can have list, sequence etc for pairs

16:35 rhickey: yeah, they aren;t more useful than [k v]

16:36 nsinghal_: thx

16:36 hoeck_: i was just puzzled by the output of (first {:a 1}) being <:a 1>

16:37 Chouser: Just today I wanted to use map to process both parts of a map entry.

16:37 rhickey: You can do destructuring of map entries already using [k v]

16:38 Chouser: ah, that's cool.

16:38 oh! I can use that...

16:39 ah, very nice.

16:41 hoeck_: destructuring in let and fn is really nice

16:41 rhickey: I still have to add it to loop

16:43 hoeck_: but i found out, while using clojure i am sticking more to the functional paradigms of lisp

16:44 Chouser: those immutable data strcutres are keeping you honest, aren't they.

16:44 rhickey: you pretty much have to

16:44 :)

16:44 hoeck_: as opposed to common or emacs lisp where i loved (and love) the loop and iterate macros

16:44 rhickey: loop in Clojure is completely functional

16:45 Chouser: using scala broke me of needing looping structures. It's recursion or (map/reduce/filter) for me.

16:46 rhickey: Isn't Scala less functional than Clojure?

16:47 Chouser: eh. Scala allows some less functional code, but it too provides mainly immutable data, and fully supports tail recursion, map/reduce/filter, and for-comprehension.

16:47 you can use while loops and Java mutable containers if you really want to.

16:48 rhickey: but Scala itself also has mutable variables and members, not just in the Java interop, right?

16:49 Chouser: yeah, you can declare a "var" instead of a "val", but that seems roughly like "def" instead of "let".

16:50 Not sure about class data members -- didn't do much with that, but I think it's essentially the same-- pick an immutable "val" or a mutable "var".

16:50 rhickey: I don't think so - given a Scala object can you know that it is safe to treat it as a value, i.s. that it is immutable?

16:51 If anywhere in the member chain there's a var, you can't

16:51 Chouser: Right, I'm not sure if that info is carried in the type system or not. I think probably not.

16:52 rhickey: mutable data scares me much more than lack of a 'type system"

16:52 Chouser: I haven't written anything big in Scala (or Clojure, for that matter) to become familiar with the interaction of more complex types.

16:53 I'm still ambivalent about static types. I *think* what I want is optional static typing, but I'm not sure.

16:54 Scala requires types, and I often found myself fighting to correctly declare what I new to be functionally correct code, or distorting my design to make up for static typing (or my lack of understanding of its type system).

16:54 s/new/knew/

16:58 what's the best way to test if x is empty, when x may be a map or a list of map entries?

16:58 rhickey: (seq x)

16:58 Chouser: (nil? (seq x)) works, but is it slow for a large x?

16:59 rhickey: no - seq is constant time for everything

16:59 Chouser: splendid, thank.

16:59 thanks.

17:00 rhickey: (when-not (seq x)... better than (when (nil? (seq x)) ...

17:01 Chouser: for performance or readability?

17:01 rhickey: readability, more idiomatic, the return value of seq is directly testable by if, that's an important idiom

17:02 Chouser: ok

17:02 I'm in a cond. I'll re-arrange...

17:02 rhickey: in a cond, ok

17:04 Chouser: I'm finding I like cond even when I could use if, just because I can mark the :else clause more clearly.

17:05 rhickey: interesting - pg took else out of cond and called it if in arc

17:05 Chouser: heh, yeha.

17:06 is there a common idiom for where to put terminal case in recursion? First, last, doesn't matter?

17:07 rhickey: I usually follow the positive test - if there's stuff to do, do it, (else) return

17:08 Chouser: ok

17:13 ericthorsen: when passing java objects to clojure do i need to wrap them in something?

17:13 rhickey: nope

17:13 ericthorsen: just checking

17:13 rhickey: primitives will get boxed when passing to invoke as Object

17:14 which is what Clojure expects to see

17:14 ericthorsen: just wanted to make sure clojureVarInJava.fn().invoke(new MyJava())

17:14 was all i needed

17:15 rhickey: just use clojureVarInJava.invoke(...), don't use fn()

20:08 rhickey__: proxies are up! - you can now derive from concrete classes dynamically

20:16 * Chouser tries it out

20:16 albino: Is a concrete class a class written and compile in java?

20:16 rhickey__: It's a class that's not an interface

20:17 but yes, it must be named and therefore from Java-land

20:18 for instance you could derive a proxy from javax.mail.Authenticator

20:19 and override getPasswordAuthentication()

20:22 Chouser: hm, sounds familier...

20:28 ha! just like that. worked perfectly first try.

20:28 rhickey__: great!

20:28 Chouser: thank you!

20:28 rhickey__: sure - it was the most frequently requested missing feature

20:28 Chouser: that code in proxy.clj's pretty scary.

20:29 rhickey__: Welcome to compiler writing

20:33 actually at ~200 lines of serious stuff, it's much more compact the kind of code that takes Compiler.java to 3500

20:40 albino: Is that an actual file Compiler.java?

20:41 rhickey__: yes, part of the Clojure source

20:41 albino: ahh, okay

20:41 I thought you were referencing jdk7 source code or something

20:42 rhickey__: no, just me in Java vs me in Clojure

20:43 albino: yeah

20:43 rhickey__: you pretty good with cL?

20:43 err CL

20:43 rhickey__: ok

20:44 It was my first Lisp love...

20:44 albino: rhickey__: have you thought about porting clojure to CL?

20:44 rhickey__: clojure started in CL

20:44 albino: oh cool

20:44 does that version still exist in some source control tool somwhere?

20:44 rhickey__: Originally it was CL that generated Java and C# source

20:45 Everything source-wise is on SF, all the design stuff is on my Macs

20:46 Clojure never targeted CL though

20:47 It has changed a bunch over the years, a lot of work preceded its release in October

20:48 Chouser: The first release was just in October?

20:48 rhickey__: yup

20:49 Chouser: How much have you written in Clojure, not counting parts of Clojure itself?

20:49 rhickey__: mostly Clojure

20:49 that's the bane of the compiler writer

20:50 Chouser: :-) yeah.

20:50 albino: rhickey__: so you've been working on it on your own for years, and just got around to releasing it recently?

20:50 rhickey__: I am very excited about using it for the rest of my work

20:51 Chouser: what is that other work?

20:51 If I may ask.

20:51 rhickey__: yes, worked for years to solve the Lisp+Java/.Net problem - see jFli, Foil, Lisplets etc

20:52 My other work is audio research, cochlear modeling, scheduling systems etc

20:52 Chouser: huh! ok.

20:53 pjb3: Is there a way to have one clojure script load another clojure script?

20:54 rhickey__: load-file

20:54 albino: wow, never heard of jFli before, looks cool

20:57 Chouser: neither \xA0 nor \u00A0 work in my string literal

20:57 So I guess I'll continue using (str (char 160))

21:27 pjb3: Is there something like load-path and require in clojure?

21:27 where load-path is all of the places clojure looks for files to load

21:27 and require loads them, making sure not to reload already loaded files

21:28 rhickey__: not yet, it has been suggested

21:29 pjb3: ok, it seems like that would be helpful for organizing larger projects, what do you think?

21:30 rhickey__: I think that loading and requiring are going to be separate

21:31 pjb3: what do you mean by that

21:32 rhickey__: that loading should not be a side-effect of requiring, requires can be analyzed to create a load system definition

21:38 pjb3: So would (require "foo") load foo.clj?

21:40 ericthor_: are you referring to parsing and finding all the refers for a set of files to determine a load order?

21:41 what about qualifier names? name-sapce/func-call

21:41 rhickey__: So would (require "foo") load foo.clj -> no

21:41 pjb3: then what does (require "foo") do ?

21:41 ericthor_: "requires can be analyzed to create a load system definition" ...how?

21:42 we were discussing this today and ran into the question on knowing about other namespaces not in the 'refers' calls

21:43 we were discussing this today and ran into the question on knowing about other namespaces not in the 'refers' calls

21:43 I'm ready to do it!

21:43 rhickey__: a program could be analyzed for refers and requires to determine the dependency graph and generate a loading plan

21:44 ericthor_: but it would need to analyze the use of qualified names as well...yes?

21:47 rhickey__: no - if you use qualified names without refer you will need a require

21:48 ericthor_: I cannot say n1/foo without a (require 'n1) ?

21:49 i know it works if n1/foo is loaded...is it not 'proper' clojure?

21:50 rhickey__: there is no such thing as require yet, we're just speculating, but the loading system will need it

21:51 ericthor_: that was my next question....

21:52 that would not be an unreasonable requirement IMHO and at least is something we can do and use now even if the requires is just used for a dependancy graph

21:52 i like it...it's simple

Logging service provided by n01se.net