Fork me on GitHub
#clojure
<
2018-06-01
>
seancorfield00:06:40

@andy.fingerhut Yeah, that's definitely a better choice in this case.

Vincent Cantin03:06:27

... and then nobody would come to cry if a function was removed in a new version of a library.

Vincent Cantin03:06:22

... and then library maintainers would happily remove the functions they don't like from their library's new releases without fear of breaking people's code.

Vincent Cantin03:06:50

It feels like a dream - too good to be true. Of course there should be some reasons why this would be a bad idea, but I don't think of some at the moment. Please help.

the2bears04:06:10

So different name spaces could 'require' different versions of a library? I suppose the potential for name collisions could be mitigated by incorporating the version as an alias but then you're likely to run into dependency issues still. As deps require deps you're far more likely to be unable to avoid naming collisions.

Vincent Cantin05:06:04

I had in mind 1 namespace requiring multiple versions of the same library at the same time.

the2bears05:06:10

But how would that look? Your example doesn't show bringing in multiple versions. So one method from version 1.0, and different method from version 2.0?

seancorfield04:06:45

It's fundamentally not possible due to the way classloaders work on the JVM.

👁️ 4
seancorfield04:06:49

You can't have multiple versions of the same library loaded into the same classloader @vincent.cantin

seancorfield05:06:11

This is part of why Rich was talking about only ever accreting functionality as a library changes -- and using different names (at the namespace level) if you ever want to break backward compatibility.

the2bears05:06:38

@seancorfield you're right, as I can't imagine a set up where everything doesn't fall under the same classloader hierarchy. OSGi gets away with some fancy trickery and peer classloaders but I don't see how anything like that could work with Clojure. Though, having worked on a framework a few years ago that rewrote Dalvik bytecode to trick the Android system into thinking there were multiple versions of apps such a thing might trick a person into starting down that path until you hit the dependencies that your libraries bring in - at which point you're in the situation you describe. Not just naming collisions, but the inability to load multiple versions of a class.

lmergen06:06:26

does anyone know whether dynamic binding of vars is thread-safe ? it appears to be the case, but i'm confused as to how this works under the hood, and what kind of limitations there are

lmergen06:06:50

i.e. the context of dynamic vars appears to be transferred between threads, which has me very confused

👍 4
leonoel06:06:20

it is implicitly transferred with future, send, go blocks

lmergen06:06:32

so that's why

lmergen06:06:35

okay, that makes sense

leonoel06:06:19

no it doesn't

leonoel06:06:25

but that's how it works

lmergen06:06:30

it also works with manifold.deferred :thinking_face:

lmergen06:06:45

thanks, it seems that that post answers my question

lmergen06:06:40

my case in point: i want to use timbre/with-context for binding additional context metadata to generated logs based on http request context, and i'm using Netty under the hood... i wonder whether this is safe

leonoel07:06:33

with-context just wraps binding, look at your asynchronous boundaries and check if they implicitly transfer bindings or not

leonoel07:06:47

you can always make it explicitly e.g with binding-conveyor-fn

lmergen07:06:04

oh! i like that

lmergen07:06:57

looks like bound-fn is what i want

korny09:06:04

Anyone got any favourite really simple command-line libraries? I’ve used tools.cli a fair bit, and it’s nice for real apps, but I’d love something simple for scripts I’m throwing together. My use case is, I’m trying to use deps.edn to replace all the little bits of glue I use, most often in ruby or bash, with clojure. If I can. So I don’t want full user-friendliness, validation, multiple options and the like. Just some simple boilerplate to let me pass parameters with less pain than parsing arguments myself. I can cut-and-paste the bits I need from tools.cli but it always seems to have a bit much complexity for what I want.

danp09:06:41

Hi all, I'm using clj-http.client/get to pull data from an API authorised by a token in the URL. When I run on my local machine, the code works as expected, however when I move it to the target environment, I get the following error:

