This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-25
Channels
- # aws (2)
- # bangalore-clj (2)
- # beginners (90)
- # boot (89)
- # bristol-clojurians (1)
- # cider (23)
- # cljs-dev (48)
- # cljsjs (2)
- # cljsrn (3)
- # clojure (118)
- # clojure-argentina (3)
- # clojure-austin (8)
- # clojure-czech (1)
- # clojure-dev (18)
- # clojure-ireland (1)
- # clojure-italy (4)
- # clojure-russia (6)
- # clojure-spec (75)
- # clojure-uk (224)
- # clojurescript (103)
- # core-async (28)
- # cursive (3)
- # datascript (7)
- # datomic (15)
- # dirac (30)
- # emacs (14)
- # events (3)
- # figwheel (1)
- # hispano (1)
- # hoplon (176)
- # lambdaisland (1)
- # lein-figwheel (6)
- # off-topic (21)
- # om (7)
- # onyx (2)
- # pedestal (6)
- # re-frame (4)
- # reagent (15)
- # spacemacs (67)
- # specter (13)
- # testing (9)
- # untangled (65)
- # vim (6)
- # yada (1)
@paulspencerwilliams which predicate were they complaining about for instance?
@thomas I intentionally used the examples from the clojure.spec guide so attendees could read further. The arg predicate was
(s/and (s/cat :start int? :end int?)
#(< (:start %) (:end %)))
ok... I thought that int? was quite obvious... once you know that is convention, but that is a small thing IMHO.
Bore da
I suppose there's a few problems with that when not used to lisp.
the function syntax, the cat, the #, as you say, what's the significance of ?. It's just syntax.
I can see the lambda in there being hard for a non lisper to understand. I've come across int?
or similar in C style languages so wouldn't have thought that was a problem. I could see Spec cat
causing some head scratching...took me a while for that to sink in!
@paulspencerwilliams I find it's the lack of syntax that causes confusion. Things like ?
on a predicate is just idiomatic but not enforced this takes a while for people to understand. For example, *
around a dynamic var is just convention but noobs often think it's how you tell the compiler the var is dynamic.
@agile_geek agreed. It's familiarity.
Sometimes lisp syntax's strength is it's weakness too, we often need structure and constraints to help our pattern matching biased brains make sense of things quickly. It's why I would actually like to see a 'sane' framework implemented in Clojure. I spend far too much time asking or telling what the idiomatic approaches should be. If not a framework then more books and guides like Clojure Applied that can be adopted as idiomatic approaches (note I avoided saying 'patterns' so as not to upset people who have an OOP driven fear of the word!)
@agile_geek do you think a tool like kibit could help here? suggesting what style to use.. (if that is possible at all)
@thomas only at the lowest level
agile_geek I'm still a bit unclear about what your particular style (or design?) issues are
Doesn't take long to learn what fn's to use...although I keep forgetting them! It's the medium sized things that are typically patterns in OOP
I still learn new core functions after several years of clojuring... so many hidden gems in that.
@agile_geek is that not a concern of architecture, as opposed to one of others to enforce what is proper for your project?
I kind of like the non-framework status, as it allows me freedom to think through my problem & solve it how it all fits.
Here's a non exhaustive list, a lot of which I have 'an' answer too but it's not clear to me if it's a 'good' answer: 1 How to structure namespaces 2 How to pass resources through a fn stack without introducing dependencies for fn's that don't need the resource. (e.g. connections) 3 How to keep concerns separate without using 'objects' - I find this particularly painful in CLJS! 4 How to communicate data structure 'shape and type' - this is a huge issue (that can partially be solved with Spec/Schema before someone shouts but teams need to actually use them!) ..... not got time to list more but there are plenty @dominicm Yes and No. I keep seeing arguments about differing style and convention that end up in a dogs dinner. I'd rather structure imposed from a position of authority as a starting point to provide consistency and structure with the freedom to change it easily later if things don't fit Basically, I'm not clever. I can't, and don't want to, reinvent the wheel everytime I want a bloody web app! I just want to get sh*t done.
We aren't paid to write code, we are paid to deliver value
Maybe 28 years of solving the same problems a different way every 1-2 years has made me jaded
didn't Eric Normand(?) say something like that the way your code should be organised be the same as your problem (or solution)
I agree...although I haven't watched Erics talk yet. I think the namespace equivalent of Simon Brown's 'services as packages' approach in Java works well.
1. I don't understand this question, could you expand a little? 2. This seems like you want function passing (pass me a function that when called makes Q query) 3. function passing again! Or channels. https://www.reddit.com/r/Clojure/comments/5e7w0p/no_ceremony/daddlt5/ 4. I've worked on projects that are over-schema'd, so I think this is something that just depends on what people have used. I think that on some projects it's not appropriate to introduce spec/schema yet, so it's good it isn't forced.
good luck @agile_geek and don't worry... and if getting you (day) job takes priority... so be it. we are not going to hold it against you 😉
Morning
my @agile_geek answers:
[1] can be challenging, and tools like potemkin can be helpful, but i'm not sure there is a definitive answer any more than to the "how to structure OO classes" question - sure, there are bad solutions, but there is rarely a single 'right' solution
[2] pass a context map down through your stack... use schema or spec to enforce the keys/values a particular fn requires, and ignore other keys... reader monad could be another way to go to achieve similar without adding the context maps to your fn signatures, but i haven't really investigated
[3] i find this less of a problem with clj/s than with OO languages - mostly everything is mediated with plain old simple data, and where it isn't it's easy to give anything a map-like or deref interface, so concerns can stay out of each others junk
[4] spec/schema at component boundaries seems to do quite well here
@mccraigmccraig Having said I'm too busy...can't resist replying. Firstly, these are all my starting approaches on these problems, so nice to have some validatation! Secondly, this was all a little bit of a leading question(s) as all of these things are really about establishing and communicating approaches, i.e. as in all IT, it's a people problem. Most of the pain I'm seeing is due to people not agreeing and/or communicating this stuff well. So.....we should have a 'patterns' book/guide for all this somewhere. You don't have to follow them but they're a good starting point.
If the right person wrote an "Effective Clojure" book, I would buy it.
a leading question @agile_geek - i am shocked 😱 !
@peterwestmacott who is the right person?
@dominicm seemed quite willing last night 😉
ducks for cover
@agile_geek If I knew - I'd hassle them directly
Maybe that would prompt them to write the book!
I volunteer @mccraigmccraig
Fortunately, it's never going to be me!
@dominicm we are having a talk on Integrant by weavejester (James Reeves) on March 7th at the London Clojurians. I'll publish the talk soon
@glenjamin I would say as a rule of thumb, reduce the dependencies of fn's on other fn/resources (SRP) and group fn's in namespaces based on 1st functional area (business context), 2nd it's function (i.e. modeling, I/O, etc)??
agile_geek in some ways SRP doesn't feel right at the level above the function. It is more about how to partition an app between pure things and side effecting things (though it works itself out in SRP in the functions)
this is the kind of thing I feel that Rich was talking about the Language of the System
@otfrom wouldn't you still want to organise function in areas (ns?) if only so you can find what you're looking for or if you want to carve them off into there own module/service later?
agile_geek I would, but it partly depends on what the functions are doing and if they are domain related or not
To me SRP is valid at all levels - and is a principle that has nothing to do with FP, OOP or any other P
(and I generally err on the side of having repeated code until you know that the similarity is real rather than accidental)
I would agree
your understanding of SRP is probably deeper than mine then. I've mostly seen SRP applied at the class/method or function level
but that's a separate conversation about deferring design decisions to the appropriate moment
and for me the dividing line is more around things that are referentially transparent and things that are side effecting in addition to grouping things according to domain/module/service/etc
I'm a bit of an essayer (tryer) when it comes to designs, so I suppose that design moment for me is probably after having thought, repl'd and built at least one version
I think we are actually on the same page
If you remember my tweet about a personal insight into data and design this is an aspect of the blog or blogs I want to write
@otfrom actually as I think it may take several drafts and I may have to write a whole series of posts before I can write the abstract intro one I was thinking of using you and @krisajenkins as peer review. But don't worry if you're too busy as I don't mind just foisting my opinion on everyone without checks and balances! 😈
(tho I'll have a look, can be hard to comment quickly on things that make me think tho)
@agile_geek publish to blog.... nothing like exposure to public ridicule to galvanise the attention.
agile_geek I think you'll find that jasonbell is going to say bad things about your stuff regardless, so you might was well publish something that feels like a draft or stream of consciousness
@otfrom and you think I actually take Jade's opinion into account?
But, if @agile_geek is going to keep the Jade malarky going on then I might just change my mind
how does one discover one's True Name ™️ ?
hi hi 🙂 Is there a way to build strings without having to quote special chars? i.e, I've got a bunch of bash script snippets.
@jasonbell you must not have learned an important lesson in school... Never let the school bully know he's getting under your skin, Jade
mattford this looks interesting (not used it) https://github.com/sunng87/shake
this is the one from pallet https://github.com/pallet/stevedore
at least in core, but core is very conservative and most things happen in libaries (spec being a weird exception)
@mccraigmccraig to find one’s true name just get @agile_geek email reply to autocorrect your name wrong.
Any rational human would apologise for the indirect error..... @agile_geek suggested I change my name to deed poll so he could dodge admitting there was an error. Hence he’s called me Jade via email ever since.
hmm - I was hoping to avoid having to quote the quotes but that still looks to be the case in pallet/stevedore
mattford can you give us an example of what you have to do and what you'd like it to look like?
(let [result (ssh session {:in "echo \"SONAUGHTY\" | sudo -S /bin/bash -l -c \"ls -l\"")})]
(let [result (ssh session {:in @echo "SONAUGHTY" | sudo -S /bin/bash -l -c "ls -l"@)})]
ah, so the problem is the general string quoting inside clojure rather than having to quote the shell things
I wonder if the approach like @krisajenkins yesql would work for this https://github.com/krisajenkins/yesql
so that's similar to slurping a file and letting it take care of the quoting (I think)
Wanted to build the strings though a bit more dynamically. Was exploring how clojure could be used like Python's Fabric.
not really. Fabric let's the user write stuff like this run("ls -l")
or sudo("ls -l")
as a Python like DSL for running over a list of hosts. Was trying to mimic the Sudo function. The clojure code with clj-ssh looks very similar to what Fabric does (syntax aside).
Speaking of proof-reading @agile_geek (and @otfrom) - anyone want to give this the once-over for me? http://blog.jenkster.com/2017/01/theres-immutable-and-then-theres-immutable.html
@krisajenkins might not have time for a day or two but I'm happy to critique in retrospect! 😈
@krisajenkins looks fine to me - though i did wonder about the second meaning of 'isomorphic' which i'm not aware of - another footnote ?
Oh, thanks yes.
Out of interest, what’s the one you know?
(And thank you for taking a look so quickly! 😄 )
How do you mutate a scala.collection.immutable.List ?
@krisajenkins an app running the same language front & backend (obvs there are mathematical isomorphisms too, but i'm thinking of isomorphic apps)
@peterwestmacott Allowing for syntax: listyMcListface[0].setName(”Hugmaster”)
@mccraigmccraig Then you know both. Haskellites will fight to the death for the real meaning of isomorphic. 😄
ah, ok 🙂
so the list object is immutable, but the objects within it are not?
Exactly. 😞
okay, no new surprises then - I'm not sure that it reads like that in your blog post
I resisted the temptation to say, “cargo cult immutability."
I inferred that the list object could be changed
(ie. mokeypatched or some-such)
Ah, thanks. I’ve updated to make that a bit clearer. 🙂
Okay, the ship’s left port. Thanks folks! https://twitter.com/krisajenkins/status/824285852037771264
(...though pedantically, if they put an immutable object into the list then they are fine, perhaps "it’s still mutable" -> "it still might be mutable")
oh - I guess that train has sailed...
Ha, gonna hedge it: > No special guarantees there - it's still mutable as it was before.
Sometimes a hug is just a fight trying to move.
Just catching up on todays chat… FWIW: I agree with @agile_geek’s list - not because there aren’t good solutions to these problems, but because they are things people I’ve onboarded have struggled with. Not sure if any of you saw Zach Tellman’s Elements of Clojure… the sample chapter developed idea's of naming things quite well… not seen the follow on chapters. I remember it because at the time he announced it I was thinking about how best to structure namespaces so that they communicate the architecture of the application - questions like do you cut it horizontally/vertically etc, and make the single pass compiler work for you rather than against you etc… IIRC I traded some emails with him on the topic - not sure if he’s decided to talk about that though.
@krisajenkins I don’t generally think of JS as having pointer-like semantics
I do fairly often get asked whether it’s pass-by-reference or pass-by-value by C people, and have to explain how it’s neither
No? Equality implemented as a test on memory address. (And so, for instance, sets that compare on the value of the pointer, rather than the thing it points to.)
there are immutable primitive values, and objects. Objects are mutable, “variables” are locally scoped names for those
But what’s identity, if not the same effective semantics as pointer-equality?
(I’m not saying they’re actual hardware pointers-to-memory, just that they behave the same way.)
That’s exactly what I find odd - all the downsides of pointer semantics, none of the control.
(Not that I want that control. But I don’t want the semantics either.)
I can understand why it’s like that, I can’t understand why any new language defaults to identity for eqality
I…can’t any more.
You can’t.
or at least, why shouldn’t I be able to check that they are and receive and affirmative
You can’t in the general case, I mean. That’s proven, I believe.
Can’t prove they express the same relation? That sounds like something someone would prove
If you have access to the source code, I think that’d be different.
@rickmoynihan I've read Elements of Clojure another source I'd recommend along with Clojure Applied
krisajenkins & glenjamin I consider java and javascript to do all passing by value, it is just that the value for things that aren't "primitives" is the value of the pointer
That is a novel way of looking at it. 😛
I think of it as pass by reference, except some primitives are magic.
@glenjamin proving functions equivalence is impossible
Really?
glenjamin: yeah IIRC it’s basically the halting problem in the general case.... obviously you could compare byte/source code is identical
in the general case, sure, but functions being equal via identity and lisp forms being equal lexically seem useful in some cases
agreed
(I'm agreeing with @otfrom, just clarifying that it's actually a fact and not just an opinion)
@bronsa I knew that ... I knew that...
@glenjamin yeah, and that happens in the jvm
Oh…it’s pass-by-value, except nearly every value you’re passing is a transparently a reference. Well the lawyers may win that one, but I don’t think justice has been done.
I have in the past implemented a variation of defn which captured the lexical scope and hashed it for such things… was far from perfect because it didn’t recursively do it, or walk values of bound vars.
@glenjamin if it were pass-by-reference you'd be able to do things java doesn't actually support
@krisajenkins it's pass by value because if you reassign a new value to your 'reference' it only impacts your copy of the reference... unlike in pointers
Is the reference actually copied in JS/Java? I’ve always pictured it as the callee getting a new local name for the same reference
@glenjamin I think it's a real copy
or at least, the jvm acts as if it was actually copied for real, the copy is likely optimized away
right, the pointer itself is an immutable primitive, so a copy should always be pointless?
copying pointers considered pointless
@bronsa I know a guy who co-wrote the compilers (C1 and C2) for the AMD implementation of OpenJDK 8 if you want a definitive answer.
I'll see if I've got his contact details and ping him. I've met him a couple of times as he works for red hat in Newcastle
So here's some relatively simple code I wrote - I'm very new to Clojure. Please feel free to assassinate it! I'd love to learn what I should do differently. Pointers to what I should look at very appreciated.
(use 'clj-ssh.ssh)
(use '[ :only [reader input-stream]])
(defn -main
"Grab some host logs"
[]
(let [agent (ssh-agent {})]
(future (let [session (session agent "10.206.6.245" {:strict-host-key-checking :no})]
(with-connection session
(let [result (ssh session {:cmd "journalctl -xe --no-pager -f" :out :stream})
stream (reader (:out-stream result))]
(doall (map println (line-seq stream)))))))
(future (let [session (session agent "10.206.6.42" {:strict-host-key-checking :no})]
(with-connection session
(let [result (ssh session {:cmd "journalctl -xe --no-pager -f" :out :stream})
stream (reader (:out-stream result))]
(doall (map println (line-seq stream))))))))
I have the general impression that doall
is "bad" and that future
is not the best way to thread. But these are vague feelings at the moment.
doall
isn't bad @mattford ... you could also use (doseq [l (line-seq stream)] (println l))
, since the map
isn't producing anything and doseq
is clearly for side-effects, but it's no biggie. future is a perfectly good way of threading... but if you want more control of your threads (e.g. non-blocking, error-state, completion callbacks) then a manifold future is better - https://github.com/ztellman/manifold/blob/master/docs/deferred.md#future-vs-manifolddeferredfuture
mattford: Biggest improvement would probably be to factor out let
blocks which are common to both futures into a separate function definition, and simply call that function with different sessions.
I’d probably recommend not complecting the task (executing a command on a server) with the spawning on a new thread.
As mccraigmccraig says map
is lazy so it’s normally a bad idea to put effectfull things into it… It’s arguably acceptably bad to do so though; and it is quite common in some circumstances - but here it’s redundant as your intent is clearly to execute the println
immediately.
basically main could just be something like:
@glenjamin I'd explain it as being pass by value, but also add that objects are pointers in C++: transparently pass by reference. Then you can grumble with them about that anti-feature!