#clojure log - Aug 30 2009

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

0:22 * technomancy is having a lot of fun with clj-processing: http://p.hagelb.org/myu.png

0:33 liebke: technomancy: very cool image! I just posted a blog entry on using Processing from Clojure: bit.ly/VPCvF

0:34 technomancy: liebke: cool! I noticed you're moving some of Incanter over to that?

0:35 love the header on that site btw.

0:35 liebke: Yeah, Processing provides a lot of flexibility for creating visualizations

0:35 thanks :)

0:36 technomancy: liebke: why did you fork clj-processing instead of adding it as a dependency? did you need to modify it too much?

0:36 I contacted the clj-processing author; he seemed to be fairly open to contributions.

0:37 liebke: yeah, I go into some of the changes I made in that blog entry. The biggest change was I wanted the PApplet argument to all the functions to be explicit instead of binding it to *applet*

0:38 technomancy: liebke: is that because you want to be able to juggle multiple applets at once?

0:38 seems for regular processing visualizations it's nice to not have to think about that

0:40 liebke: btw; I think you have the titles of the books mixed up

0:40 liebke: I agree, the binding approach makes the api look more like the "real" Processing API, but it made it difficult to figure out which functions could be called outside of the PApplet's methods.

0:40 Ah, thanks... let me fix that

0:41 technomancy: I'm not sure what I think of the multiple versions (-float, -int) of some of the core processing functions; seems awkward

0:42 also I suggested allowing use of keywords instead of defing all the myriad Processing CONSTANTS

0:42 liebke: that's why I merged those functions

0:42 yes, keywords is a great idea

0:45 technomancy: also I abstracted away the applet proxy: http://github.com/technomancy/clj-processing/blob/32f26eee13cf5b516f0ac4f33d7ade501a04b0aa/src/rosado/processing/applet.clj

0:45 anyway, I wonder if it wouldn't be worth sharing code since I'm probably going to continue hacking clj-processing and you might want to pull in those updates.

0:46 liebke: nice approach

0:46 there, fixed the book titles, thanks for pointing that out

0:46 technomancy: maybe make your non-binding applet functions in a layer on top of clj-processing so the codebases don't have to diverge.

0:47 liebke: hmm, interesting idea

0:47 technomancy: of course... handling dependencies in Clojure is not always a lot of fun. =\

0:48 but it's worth considering

0:48 I'm using Corkscrew for my Processing sketchbook experiments and it's not bad: http://github.com/technomancy/sketchbook/blob/6313522c8127a7d896e3d50347ec31b55484c411/project.clj

0:48 liebke: I think it's a good idea

0:50 andyfingerhut: I've used clojure.contrib.trace/deftrace for tracing some Clojure functions, but I was wondering if there was something more like Common Lisp's trace/untrace available, where you can enter an expression at the REPL that enables/disables tracing for the named fn?

0:53 technomancy: liebke: well, I better take off. looking forward to seeing more on Incanter.

0:53 that's some good stuff you've got going on.

0:53 bye!

0:53 liebke: Thanks, goodnight

0:55 andyfingerhut_: Or do people perhaps just change "defn" to/from "deftrace" and redefine the function? Or maybe people don't use tracing?

4:57 Nate75Sanders: in the clojure-dev screenshots on the clojure-dev webpage, do they have spell-checking disabled?

7:05 ambient: are Waterfront and Light the only text editors done in Clojure? I really like Emacs/SLIME but would like to see a simple REPL implementation done with Clojure. I can do so much with REPL that I might just not need a separate text editor at all. Adding paredit style editing to that and jumping to functions etc would probably work very well.

7:06 also i've been wondering how well would binding namespaces to directories and instantly saving everything defined in a REPL to a file work

7:51 ole3: ambient: what is Waterfront and Light?

9:10 ambient: ole3: http://sourceforge.net/projects/waterfront/ and http://code.google.com/p/lighttexteditor/

9:23 wlr: rhickey: re: juxt naming. Semantically comp does a math composition. Doesn't juxt semantically do a math right-distribution? So, maybe "rdist" would be an ugly but meaningful alternative.

9:30 rhickey: wlr: I think function composition is much more widely known. rdist wouldn't be meaningful to me. Have you got a reference link for right-distribution?