java.lang.Exception: The application script threw an exception: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target, compiling:(core.clj:21:16)
We've encountered this with some Java code previously and created a naive TrustManager (it's just dev stuff, so this is permissible 🙂). I've found a way to get around the error (generally) in Clojure, but wondered if I could do something similar with clj-http: https://yogthos.net/posts/2016-07-15-JavaSSLWorkaround.html

jumar10:06:19

@danp are you sure the endpoint you're calling has a valid certificate? Is/was that certificate imported into your local java installation, but (perhaps) not on your server?

danp10:06:22

@U06BE1L6T I've never added anything to the local install.

jumar10:06:59

Does the service have a valid ssl certificate?

danp10:06:03

Yes it's valid

jumar10:06:21

Btw. you can try :insecure option for clj-http but I'd strongly recommend against using it for anything else than experiments:

(clj-http.client/get "")
;;=> SunCertPathBuilderException unable to find valid certification path to requested target  sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)

(clj-http.client/get "" {:insecure true})
{:request-time 1062,
 :repeatable? false,
 :protocol-version {:name "HTTP", :major 1, :minor 1},
 :streaming? true,
 :chunked? false,
 :reason-phrase "OK",
...

danp10:06:24

Thanks @U06BE1L6T - I've already tried that and it refuses the connection.

jumar10:06:55

That's very strange - problem has to be somewhere else then...

danp11:06:39

java.lang.Exception: The application script threw an exception: java.net.ConnectException: Connection refused (Connection refused)

danp11:06:46

Like I mentioned above, we had this happen with some Java code before and creating a blind trust manager sorted it out (it was the same server).

danp11:06:15

I'm having a look at other clojure http clients too

jumar11:06:49

That's probably suboptimal but can work. Sometimes, there can be problems with intermediate certificates. I'd probably first try to upgrade java version as pesterhazy said to make sure that it's not affected by that. Then you could try to enable debug logging for apache http client - you should then see very detailed logs in your console. Moreover, you can also enable very detailed java ssl logs via -Djavax.net.debug=ssl (see also https://stackoverflow.com/questions/23659564/limiting-java-ssl-debug-logging)

jumar11:06:56

Anyway connection refused looks like a firewall issue or something

danp11:06:02

that'd be a case of running the jar from the command line wouldn't it?

danp11:06:37

Yeah, that's what I thought, but there's already code on the same machine that is hitting the same endpoint.

jumar11:06:43

I don't know then 😮. As I said, start with http client debug logs and perhaps move to ssl debug logs once you resolve the "connection refused" part.

danp11:06:54

Does clj-http have a debug option - it's not something I'd noticed when digging around

jumar11:06:45

try {:debug true}

danp11:06:11

Yep, thanks - I found that just now. Turns out the jar works fine when I run it from the command line. I have to wrap the Clojure in our ETL code using Java, which I guess must be the problem

danp11:06:26

😳 turns out it was a consequence of running the code from home - I ran the same job that failed yesterday, but from the office and it completes successfully.

danp11:06:41

Thanks for your guidance - it's much appreciated! 🙂

👍 4
pesterhazy09:06:55

if there's a difference between local and prod envs, this might be related to your Java version

danp09:06:25

Cheers @pesterhazy - they're both running Java 8, though there is a slight discrepancy in the minor version.

pesterhazy09:06:59

It might very well be that updating to the latest patch version fixes the issue

danp09:06:14

Cool, I'm not sure how feasible it is to get that done at the mo 😕

danp10:06:12

There are a few things running currently and don't want to disrupt anyone else

korny10:06:35

More on the “trying to replace my ruby” subject - is there a simple graphql client in clojure? I looked around on clojure-toolbox and https://graphql.org/code/#clojure and all I can see is lots of complex server implementations. (I did find https://github.com/Vincit/venia but it implements the DSL but not the client logic; and https://github.com/oliyh/re-graph but it seems to be clojurescript-specific)

dominicm10:06:45

I don't think a client will really appear, same way there's not clojure wrappers around most http apis floating about. GraphQL is particularly simple to implement, POST JSON to an endpoint = done.

korny10:06:23

Well, true, though it’s nice to have someone abstract how you pass query parameters, and authentication, and ideally abstracting away pagination a bit… but yeah, maybe it’s too simple to have strong demand for a library.

pesterhazy10:06:21

@danp, you can verify the assumption by downgrading the JDK locally

danp10:06:49

that's a possibility - will give it a whirl now 🙂

jeff.terrell15:06:14

I'm finally getting around to reading (more of) the recent Rich Hickey interview by Joy Clark [1], and I found this quote from Rich to be pretty interesting, giving some insight into the static vs. dynamic issue: > And it was certainly my experience before Clojure, working with static type systems that all the systems were incredibly brittle, and eventually the costs of change just got so high... Every system eventually got thrown away because the costs of change became too great. [1] http://www.case-podcast.org/20-problem-solving-and-clojure-19-with-rich-hickey/transcript

yogsototh15:06:06

I personnaly find that change cost more when you don't have types to help you not create a bug in the process. And spec / schema were done to minimise those risks of breaking things when we change something. Even if those are not type system, sometime I would really have loved to have spec / schema and an additional modern type system to detect errors in my code before I deploy it to production.

4
andre.stylianos16:06:41

I feel the same... I think the biggest factor impacting the cost of change is not static/dynamic type systems, but the complexity of your system. But type systems can at least provide some security in this case

john16:06:59

Does adding more and more invariants to a system make it more difficult to change from "correct thing A" to "correct thing B"? I guess you could also separate those invariants between invariants in the underlying implementation - the implementation abstraction, like bytes, vectors and maps - and invariants in the target model... It would seem that adding more and more invariants to the target model will make it more difficult to rewrite that model for a different target. Whereas invariants in the underlying abstraction may not necessarily over-constrain the evolvability of different target models.

sova-soars-the-sora16:06:21

@john what you wrote reminds me of crystallizing too early or too late in the process -- where do you decide what your building blocks are? ideally before you start building castle #1 and castle #2 ... otherwise you end up with lots of parts that only fit castle #2 that can't be moved to castle #1 and so forth... the fact that software engineering has mimicked physical prototyping thus far (for instance, models of cars, and how they are each engineered without a lot of overlap or commonality in components) is perplexing, and i'm glad we're moving beyond it -- beyond the "brittle in change" to "robust in progression"

👌 4
Alex Miller (Clojure team)16:06:27

@andre.stylianos that seems to assume that use of static type systems is independent of complexity. I think what Rich was saying above is that (at least some) of that complexity is actually caused by the brittleness of types.

👍 8
andre.stylianos17:06:43

True, true. I'm in agreement that static type systems do bring complexity in a lot of ways, but I also think that dynamic typing does come with its own complexities (just in different ways). I'm not too firmly on either side, I actually think the language design in general is much more important. I've used Java and have no desire to do it again, I've also used Python (briefly) and have no interest in it. But I love working with Clojure and I also really enjoyed working with Scala. Sometimes I look at some Scala code and marvel at how much simpler clojure is, and sometimes I break something in my clojure code and sigh at how that kind of mistake would never have happened with Scala 😛

Alex Miller (Clojure team)17:06:55

well, agreed that I don’t think static/dynamic is the most important attribute :)

