Fork me on GitHub
#clojure
<
2016-04-08
>
igotmine02:04:47

So, I was in here yesterday with some questions about namespaces, and I think they've only expanded over the last day or so. Are there any really basic namespace mistakes a beginner is liable to make that would prevent vars in a namespace from being accessible? Or obvious things to look for in the error message that would tell me if I'm in (or have access to, in the case of something like 'use') the namespace in question?

igotmine02:04:35

Apologies for being vague, I would be glad to provide more information on what I've specifically tried but I don't want to text dump.

hiredman02:04:14

in-ns is a very low level tool to manipulate the namespace that following forms will be compiled in the context of

hiredman02:04:06

if you (in-ns 'foo) will drop you in the foo namespace, but won't set the namespace up for easy access to the functions in clojure.core

hiredman02:04:34

and speaking of foo, outside of sort of toy examples you shouldn't use single segment namespaces

hiredman02:04:03

namespaces don't really have any kind of access control, vars in a namespace can be marked as private, which means the compiler will throw an error if you try to use them outside of that namespace, but it is hard to do that accidentally (and you shouldn't do it anyway)

hiredman02:04:19

new comers (and old salts) sometimes start thinking of namespaces as being hierarchical, but they are not, just a flat single space of names

hiredman02:04:06

namespaces are largely compile time contexts, they are used by the compiler when generating code, but not really used by that generated code at runtime

igotmine02:04:45

Hrm, I'm getting the same unable to resolve error when I use in-ns, which I guess means it has to be down to the clojure file itself, but it's just copy-paste from the ring getting started tutorial

hiredman02:04:12

don't use in-ns, unless you have already loaded the code

hiredman02:04:29

my guess would be you started a repl, didn't load your code, and can't find it

hiredman02:04:31

if you want your code to be available at the repl, you need to load, usually using 'require'

hiredman02:04:43