9:33 wlr: rhickey: http://en.wikipedia.org/wiki/Distributivity

9:33 rhickey: distribution makes me think of probability distribution, and this is not distributivity

9:34 wlr: i know. overloaded terms always present problems. distibuted programming is another.

11:13 rhickey: wlr: sorry, had to step away. ok, I could see how you could consider this right-distributive if you presume there is some concat operation between the fns and apply to the argset - ((juxt a b) x) === (a concat b) applyto x == (a applyto x) concat (b applyto x)

11:17 still not buying rdist though

11:17 :)

11:19 cemerick: rhickey: you were right on with the isa? usage :-/

11:19 rhickey: cemerick: oh good

11:19 cemerick: heh. I did a :facepalm: when I verified it. I should have caught that early on.

11:23 rhickey: direct isa? usage isn't actually discouraged though, is it?

11:25 rhickey: not at all, I was just concerned as you talked about it in the context of multimethods. I wonder though that Java isn't doing more caching of its own to support isAssignableFrom. So far I haven't cached myself in the reflection code

11:26 you should use isa? in preference to (contains? supers x) if possible

11:26 isa? asks a direct question while supers needs to gather

11:26 cemerick: I definitely don't use supers directly at all.

11:27 The typical usage is (isa? (type foo) ::some-keyword)

11:27 rhickey: ah

11:30 cemerick: ...and our primary hierarchy has our set of entity interfaces being derived from higher-level 'types'...so the typical case has supers being called on a class object in every invocation of isa?

11:30 rhickey: got it, that's not going to be very fast unless you route it through a multimethod

11:31 cemerick: yeah...which I obviously don't want to do :-)

11:37 angerman: is there a markdown parser for clojure?

11:43 j-dot: angerman: I'm not sure, but I believe the documentation generator for Clojure Contrib now supports markdown. I would check there.

11:44 kotarak: angerman: there is markdownj

11:44 angerman: http://sourceforge.net/projects/markdownj/

11:51 angerman: hmmm > 2000loc ok

11:51 Chouser: &v

11:51 sorry

11:53 cemerick: rhickey: I've got a WeakHashMap-based memoize fn, and a patch to apply that memoization to supers (also easily applicable to bases, to help anyone using parents). Is this something you'd consider for inclusion?

11:53 The safety issue isn't really something I can determine conclusively.

11:54 rhickey: no, I'm quite leery of WeakHashMap

11:55 also I recommend against memoizing or otherwise dynamically binding standard fns

11:56 cemerick: OK -- is there a better approach I can take? It works well enough for us so far, but we have more control over execution environment, etc., than some.

11:56 rhickey: you can of course use your own memoized wrapper fns

11:57 cemerick: Don't worry, I am :-)

11:57 I'd just like everyone to get the same benefits, if possible.

11:58 rhickey: sure, but the macro you posted scares me

11:58 cemerick: heh

11:59 that was just something I posted so others could easily see what the delta would be for their code.

11:59 rhickey: one possibility is to ask a hierarchy to cache a relationship, as a function of the hierarchy

12:01 are you using your own hierarchy or the global one?

12:01 cemerick: oh, just the global one

12:02 Chouser: cemerick: on real Java classes only, right?

12:02 cemerick: Chouser: as opposed to fake ones?

12:02 ;-)

12:02 Chouser: heh. as opposed to keywords.

12:02 rhickey: it would be relatively straightforward to have the global hierarchy cache isa? keyed on the identity of the hierarchy, as do multimethods

12:03 Chouser: or symbols

12:03 rhickey: Chouser: it's the relationships between real classes and keywords that aren't cached/fast

12:03 Chouser: oh, ok.

12:03 rhickey: cemerick: The typical usage is (isa? (type foo) ::some-keyword)

12:04 cemerick: Chouser: just classes (interfaces, actually), and namespaced keywords

12:04 Chouser: ok, ok. Sorry for slowing down the discussion.

12:04 cemerick: rhickey: wouldn't isa? caching have the same issues as memoizing supers, etc?

12:05 ambient: anyone want to help me with my newbie problem ~20 lines with Java interop? http://paste.lisp.org/+1UK7 I just can't figure out what's causing the error

12:06 rhickey: cemerick: which issues? class unloading? hierarchy modifications?

12:06 cemerick: rhickey: Yes :-)