val_waeselynck16:06:38

I don't think we should condemn static typing in general because of some instances of static typing (i.e some language in some project), just like we should be condemning dynamic typing because, say, dynamic typing in a class-based language generally sucks (as you get the downsides of both static and dynamic typing)

seancorfield16:06:28

I think the choice of static vs dynamic is entirely subjective -- there really aren't any conclusive studies to show that systems built either way are "better" in terms of bugs or maintenance. Some people like type systems, some people don't like them.

☝️ 4
Alex Miller (Clojure team)16:06:10

one issue with static type systems is that they are “everywhere, all the time”

Alex Miller (Clojure team)16:06:28

whereas I really want “some places, eventually”

🎯 12
seancorfield16:06:31

For me, type systems seem to create brittle systems and they aren't expressive enough to describe business logic invariants. So I'm with Rich on that.

💯 4
mpenet16:06:32

Well, most do inference too

val_waeselynck16:06:01

@seancorfield to most people, it's a matter of dogma; to some, it's a matter of taste, but I hope one day we'll all be lucid enough to make it a matter of tradeoffs (I don't claim that I am yet)

mpenet16:06:19

Most of the time you type the edges (kinda) and inference does the rest for free

seancorfield16:06:34

Yeah, gradual typing seems a possible middle ground. Type inference is just not good enough (yet).

