Fork me on GitHub
#clojure-uk
<
2017-01-25
>
thomas07:01:31

@paulspencerwilliams which predicate were they complaining about for instance?

thomas07:01:36

morning btw

paulspencerwilliams08:01:08

@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 %)))

thomas08:01:08

ok... I thought that int? was quite obvious... once you know that is convention, but that is a small thing IMHO.

paulspencerwilliams08:01:04

I suppose there's a few problems with that when not used to lisp.

paulspencerwilliams08:01:50

the function syntax, the cat, the #, as you say, what's the significance of ?. It's just syntax.

agile_geek08:01:56

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!

agile_geek08:01:00

@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.

paulspencerwilliams08:01:18

@agile_geek agreed. It's familiarity.

agile_geek08:01:03

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!)

thomas09:01:09

@agile_geek do you think a tool like kibit could help here? suggesting what style to use.. (if that is possible at all)

agile_geek09:01:29

@thomas only at the lowest level

otfrom09:01:10

agile_geek I'm still a bit unclear about what your particular style (or design?) issues are

otfrom09:01:23

I'd like to figure them out and happy to talk through any initial thoughts you have

agile_geek09:01:31

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

thomas09:01:59

I still learn new core functions after several years of clojuring... so many hidden gems in that.

dominicm09:01:23

@agile_geek is that not a concern of architecture, as opposed to one of others to enforce what is proper for your project?

dominicm09:01:52

I kind of like the non-framework status, as it allows me freedom to think through my problem & solve it how it all fits.

agile_geek09:01:06

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.

agile_geek09:01:41

We aren't paid to write code, we are paid to deliver value

agile_geek09:01:44

Maybe 28 years of solving the same problems a different way every 1-2 years has made me jaded simple_smile

thomas09:01:11

didn't Eric Normand(?) say something like that the way your code should be organised be the same as your problem (or solution)

agile_geek09:01:03

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.

dominicm09:01:45

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.

thomas09:01:15

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 😉

mccraigmccraig09:01:15