12:06 rhickey: they ar edifferent

12:07 cemerick: actually, supers memoization doesn't affect hierarchy mods, as that's only dealing with classes

12:07 * cemerick steps away for 20 min, sorry

12:08 Chouser: ambient: that is indeed odd. You can try (def synth (MidiSystem/getSynthesizer))

12:08 ambient: that is indeed odd. You can try (def synth (MidiSystem/getSynthesizer))er

12:08 er

12:09 (def #^Synthesizer synth (MidiSystem/getSynthesizer))

12:09 ambient: I can't test that because I'm getting Unavailable expecetions, but it might help.

12:10 tashafa: ,((fn [& v] (apply + v)) 1 2 3)

12:10 clojurebot: 6

12:10 ambient: ok, seems that that did the trick :) I already tried type hints but seems I put them in the wrong place

12:10 thanks

12:11 Chouser: ambient: it shouldn't be necessary though. It seems you may have found a discrepency between the compile-time reflection and the runtime reflection code.

12:13 ambient: might just be that my Emacs repl is somehow broken

12:13 Chouser: ambient: what's the specific class of Synthesizer that you get?

12:13 ambient: MixerSynth, but I get it both ways

12:13 with or without type hints

12:14 Chouser: right

12:14 you would.

12:14 what package is that in?

12:14 ambient: javax.sound.midi

12:15 iirc

12:15 Chouser: ,javax.sound.midi.MixerSynth

12:15 clojurebot: java.lang.ClassNotFoundException: javax.sound.midi.MixerSynth

12:15 Chouser: ,(class (MidiSystem/getSynthesizer))

12:15 clojurebot: java.lang.Exception: No such namespace: MidiSystem

12:15 Chouser: ,(class (javax.sound.midi.MidiSystem/getSynthesizer))

12:15 clojurebot: javax.sound.midi.MidiUnavailableException

12:16 Chouser: heh. no playing of midi on clojurebot's server...

12:16 maybe com.sun.media.sound.MixerSynth

12:16 JAS415: oh man, does clojurebot do techno now?

12:16 Licenser: dun dun dun :)

12:17 rhickey: java.lang.IllegalArgumentException: Can't call public method of non-public class: public javax.sound.midi.MidiChannel[] com.sun.media.sound.AbstractPlayer.getChannels()

12:18 ambient: some JRE's are missing the soundbank from their folders though. don't know about JDK's