(require 'your-name.space)

igotmine02:04:05

One second, I am just looking over everything again because it is still not cooperating.

hiredman02:04:36

if you haven't restarted your repl since you were fiddling, I recommend you do so

igotmine02:04:39

and in the clj file itself, (ns myname.space) is sufficient, yes?

hiredman02:04:04

it needs to be on disk in a directory structure that matches the namespace

hiredman02:04:19

if you share the actual error it would be easier to tell you want is happening

igotmine02:04:28

Ok one moment

hiredman02:04:39

if require is throwing an error about not being able to find the namespace, your files on disk aren't in a directory structure that matches the namespace, or the root of that structure is not on the classpath

hiredman02:04:44

are you using lein?

igotmine02:04:53

I also tried it with cider

hiredman02:04:14

are you using the core.clj file lein makes for you when you create a new project?

igotmine02:04:56

I thought so but I realised there was a duplicate and I am moving the one I want because I think that was the problem

hiredman02:04:43

if you edited the file, make sure the namespace still corresponds to its name and place in the directory tree under src

igotmine02:04:12

And I want to be running the repl from the main project directory, correct?

hiredman02:04:39

if I recall, that doesn't matter and lein will just figure it out as long as you are in the tree

igotmine02:04:52

Still not cooperating with me, let me paste the relevant info

hiredman02:04:35

even just the message from the exception would be something

hiredman02:04:24

for long and laborious reasons, when you have '-' in a namespace name it needs to be a '_' in the filesystem, since you didn't get an error from the require, you must not be reporting what is happening correctly

igotmine02:04:32

Ok so, change all references in the filesystem from "hello-ring" to "hello_ring"?

hiredman02:04:44

no, that must already be the case

hiredman02:04:52

otherwise require would have throw an error

igotmine02:04:15

oh you're right I'm an idiot, it's path/hello-ring/src/hello_ring

hiredman02:04:19

the error you are reporting there is from the compilation of the (run-jetty ...) form

hiredman02:04:39

you have loaded the code in the require namespace

hiredman02:04:35

you need to either refer to the names from that namespace in fully qualified form, or make them available in an abbreviated form in the current namespace (the default current namespace is user, as seen in the repl prompt)

hiredman02:04:40

the easiest way to make the symbol 'handler' in the user namespace resolve to 'handler' in the namespace you required is to alter the require form to do that

hiredman03:04:03

'''(require '[your-namespace :refer [handler]])

hiredman03:04:10

something like that

hiredman03:04:36

there are dedicated functions to do it, but it is generally done using require or even more commonly using the (ns ...) form, which has the ability to run requires and other similar things for you when first setting up a namespace

igotmine03:04:52

Ok I clearly need to dedicate serious time to actually figuring these out, but that worked

igotmine03:04:01

Thank you for your help

hiredman03:04:14

http://clojure.org/reference/namespaces has some links to namespace related functions and macros, and has some namespace related documentation that is likely to wiz by without context, but just keep it handy for later

igotmine03:04:30

Yeah I had been looking at it but was not able to nail down what I was lacking

igotmine03:04:22

Though I'm now really unclear as to what use is, because I thought it was require with :refer for free

hiredman03:04:46

meh, maybe not, there is some uncovered ground between namespaces and vars

igotmine03:04:08

Oh I had not looked at the vars documentation though

hiredman03:04:34

I am not sure it would have been helpful

igotmine03:04:06

Whatever, in any case it's more information about the language I should familiarise myself with.

escherize03:04:59

is {} a macro?

hiredman03:04:09

vars are in some sense a compiler detail leaking out, but they end up being super useful

hiredman03:04:51

depends who you ask, some people would call it a reader macro (in fact clojure's reader calls { a reader macro)

hiredman03:04:05

my understanding is at least some lisps have allowed users to arbitrarily extend the reader, and that facility is traditionally called reader macros

hiredman03:04:33

clojure doesn't let users do that

escherize03:04:42

Right, I can see how {} is different from unless

hiredman03:04:57

what is unless?

escherize03:04:20

the usual defmacro example

escherize03:04:54

(unless true 1 2) -> 2 or somsuch

hiredman03:04:03

'{}' is map from the moment it leaves the reader

escherize03:04:51

so is {} more like a C kind of macro? Like where {:a 1} -> (hash-map :a 1)

escherize03:04:16

I guess it changes the ast still

hiredman03:04:35

clojure (and lisps in generally) have many more sort of phases in the lifecycle of code than C does

alexmiller03:04:36

{} is syntax

hiredman03:04:17

a traditional break down is something like read -> eval -> print

alexmiller03:04:21

macros let you take s-expression like things that are Clojure-ish and turn them into Clojure code

alexmiller03:04:35

reader macros would let you read arbitrary things that weren't s-expressions

hiredman03:04:48

{} comes out of read as a map, and is passed as a map to the evaluator

alexmiller03:04:51

the problem they introduce is that if you don't have the reader macros, you can't read the code

escherize03:04:00

I assume {:a 1} is not an s-exp then?

hiredman03:04:08

it is in clojure

alexmiller03:04:29

so Clojure constrains you, but makes things universally readable

alexmiller03:04:41

but gives you back some flexibility to create custom data with tagged literals

escherize03:04:47

I started asking because I had (comment {:a}) somewhere and it broke.

escherize03:04:09

Right - I'm familiar with tagged literals. That seems to fill the gap just fine.

hiredman03:04:11

because (comment ) is a macro, the code it comments out needs to be valid

alexmiller03:04:12

tagged literals can be read and passed on without being semantically understood

escherize03:04:16

so did {:a} break at read time

escherize03:04:28

👍:skin-tone-3: !

hiredman03:04:29

comment can only throw stuff away at macro expand time

hiredman03:04:37

and comment has to return a value

alexmiller03:04:46

#_ is another interesting read macro to throw away the next form

hiredman03:04:51

(comment ...) => nil

hiredman03:04:22

so #_ is like the reader macro equiv of the macro comment

escherize03:04:34

#_ is amazing. I started using `#_#_` like: ``` {:a 1 #_#_:b 2 :c 3}```

hiredman03:04:37

but because it is in the reader it can throw stuff out

alexmiller03:04:50

yeah, they nest so that's a good trick

escherize03:04:03

that makes a lot of sense - "reader macro" comment

alexmiller03:04:09

reader conditionals also do this trick of reading selectively

escherize03:04:11

#_{:a} will not break then

alexmiller03:04:20

it's still reading {:a}

escherize03:04:25

oh it will T_T

hiredman03:04:27

#_ throws away the next form that is read

alexmiller03:04:34

only ;; will prevent that

escherize03:04:59

thanks for the help guys

escherize03:04:13

back to reverse engineering etsy's messaging protocol for fun+profit

igotmine03:04:57

Hey so, I wanted to reiterate my thanks because I think now I've figured out how to do what I was trying to do more conveniently and in cider so the workflow makes sense

danielcompton04:04:52

@escherize: when using #_, all of the forms ‘inside it' still need to be syntactically valid, they are just discarded after being read

danielcompton04:04:10

e.g. mismatched parens and square brackets will break it

escherize04:04:30

and that's the same as with (comment ), right?

danielcompton04:04:23

yeah, I guess? I don’t really use (comment) but it makes sense it would be the same

danielcompton04:04:58

yep, just checked

seancorfield04:04:12

#_ is useful to remove a single form, (comment ..) is useful to "remove" a series of forms -- although it produces nil instead.

seancorfield04:04:22

I tend to only use (comment ..) to wrap examples of code usage when I'm thinking out loud about how things should hang together -- and you can still evaluate forms embedded in (comment ..) in Emacs with CIDER simple_smile

sveri05:04:08

@hiredman: @zentrope I must have missed the answer or something, so, did I get this right? you should not "dissoc" components on stop? Just leave it like it is if there is no shutdown function or something similar?

lmergen06:04:01

what would be the best approach to monitor the http traffic going over the wire when using http-kit client ?

lmergen06:04:09

(i'm using wireshark right now, which is suboptimal)

hiredman06:04:36

@sveri: no, the issue is, dissoc from a record turns the record in to a map, if your stop implementation dissocs from 'this' the result will be a system full of maps, no records, and you won't be able to start the system again

sveri07:04:00

@hiredman: Now as you say that, it totally makes sense, so, you say it would be better to just return the component as is in the stop function?

sveri07:04:36

OTOH, associng is ok?

plexus07:04:21

@lmergen: maybe https://github.com/plexus/tracer-gui is helpful? (shameless plug 😉)

lmergen07:04:43

oh that looks worth looking into

lmergen07:04:15

i suppose that's from the server side of things, though?

plexus07:04:28

Let me know if you have any issues with it. It still needs some polishing up

plexus07:04:31

Do you want to inspect outgoing http requests? Should be possible as well but haven't tested it

sveri07:04:48

@plexus: I will definitly add it to my web template simple_smile

plexus07:04:11

But it's definitely a use case I want to support

lmergen09:04:25

@plexus: well actually, this solves a very real problem for me as well, which is that my (strict) compojure-api specification sometimes rejects incoming requests (400 Bad Request) before I can even inspect the request in a handler.

lmergen09:04:52

so I'm probably going to hook this up with my production servers as well

len10:04:10

Hello all from South Africa simple_smile

len10:04:43

I am looking at pedestal and needing some design advice. We are trying to talk to an existing postgres database, and from a pedestal design with interceptors what would be a good way to integrate this access into the services ?

ikitommi11:04:04

@lmergen: you can intercept all request validation errors with c-api server-side too, they have type :compojure.api.exception/request-validation

Yehonathan Sharvit13:04:50

I have a question regarding keywords: In clojure, keywords can behave like functions e.g. (:a {:a 36}). How does it work?

chosenbreed13:04:29

hi folks. thinking of using one of the public images for clojure from docker hub. At a quick glance neither lein or boot seem to explicitly download or refer to clojure. Is that something that the tools handle under the covers?

alexmiller13:04:50

viebek: keywords are invokable (implement the IFn interface) as if they were a function that took an associative data structure. the implementation of that function calls get on that data structure with itself as the key.

bronsa13:04:37

@viebel: clojure doesn't have protocols at the bottom like cljs does

Yehonathan Sharvit13:04:53

So how does it work for keywords?

bronsa13:04:41

viebek: the keyword class is defined in java as extending IFn, it's not defined and then extended to IFn

bronsa13:04:11

the jvm doesn't let you extend an existing class to an interface

Yehonathan Sharvit13:04:36

So in a sense, clojurescript is more powerful than clojure!

bronsa13:04:37

classes aren't "open" as in ruby

bronsa13:04:44

in a sense

Yehonathan Sharvit13:04:59

in a sense javascript is more powerful than java!

Yehonathan Sharvit13:04:23

in a sense the browser is more powerful than the server 😂

Yehonathan Sharvit13:04:33

I’m kidding 😃

Yehonathan Sharvit14:04:09

@bronsa: what about creating a custom type that could behave as a function. Is it doable in clojure?

bronsa14:04:18

using deftype

Yehonathan Sharvit14:04:33

And implementing what protocol?

donaldball14:04:58

The clojure.lang.IFn interface

Yehonathan Sharvit14:04:17

Ok. I’m testing it...

Yehonathan Sharvit14:04:07

Hourra! The following works in clojure

Yehonathan Sharvit14:04:09

I’m writing an article about extending IFn in clojure

Yehonathan Sharvit14:04:41

I’d like to point out the differences between clojure and cljs

Yehonathan Sharvit14:04:50

the big differences are:

Yehonathan Sharvit14:04:12

1. IFn is defined in java in clj while in cljs it is defined in cljs

Yehonathan Sharvit14:04:40

2. base types are not extensible in clj; they are extensible in cljs (although it is very dangerous)

Yehonathan Sharvit14:04:52

any other differences you guys are aware?

bronsa14:04:05

base types are extensible in clj, just not to interfaces

bronsa14:04:11

you can extend String to a protocol

bronsa14:04:11

protocols are a clojure concept, interfaces a java/jvm one. protocols are open, interfaces are not

bronsa14:04:33

you can extend any type to a protocol, you can only make classes you define implement an interface

bronsa14:04:52

clojure is defined on top of interfaces, not protocols

Yehonathan Sharvit14:04:03

hmm… very interesting

Yehonathan Sharvit14:04:17

I guess that is is for legacy (or maybe perf) reasons

Yehonathan Sharvit14:04:36

I’d expect a lot of java code from clojure repo to be re-written in clojure

Yehonathan Sharvit14:04:53

I once heard about a project named: “clj in clj"

Yehonathan Sharvit14:04:01

Do you see what I mean?

mrg14:04:06

I find myself using this pattern fairly often:

(loop [thing (get-the-next-thing :with :lots :of :stupid :arguments)]
  (do (stuff :with thing))
  (recur (get-the-next-thing :with :lots :of :stupid :arguments)))
which rubs me the wrong way due to calling get-the-next-thing twice for what is the same operation. Is there a better way to get around this other than something like this:
(loop [thing nil]
  (when thing
    (do (stuff :with thing)))
  (recur (get-the-next-thing :with :lots :of :stupid :arguments)))
?

bronsa14:04:19

@viebel: I'm the author of said project

bronsa14:04:06

but it's not an an official clojure effort, and it currently only focuses on the compiler bits. what you'd want is the whole runtime to be rewritten in clojure, and that's hardly going to happen

bronsa14:04:21

and certainly not by the core team

Yehonathan Sharvit14:04:34

could you share a link to this project?

bronsa14:04:40

I don't think there's any interest at this point in rewriting clojure in clojure

Yehonathan Sharvit14:04:05

Somehow cljs made it a reality...

bronsa14:04:36

cljs has a different compilation model and lives in a completely different runtime

Yehonathan Sharvit14:04:11

thx @bronsa could you quickly go over my article to make sure I didn’t write any big inacurracies?

Yehonathan Sharvit14:04:35

It’s a honour for me to chat with CinC author!!!

bronsa14:04:25

@viebel: it's correct, if you replace clojure with clojurescript simple_smile

bronsa14:04:17

yeah, it's really nice

Yehonathan Sharvit14:04:19

I think it’s great for education/blogs etc...

Yehonathan Sharvit14:04:29

Do you know any good communication channel I could use to let the community know about KLIPSE

Yehonathan Sharvit14:04:42

I have tried in the google groups but it was not a success.

nkraft14:04:19

@viebel: Seems like the clojurescript and announce-to-everyone channels here would be the right place to announce or ask that question.

dominicm14:04:47

@viebel are you viebel on the klipse blog?

Yehonathan Sharvit14:04:04

I made a type on clojurians 😞

dominicm14:04:24

I've been reading all your posts, you're definitely making a splash with KLIPSE.

mrg14:04:55

@viebel: it may intereste you to know then that Klipse murders mobile safari and crashes my rss reader (ReadKit)

Yehonathan Sharvit14:04:11

I know and I have fixed it a couple of hours ago

mrg14:04:20

Hey, neat! Thanks!

Yehonathan Sharvit14:04:27

@mrg: please confirm that it works on safari now

bronsa14:04:52

first item

mrg14:04:25

Yes, it seems fine on mobile safari now!

mrg14:04:35

I'm not at home so I can't look in my RSS reader!

Yehonathan Sharvit14:04:19

@mrg Could you give me a confirmation over twitter when you are home?

mrg14:04:41

I'll try to remember simple_smile Will be awhile though

mrg14:04:02

Thank you for fixing that!

slipset19:04:19

a bit late to the party, but I’m golfing around with leftpad

slipset19:04:39

I’ve got this one, but it doesn’t quite feel right:

slipset19:04:05

(defn lp [s l p] (apply str (concat (repeat (- l (count s)) (or p " ")) s)))

slipset19:04:02

don’t you need to dec l in your recursion?

digioi19:04:52

I was assuming that l was the defined length of the string

digioi19:04:01

it would pad until the string is that length

slipset19:04:12

sorry, my bad

digioi20:04:42

if you want to make it so you will always have say 2 spaces in front , you could decrement l in the recursion but change the comparitor to (> l 0)

hiredman20:04:34

http://accidentallyquadratic.tumblr.com/post/142387131042/nodejs-left-pad brings up some things to think about writing left-pad in a language with immutable strings

hiredman20:04:58

(the whole blog is great)

codonnell21:04:36

does anyone know if there are alternatives to drawbridge for securely running a repl in a production server?

curtis.summers21:04:17

@codonnell ssh tunnel with port forwarding?

codonnell21:04:53

@curtis.summers: that would work! thanks for the suggestion.

nooga21:04:02

provided that nrepl listens at localhost

hiredman22:04:07

I thought I saw someone used an ssh library to make a repl you could directly ssh in to

codonnell22:04:43

that would be interesting

codonnell22:04:32

I'm not sure adding an extra dependency would be worth it to avoid ssh tunneling with port forwarding