mpenet16:06:51

ocaml is pretty good at it

Alex Miller (Clojure team)16:06:52

@mpenet it’s still being checked everywhere though

seancorfield16:06:57

(part of my PhD work in the 80's was on type inference)

Alex Miller (Clojure team)16:06:01

which is both the up and downside

mpenet16:06:21

@alexmiller but that's a good thing imho

Alex Miller (Clojure team)16:06:36

I’ll contend it’s both good and bad :)

john16:06:38

Aren't most "dynamic" languages implicitly static over bytes and collections of them, under the hood? Dynamic langs just abstract them away, but the correctness is still being implemented by some analog of a type system underneath?

noisesmith16:06:57

and most static languages are implicitly dynamic about the contents of bytes and collections of them :P

noisesmith16:06:55

and there's dynamic languages with no concept of a type - eg. forth (alternatively you could say the only type forth has is a byte, and even the name of your word is just a series of bytes etc.)

mpenet16:06:45

As long as inference is not too bad

Alex Miller (Clojure team)16:06:52

there will be a cool talk at Strange Loop this year about “typed holes” - typing in the face of incomplete parts of a program

seancorfield16:06:20

@john Yeah, most dynamic languages are still strongly typed, just at runtime.

john16:06:24

@seancorfield Right. It's more like dynamic langs are abstractions of the illusion of optional behavior over otherwise statically typed underlying behavior, so that we don't have to always worry about bytes!

seancorfield16:06:31

Just noticed that this discussion is in the main #clojure channel -- we should probably decamp to #other-languages or #architecture or #off-topic

12
john16:06:49

Seems like, if your domain is as tractable and simple as organizing bytes into arrays, then a type system is a killer app for that

seancorfield16:06:03

But, bringing it back to Clojure: when you work in the REPL, the difference between a compilation error (which is where type checking would occur -- and in some cases, even in Clojure, does occur) and a runtime error is pretty minimal. You type in an expression and it fails to evaluate -- whether that exception comes from the compiler or from the runtime checking isn't terribly important.

val_waeselynck16:06:56

Well, you do have to get the code to evaluate, and even then that will account for only one point in the state space

👍 4
val_waeselynck17:06:30

It seems to me what frustrates Rich and other people most about type systems is how they tend to create more work (less code reuse, over-specificity) and hinder progress (because rigidity). But I think a lot of organizations don't even reach the point where these limitations matter, because their development teams are not careful enough to not shoot themselves in the foot without mechanically enforced constraints, and don't have enough architectural skills to benefit from the opportunities offered by dynamic typing. What do you think?

bendlas17:06:44

I think you might be onto something with that. I'd answer two-fold: 1) mediocrity of the masses shouldn't ever be a reason not to aim higher 2) many of the people, you described, will learn rather quickly, if offered the chance

val_waeselynck17:06:13

I don't know, I used to be have a very "universalist" mindset towards programming mastery, but it seems the last months in company of other programmers have made me less optimistic

val_waeselynck17:06:36

Note that I never said that as an argument in favour of abandoning dynamic typing - if the problem is in HR and process, let's fix it there, not in programming languages

seancorfield17:06:59

This definitely needs to go to #off-topic (or perhaps #jobs-discuss ). I have some strong opinions on this topic but they're not appropriate for #clojure 🙂

val_waeselynck17:06:27

OK, as @seancorfield suggested, let's move this to #off-topic