12:18 tashafa: ,((fn [& v] (apply + &v)) '(1 2 3))

12:18 clojurebot: java.lang.Exception: Unable to resolve symbol: &v in this context

12:19 tashafa: ,((fn [&v] (apply + &v)) '(1 2 3))

12:19 clojurebot: 6

12:19 rhickey: better message with the latest it seems, but this explains why the call must go through the interface via hints (the 'weird reason' the latter works is that the call to static method yields a return value of known type to the compiler)

12:19 the def'ed synth is just Object to the compiler

12:22 tashafa: ,((fn [&v] (apply + &v)) 1)

12:22 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer

12:23 tashafa: sorry i'll go play in my repl now :)

12:26 Licenser: Is there a way to get some more epxressive messagesion from the REPL?

12:26 I've seen some nice stuff in the videos, where an exception sayed which line it came from and showed a little stack trace

12:27 ambient: well if someone has that, then i need to get some too!

12:28 swdunlop: There are a couple nice hints about stack traces at http://jackndempsey.blogspot.com/2009/07/opening-your-mind-with-clojure.html

12:51 Licenser: swdunlop: thanks

12:51 swdunlop: Glad to help. :)

13:00 rlb: ISTR someone mentioning something like and-let*. Does clojure have something similar?

13:13 swdunlop: rlb: Interesting form.. Just read SRFI-2. I haven't seen anything like it in Clojure..

13:14 rlb: I supppose condp :>> is at least a bit related.

13:18 swdunlop: It would be an easy macro to write, just depends on how you wanted to handle the nonlocal exit.

13:18 I'm assuming just cheating and doing (let [...] (and ...)) is unsatisfactory. :)

13:21 cemerick: I wonder why Rich is uncomfortable with WeakhashMaps

13:29 LauJensen: Good evening gents

13:30 swdunlop: Evening.

13:34 rlb: swdunlop: right, it's just a syntactic sugar. And actually I was really thinking of the case where you need the value of an if guard in the true clause.

13:34 s/true/then/

13:35 Chouser: I haven't looked -- is that different from if-let?

13:35 rlb: Chouser: ahh, perhaps that's what I was thinking of (and maybe it was you who mentioned it before...). I'll look.

13:36 Chouser: Looks like that's exactly it. Thanks.

13:37 swdunlop: Chouser: It's similar. Sort of a chained if-let.

13:37 rlb: (and by exactly it -- exactly what I was thinking of)

13:38 swdunlop: If I'm understanding if-let correctly, it permits you to bind the result of the test clause to if to a variable, then use that result in the branches, correct?

13:39 Chouser: in the 'true' branch anyway

13:40 swdunlop: and-let* binds each clause in a shortcutting and form.

13:40 Chouser: yeah, only the true branch.

13:40 if-let can sometimes interact nicely with destructuring, since the latter is only attempted in the true case.

13:42 swdunlop: Yeah. I can see how if-let could be a useful idiom, too. I tend to do a lot of (let [x ..] (if x ..)).

13:42 and-let is a more general form of if-let, I believe.

13:42 rlb: Is there an idomatic way to build up a map with optional elements? Of course I know you can build the map with the non-optional elements, and then conj or assoc the optional ones.

13:43 swdunlop: rlb: Like struct v. struct-map ?

13:43 Chouser: rlb: I've run into that a few times. also with seqs for vectors, but I've not seen a pleasant way to handle it.

13:44 swdunlop: I'm a Clojure newbie myself.. Coming over from Mosquito. :)

13:44 Chousuke: if the optional elements have default values, you could have a constant map to use as a base.

13:44 rlb: Chousuke: right. I'm talking about cases where the elements shouldn't exist if they don't have a value.

13:45 i.e. you can do (conj m (if x [:x x] []) ...), but I wondered if there was something better...

13:45 Chouser: for lists and vectors, you can abuse ` and ~@ ...but that doesn't work for maps.

13:45 rlb: Chouser: ok, thanks.

13:45 Chouser: , `[:a 1, ~@(when true [:b 2]), :c 3]

13:45 clojurebot: [:a 1 :b 2 :c 3]

13:46 Chouser: , `[:a 1, ~@(when false [:b 2]), :c 3]

13:46 clojurebot: [:a 1 :c 3]

13:46 Chouser: , `{:a 1, ~@(when true [:b 2]), :c 3}

13:46 clojurebot: 5

13:46 Chouser: uh

13:46 try that last one yourself. It don't really return 5

13:48 rlb: I suppose you could also just write the whole construction as one conj with if clauses for the optional members, though presumably that might be a bit less efficient.

13:48 Chouser: anyway, thanks.

13:49 Chouser: rlb: so I don't know anyway but to it using conj or assoc after-the-fact. Even then it ca be a bit messy.

13:49 ,(-> {:a 1, :c 3} (#(if true (assoc % :b 2) %)) (#(if true (assoc % :d 4) %)))

13:49 clojurebot: {:d 4, :b 2, :a 1, :c 3}

13:50 rlb: Right. I was just using (let [x {...}] (conj x (if ...) (if ...))).

13:51 Chouser: ,(into {:a 1, :c 3} (concat (when true [[:b 2]]) (when true [[:d 4]])))

13:51 clojurebot: {:d 4, :b 2, :a 1, :c 3}

13:52 Chouser: hm, conj is better than into/concat

13:52 Chousuke: how about a "maybe-zipmap"? :P

13:52 Chouser: rlb: yeah, that's the best I've seen yet.

13:53 ,(conj {:a 1, :c 3} (when false [:b 2]) (when true [:d 4]))

13:53 clojurebot: {:d 4, :a 1, :c 3}

13:53 Chouser: no good for vectors or lists, but good to keep in mind for maps

13:54 rlb: Chouser: "when" is an improvement.

13:56 Chouser: conj isn't using transients (yet)

13:56 rlb: Chouser: since if guarantees nil when else is missing, if would be fine without an else clause too.

13:57 Chouser: yes. My understanding is that using 'when' is the preferred style when there is no else clause. *shrug*

13:58 rlb: yeah, that's fine.

15:14 ankou: hi, what do I need to do to tell slime where to find clojure?

15:14 *on linux

15:26 juhal: hi, can anyone explain why this fails

15:26 (let [hello #(println %)] (eval '(hello "world")))

15:26 but this doesn't

15:26 (let [hello #(println %)] (hello "world"))

15:27 or how I can make the former work?

15:27 rlb: juhal: I haven't use eval in clojure, but I would suspect that eval doesn't evaluate in an envt where hello is visible.

15:28 i.e. hello's a local binding, and eval doesn't operate in the local scope.

15:28 but I'm just guessing.

15:29 In guile for example, IIRC, local-eval might do what you seem to want.

15:30 juhal: there doesn't seem to be local-eval in clojure

15:30 dreish: juhal: What are you trying to do?

15:31 rlb: dreish: (yes, better question)

15:34 juhal: I'm writing a clojure based DSL for configuring a system. The configuration contains settings where I want to evaluate arbitrary expressions. Those expressions contain calls to domain specific functions.

15:35 dreish: So why are you trying to create them with let instead of defn?

15:36 Nevermind. Here's the closest alternative in Clojure:

15:36 (declare hello)

15:37 (binding [hello #(println %)] (eval '(hello "world")))

15:37 rlb: juhal: also note that if you have any security/safety concerns, you'll need some kind of restricted reader -- either an envt with no unsafe functions (if that's possible in clojure), or your own (hopefully fairly simple) sexp parser.

15:38 Chousuke: hm, can't you just bind *read-eval* to false?

15:38 rlb: Again, in guile, for example, you can create an empty environment and then populate it with whatever you want, then call eval in that envt. I don't know if clojure has something similar.

15:39 Chousuke: ah, never mind, that would only allow you to read the config, not eval it :/

15:39 rlb: Chousuke: would that prevent someone from calling "rm -rf /"?

15:39 in the config file?

15:39 That's what I was wondering about.

15:39 i.e. can you create an eval environment in clojure that's "safe"?

15:40 Chousuke: rlb: well, it'd basically disallow any evals from just reading the config.

15:40 rlb: for whatever your definition of safe is.

15:40 Chousuke: so you can at least read the file safely.

15:40 rlb: Ahh. The nice thing about the "safe envt" approach is that it makes it much easier to use the language itself as a config file, even for things where safety might matter.

15:40 Chousuke: evaling it safely is trickier. probably needs code-walking.

15:41 because of .

15:41 rlb: Chousuke: or the ability to create an environment that just doesn't have any unsafe bindings...

15:41 i.e. (eval foo safe-envt)

15:41 Chousuke: that's not possible in Clojure at the moment

15:41 because of . :)

15:41 rlb: or (load foo safe-envt)

15:41 Chousuke: though you *can* use the java sandbox...

15:41 rlb: Chousuke: right, you'd have to omit . from the envt.

15:41 Chousuke: ,(System/exit 0

15:41 clojurebot: EOF while reading

15:42 Chousuke: ,(System/exit 0 )

15:42 clojurebot: java.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.0)

15:42 Chousuke: but that's still DOSable

15:42 rlb: Chousuke: ahh, I wondered about that -- perhaps that's an alternate approach in some cases.

15:43 Chousuke: well, even the safe-envt approach I was talking about is probably DOSable, depending on your criteria.

15:43 (unless it has no loop constructs, input limits, etc. ;>)

15:44 Chousuke: it might be useful to be able to arbitrarily disallow some special forms and reader macros...

15:44 but that probably needs clojure-in-clojure :)

15:44 juhal: I'm not too concerned with the security issues at this point. I just want to make it work. I was looking for something like the local-eval thing guile has.

15:45 rlb: juhal: could you not just load the file and use macros, etc. to build the DSL?

15:45 or do you need something sufficiently different from clojure itself, language-wise?

15:45 juhal: I tried that but the macros got too complicated for a lisp newbie like me

15:45 rlb: (i.e. is the DSL not sexp based, etc.)

15:46 juhal: so I ended just parsing the sexps

15:47 anyway dresish's workaround seems ok if not elegant

15:47 thank's for the suggestion

16:01 sigh the binding trick didn't work when going through a proxy object

16:01 when will I ever learn not to try anything fancy

16:16 rlb: Is (seq some-set) the appropriate way to convert a set to a list?

16:17 Actually, maybe that's not what I meant to do...

16:27 hiredman: rlb: seq returns a sequence, not a list

16:52 hamza: hey guys, i have a vector of keywords i would like to append them in to string one after another, how can i a turn a keyword to a string?

16:54 LauJensen: ,(name :foo)

16:54 clojurebot: "foo"

16:54 Chouser: ,(apply str [:foo :Bar :baz])

16:54 clojurebot: ":foo:Bar:baz"

16:58 hamza: thx that works.

16:58 one other thing why i can't i use name in apply?

16:58 ,(apply name [:foo :bar :baz])

16:58 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$name

16:59 Chouser: name takes just one arg

16:59 arbscht: because that effectively calls (name :foo :bar :baz)

17:00 Chouser: (apply str (map name [:foo :bar :baz]))

17:00 ,(apply str (map name [:foo :bar :baz]))

17:00 clojurebot: "foobarbaz"

17:01 hamza: kk so map applies the function one by one but apply passes the whole vector right?

17:02 LauJensen: ,(doc apply)

17:02 clojurebot: "([f args* argseq]); Applies fn f to the argument list formed by prepending args to argseq."

17:02 LauJensen: ,(doc map)

17:02 clojurebot: "([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]); Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments."

17:03 hamza: thank you.

17:08 LauJensen: np, if you're running emacs you can fetch those docs straight in your slime-repl

17:10 hamza: i am using emacs but using inferior lisp, i will check out slime heard a lot about it.

17:42 is it possible to do a post request from clojure or do resort to urlconnection?

17:51 arbscht: hamza: there are http libs in clojure.contrib

17:52 rlb: hamza: this might help http://gnuvince.wordpress.com/2008/10/31/fetching-web-comics-with-clojure-part-1/

17:53 hiredman: that is an old tutorial, so watch out

17:54 hamza: thank you.

17:54 rlb: This will open a stream on a url: (with-open [in (.openStream (URL. address)) ...)

17:55 You might also be able to use duck-streams reader/writer, but I'm not sure offhand.

18:55 krumholt__: at the start of my file i use (ns my.namespace (:use some.lib)) but i am not able to load my file with (load-file myfile.clj) until i add a line (refer 'some.lib). that should be redundant because i already said (:use ...?

19:02 cark: should be (ns my.namespace (:use [some.lib]))

19:03 cemerick: (:use foo.bar) is just fine

19:03 as is (:require foo.bar)

19:03 cark: hum ok

19:04 i've always put these in a vector ...for what reason i don't know

19:05 cemerick: I generally do as well, as (:require [foo.bar :as baz]) is most idiomatic

19:07 cark: anyways to answer the question, yes it is redundant

19:10 krumholt__: hm but it is not working without the call to refer

19:10 maybe i need to put it in a vector

19:11 cark: mhh maybe your some.lib file is not at the right place

19:11 what's the error you get ?

19:11 krumholt__: unable to resolve symbol

19:12 cark: hum you need double quotes around the filename here (load-file myfile.clj) ?

19:12 krumholt__: yes have that

19:13 it starts to load the file and then complains that it cannot find a function

19:13 from some.lib

19:13 cark: that's strange, you'd get an error if the lib was not used

19:14 krumholt__: i just add the line (refer 'my.lib) and everything works

19:16 it's not that much of a problem. i mean it works in the end i was just wondering what the underlying problem could be

19:33 Chouser: if file a.clj had (ns a (:use b)), you should not need a (refer b) in that same file.

19:34 if some other place (file c or a repl) does (load-file "a.clj"), you still can't use the names from b until you do (refer b)

19:38 krumholt__: Chouser, ok thanks that explains it. i can't load-file from the repl

19:48 pluijzer: Can a function that relies upon a external constant variable be considered a pure function?

19:51 Can a function that relies upon a external constant variable be considered a pure function?

19:51 rathore_: i dont see why not

19:53 pluijzer: well the functions then has a "relevant environment"

19:58 hiredman: well, if it is really constant...

20:06 pluijzer: yes 4, 6 and pi are really constant too, but what if it relied upon a constant global variable, the function could behave differently in different programs.

20:06 hiredman: that is not a constant

20:07 pluijzer: okay

20:07 so no :)

Logging service provided by n01se.net