[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

mccraigmccraig09:01:15

[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

mccraigmccraig09:01:43

[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

mccraigmccraig09:01:21

[4] spec/schema at component boundaries seems to do quite well here

agile_geek09:01:48

@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.

Rachel Westmacott10:01:13

If the right person wrote an "Effective Clojure" book, I would buy it.

mccraigmccraig10:01:23

a leading question @agile_geek - i am shocked 😱 !

agile_geek10:01:45

@peterwestmacott who is the right person?

yogidevbear10:01:01

@dominicm seemed quite willing last night 😉

yogidevbear10:01:51

ducks for cover

Rachel Westmacott10:01:24

@agile_geek If I knew - I'd hassle them directly

agile_geek10:01:44

Maybe that would prompt them to write the book!

agile_geek10:01:12

Fortunately, it's never going to be me!

glenjamin10:01:20

[2] Reduce the number of functions which need that resource

glenjamin10:01:33

by pushing effects up the stack to the edges

practicalli-johnny10:01:17

@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

agile_geek12:01:55

@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)??

otfrom13:01:29

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)

otfrom13:01:42

this is the kind of thing I feel that Rich was talking about the Language of the System

agile_geek13:01:13

@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?

otfrom13:01:17

agile_geek I would, but it partly depends on what the functions are doing and if they are domain related or not

agile_geek13:01:35

To me SRP is valid at all levels - and is a principle that has nothing to do with FP, OOP or any other P

otfrom13:01:43

(and I generally err on the side of having repeated code until you know that the similarity is real rather than accidental)

agile_geek13:01:55

I would agree

otfrom13:01:22

your understanding of SRP is probably deeper than mine then. I've mostly seen SRP applied at the class/method or function level

agile_geek13:01:33

but that's a separate conversation about deferring design decisions to the appropriate moment

otfrom13:01:28

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

otfrom13:01:12

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

otfrom13:01:26

unless it feels a lot like (ginger|chocolate) cake to me

agile_geek13:01:43

I think we are actually on the same page

agile_geek13:01:53

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

otfrom13:01:59

looking forward to that

otfrom13:01:15

I figure I'll come around to your way of thinking once I understand it. I usually do.

otfrom13:01:34

we're probably just struggling through different layers of professional scarring

otfrom13:01:56

I'm very scarred by DDD when most of what I've done is just munged data

agile_geek13:01:40

@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! 😈

otfrom13:01:18

agile_geek publish and be damned

otfrom14:01:11

(tho I'll have a look, can be hard to comment quickly on things that make me think tho)

jasonbell14:01:53

@agile_geek publish to blog.... nothing like exposure to public ridicule to galvanise the attention.

otfrom14:01:52

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

agile_geek14:01:37

@otfrom and you think I actually take Jade's opinion into account?

jasonbell14:01:42

To be honest I don’t go slagging off everyone’s blog post.

jasonbell14:01:40

But, if @agile_geek is going to keep the Jade malarky going on then I might just change my mind

otfrom14:01:53

mccraigmccraig Jade is jasonbell's True Name ™️

jasonbell14:01:17

I’m busy.....

mccraigmccraig14:01:38

how does one discover one's True Name ™️ ?

otfrom14:01:49

mccraigmccraig mostly? autocarrot.

otfrom14:01:58

the machines know the truth

mattford14:01:21

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.

agile_geek14:01:32

@jasonbell you must not have learned an important lesson in school... Never let the school bully know he's getting under your skin, Jade

otfrom14:01:57

mattford that was one of the things pallet did well

otfrom14:01:46

mattford this looks interesting (not used it) https://github.com/sunng87/shake

mattford14:01:32

I found this

mattford14:01:01

But AFAICT nothing implemented

mattford14:01:06

Is that link I posted to a page for clojure core design consideration?

mattford14:01:35

Well it is by the looks of it. But is it official?

otfrom14:01:48

mattford I've not seen or heard any movement on the alt string quote stuff

otfrom14:01:13

at least in core, but core is very conservative and most things happen in libaries (spec being a weird exception)

jasonbell14:01:06

Right where were we....

jasonbell14:01:21

@mccraigmccraig to find one’s true name just get @agile_geek email reply to autocorrect your name wrong.

jasonbell14:01:39

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.

mattford14:01:14

hmm - I was hoping to avoid having to quote the quotes but that still looks to be the case in pallet/stevedore

otfrom14:01:43

mattford can you give us an example of what you have to do and what you'd like it to look like?

mattford14:01:03

(let [result (ssh session {:in "echo \"SONAUGHTY\" | sudo -S /bin/bash -l -c \"ls -l\"")})]

mattford14:01:30

i was kinda hoping for

mattford14:01:59

(let [result (ssh session {:in @echo "SONAUGHTY" | sudo -S /bin/bash -l -c "ls -l"@)})]

otfrom14:01:58

ah, so the problem is the general string quoting inside clojure rather than having to quote the shell things

otfrom14:01:58

I wonder if the approach like @krisajenkins yesql would work for this https://github.com/krisajenkins/yesql

otfrom14:01:14

(tho I do understand that is a different way of approaching the whole problem)

mattford14:01:18

so that's similar to slurping a file and letting it take care of the quoting (I think)

mattford14:01:09

Wanted to build the strings though a bit more dynamically. Was exploring how clojure could be used like Python's Fabric.

otfrom15:01:25

mattford got a fabric example that shows the same thing?

mattford15:01:08

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).

mattford15:01:36

Anyhow I can live with the quoting for my little experiment 🙂

mattford15:01:41

Thanks for the pointers.

krisajenkins15:01:29

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

agile_geek15:01:52

@krisajenkins might not have time for a day or two but I'm happy to critique in retrospect! 😈

mccraigmccraig15:01:10

@krisajenkins looks fine to me - though i did wonder about the second meaning of 'isomorphic' which i'm not aware of - another footnote ?

krisajenkins15:01:30

Oh, thanks yes.

krisajenkins15:01:37

Out of interest, what’s the one you know?

krisajenkins15:01:47

(And thank you for taking a look so quickly! 😄 )

Rachel Westmacott15:01:18

How do you mutate a scala.collection.immutable.List ?

otfrom15:01:41

krisajenkins that looks good to me shipit

mccraigmccraig15:01:54

@krisajenkins an app running the same language front & backend (obvs there are mathematical isomorphisms too, but i'm thinking of isomorphic apps)

krisajenkins15:01:19

@peterwestmacott Allowing for syntax: listyMcListface[0].setName(”Hugmaster”)

krisajenkins15:01:50

@mccraigmccraig Then you know both. Haskellites will fight to the death for the real meaning of isomorphic. 😄

Rachel Westmacott15:01:37

so the list object is immutable, but the objects within it are not?

otfrom15:01:14

krisajenkins I feel strangely... mutated

Rachel Westmacott15:01:23

okay, no new surprises then - I'm not sure that it reads like that in your blog post

krisajenkins15:01:28

I resisted the temptation to say, “cargo cult immutability."

Rachel Westmacott15:01:39

I inferred that the list object could be changed

Rachel Westmacott15:01:49

(ie. mokeypatched or some-such)

krisajenkins15:01:32

Ah, thanks. I’ve updated to make that a bit clearer. 🙂

Rachel Westmacott16:01:30

(...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")

Rachel Westmacott16:01:44

oh - I guess that train has sailed...

otfrom16:01:15

it will just have to be argued out now. 😉

krisajenkins16:01:23

Ha, gonna hedge it: > No special guarantees there - it's still mutable as it was before.

krisajenkins16:01:46

Sometimes a hug is just a fight trying to move.

otfrom16:01:51

yeah, I sorta get like that don't I

rickmoynihan16:01:32

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.

glenjamin17:01:31

@krisajenkins I don’t generally think of JS as having pointer-like semantics

glenjamin17:01:03

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

krisajenkins17:01:22

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.)

glenjamin17:01:24

there are immutable primitive values, and objects. Objects are mutable, “variables” are locally scoped names for those

glenjamin17:01:50

objects are compared via identity, primitives by value

krisajenkins17:01:17

But what’s identity, if not the same effective semantics as pointer-equality?

glenjamin17:01:22

I suppose so, I usually think of pointer semantics as implying pointer arithmetic

krisajenkins17:01:26

(I’m not saying they’re actual hardware pointers-to-memory, just that they behave the same way.)

krisajenkins17:01:41

That’s exactly what I find odd - all the downsides of pointer semantics, none of the control.

glenjamin17:01:52

and for example you can’t have a pointer to a primitive

krisajenkins17:01:58

(Not that I want that control. But I don’t want the semantics either.)

glenjamin17:01:36

I can understand why it’s like that, I can’t understand why any new language defaults to identity for eqality

krisajenkins17:01:46

I…can’t any more.

glenjamin17:01:51

although… how do you compare functions?

glenjamin17:01:41

why aren’t (defn x [n] (+ n 1)) and (defn abc [n] (+ n 1)) equal?

glenjamin17:01:03

or at least, why shouldn’t I be able to check that they are and receive and affirmative

krisajenkins17:01:07

You can’t in the general case, I mean. That’s proven, I believe.

glenjamin17:01:47

Can’t prove they express the same relation? That sounds like something someone would prove

krisajenkins17:01:16

If you have access to the source code, I think that’d be different.

agile_geek17:01:17

@rickmoynihan I've read Elements of Clojure another source I'd recommend along with Clojure Applied

otfrom17:01:32

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

otfrom17:01:39

works for me anyway

krisajenkins17:01:56

That is a novel way of looking at it. 😛

otfrom17:01:57

"too much syntactic sugar leads to cancer of the semicolon"

krisajenkins17:01:17

I think of it as pass by reference, except some primitives are magic.

bronsa17:01:40

@glenjamin proving functions equivalence is impossible

bronsa17:01:59

@otfrom java is pass-by-value

bronsa17:01:05

definitionally, from the java spec

bronsa17:01:58

it's just that the value that usually gets passed around is a reference

bronsa17:01:04

but it has pass-by-value semantics

rickmoynihan17:01:30

glenjamin: yeah IIRC it’s basically the halting problem in the general case.... obviously you could compare byte/source code is identical

glenjamin17:01:37

@otfrom I’ve used that definition too, I like it

glenjamin17:01:15

in the general case, sure, but functions being equal via identity and lisp forms being equal lexically seem useful in some cases

bronsa17:01:34

(I'm agreeing with @otfrom, just clarifying that it's actually a fact and not just an opinion)

glenjamin17:01:05

pass-by-value in C-land means copying though?

agile_geek17:01:07

@bronsa I knew that ... I knew that...

bronsa17:01:21

@glenjamin yeah, and that happens in the jvm

bronsa17:01:28

what gets copied is the reference tho

krisajenkins17:01:38

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.

bronsa17:01:39

the jvm has values (primitives) and references to objects

glenjamin17:01:43

whereas pass-by-value of a large array in C copies the whole thing?

bronsa17:01:57

and in the jvm you copy the reference to that array

glenjamin17:01:58

hence why I don’t like to say it’s pass-by-value to C-type people

rickmoynihan17:01:59

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.

bronsa17:01:44

@glenjamin if it were pass-by-reference you'd be able to do things java doesn't actually support

glenjamin17:01:57

right, its not like either of the models in C

glenjamin17:01:12

pass-by-value-without-copying-of-complex-things

bronsa17:01:24

pass-by-value-but-most-values-are-references

otfrom17:01:25

b/c the thing being passed is the pointer address

agile_geek17:01:30

@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

glenjamin17:01:35

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

bronsa17:01:55

no idea about js

glenjamin17:01:00

eg. the pointer itself isn’t duplicated in memory in any way

agile_geek17:01:03

@glenjamin I think it's a real copy

bronsa17:01:06

but AFAIC the reference is copied in the jvm

bronsa17:01:30

or at least, the jvm acts as if it was actually copied for real, the copy is likely optimized away

glenjamin17:01:48

right, the pointer itself is an immutable primitive, so a copy should always be pointless?

bronsa17:01:53

I'd think so

krisajenkins17:01:23

copying pointers considered pointless

agile_geek17:01:43

@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.

bronsa17:01:03

I can't say I wouldn't like to know if you don't mind bothering the guy then :)

agile_geek17:01:16

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

mattford19:01:06

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))))))))

mattford19:01:52

Ignoring the obvious cut'n'paste abstraction

mattford19:01:33

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.

mccraigmccraig19:01:08

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

rickmoynihan19:01:55

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.

rickmoynihan19:01:55

basically main could just be something like:

minimal19:01:36

you can use run! instead of map for side effects

mattford19:01:52

Thank you very much

dominicm20:01:24

@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!