Fork me on GitHub
#clojure
<
2020-10-07
>
arthur03:10:56

sorry if this me failing to google before asking... anyone know if java-time can be used in closh?

/home/arthur» (cemerick.pomegranate/add-dependencies
         #_=>          :coordinates '[[clojure.java-time "0.3.2"]]
         #_=>          :repositories (merge cemerick.pomegranate.aether/maven-central
         #_=>                               {"clojars" ""}))
{[clojure.java-time "0.3.2"] #{[clj-tuple "0.2.2"]}, [clj-tuple "0.2.2"] nil}
/home/arthur» (require '[java-time :as t])
Syntax error (IllegalAccessError) compiling at (java_time/temporal.clj:324:1).
tried to access field clojure.lang.APersistentVector._hash from class clojure.lang.PersistentUnrolledVector$Card1

seancorfield04:10:42

@arthur That line in java-time.temporal in 0.3.2 is a comment so I'm wondering if closh itself already has an earlier version?

seancorfield04:10:15

Hmm, doesn't look like it. But that does sort of feel like a compiled code/version conflict sort of issue. I've played with closh quite a bit -- but never try to add new dependencies while running -- and I did find it a bit crashy with some of the things I was doing 😐

didibus05:10:12

I've been thinking about package dependencies and the issues happening in npm and Python world, where people name squat but also try to take advantage of typos and such to introduce vulnerabilities. Clojure recommends that you use org/package and uses namespaces, so name squatting isn't as easy, since you can't take over someone else's org, but you could still put packages of the same name in similar sounding orgs or different orgs and hope to introduce vulnerabilities by way of someone accidentally using the wrong package. Maven Central I learned does a manual verification for that purpose, where they validate that you own the domain of.your org for example. Now, in GitHub, you can verify your domain for a github organization as well, and that's actually automated. So I've been thinking, what if Clojars did something similar? It could ask to verify that you either own your domain, or your identity on some supported identity website like github. And the validation could be automated as well. For domain, do what github does, ask for a DNS TXT header secret to be there, assume your org in Clojars is the reverse domain name. Similarly, for github, could ask to create a gist that contains a secret, or a repo with a file that has the secret in it. And assume your org is your github username or org name. I don't feel this would add too much friction, and maybe if we want to be backwards compatible, Clojars could offer two repos, one verified one with such verification and one for free for all. Serious libs can do the extra work of being verified and people who need that level of trust can depend only on that repo. Thoughts? (Might post this to the reddit as well)

seancorfield05:10:53

@didibus This is probably better suited to the #clojars channel -- there used to be a two-tier system with signed JARs and unsigned JARs but it was abandoned because so few people bothered to sign JARs 😐

didibus07:10:46

I can see Jar signing being more annoying to do. Also I don't think that validates identity, seems to be more for man in the middle. Like someone returning me a different Jar when I try to download the one from Clojars.

Alex Miller (Clojure team)12:10:46

Signing doesn’t tell you anything about whether you trust the identity of the signer

seancorfield05:10:03

We have so many groups on Clojars that are not either reverse domains or GitHub usernames that I don't think it would work... And Alex's blog post about qualified lib names suggested <provider>-<username>, e.g., github-seancorfield, which is not a pattern anyone uses right now but something like that would be required to avoid squatting on people's usernames on different services to sow confusion -- is seancorfield/some-lib from seancorfield on (me!) or seancorfield on some other servicer provider? (potentially not me, but mostly I'm the only seancorfield everywhere as far as I know)

didibus07:10:53

Hum, ya that would be the problem, and maybe the reason for having two repos? I wonder if you verify your domain or github on a Clojars account. Even if the Clojars account is different in name. And if by doing so, that somehow also prevented on Clojars anyone else from creating a user of the domain name or github user you verified? Maybe that be sufficient

didibus07:10:01

Someone couldn't then come and have a org.corfield/next.jdbc since seancorfield verified that it owned the domain.

didibus07:10:18

And then the next step would be preventing accounts that don't have a domain or identity verified with their Clojars user from being allowed to publish to it (maybe grandfather existing).

didibus07:10:16

Hum, ok well, rereading how groups work in Clojars. I guess it would mean that groups wouldn't be created automatically when pushing. You'd need to create the group, attach an indentity or domain to it that Clojars would validate, and then it would allow users to push to the group.

didibus07:10:26

Okay, one more idea 😝, kind of brainstorming here. Maybe all Clojars does is, if the groupId pushed is a reverse domain name, or of the form github-... or gitlab-... or bitbucket-... then it will validate it by either checking for a header on the DNS of the domain that has as value the Clojars groupId when a reverse domain, or by checking for a special repo with a readme that contains a file with the groupId in from the repo managers if it was a github-... style groupId

didibus07:10:50

So at least, going forward, as a user, you know if you depend on a lib with a reverse domain name, that it was validated to be from the owner of the domain, or if a lib with a github-user that it was validated to be coming for sure from that user on github

didibus07:10:33

And people who want to publish without wanting to validate can use groupId that are not of those format

seancorfield16:10:11

Like I said, take it up in #clojars and see how receptive the maintainers are to these suggestions.

seancorfield05:10:34

Also, there's no obvious connection between the domain I own and the username I have on almost every service seancorfield so I'm not sure how domain verification would even work in that case?

Karol Wójcik07:10:11

Is it possible to add default implementation for protocol method?

didibus07:10:14

I think you can by extending it for type Object

Karol Wójcik07:10:30

That's seems kinda nasty.

Karol Wójcik07:10:02

Is it possible to extend the type in record?

Karol Wójcik07:10:29

That would be better since I would not have to mess with Object.

didibus07:10:06

Hum, I mean it's not any nastier than if there was a default. Though I guess Object would not work for nil, where a default would since protocols can extend nil.

didibus07:10:58

You want it implemented for all record types?

didibus07:10:55

I'm sure there's some similar parent that all record belongs too that you could use?

didibus07:10:26

Wait, could it be you just want to use the same functions as the implementation for multiple record types?

didibus07:10:19

If so you can use extend it takes a map from method name (as a keyword) to the function that implements it. So you can extend all your record and give them the same map

Karol Wójcik08:10:31

@didibus I would like to have some of the records to implement IEventSourceable interface and I don’t want to specify the same function implementation over and over again.

didibus08:10:27

Ya you should be able to do that with extend. You'd still need to list out each record you want it for, but at least you won't have to type the implementation of the methods over and over

Karol Wójcik08:10:14

Thank you @didibus. This is great! Do you know whether it's possible to get record function by keyword?

didibus08:10:24

Not sure what you mean?

Setzer2209:10:23

hi! any way to mix expound's human-readable spec errors with orchestra instrumentation?

Setzer2209:10:18

I tried setting s/*explain-out* to expound/printer , but when there's a spec error I'm still getting the normal explain output

bbrinck14:10:22

Hm, this should work. If you post your code in #expound I may be able to spot the issue

grounded_sage10:10:43

Trying to grok when macroexpansion occurs in a dependency. We have a dynamic var that we wish to alter downstream. So that we can alter the behaviour of the macro dynamically.

Alex Miller (Clojure team)12:10:42

It happens whenever code using the macro is compiled. That could be at aot compile time, or load time.

grounded_sage21:10:10

When you require in a macro to a ns is that classified as load time?

Alex Miller (Clojure team)21:10:14

When you load the ns that does the require, yes

grounded_sage05:10:43

Okay. But if the ns that does the require alters a dynamic var. The var being used by the macro in the required ns. Is that too late to alter how the macro expands?

Alex Miller (Clojure team)12:10:16

I think it depends on whether you alter the dynamic var before or after the require? Although I’m not entirely sure what happens in the aot case.

Mikko Harju10:10:34

What would be the best way to declare for a local dependency in deps.edn (`{:local/root "checkouts/project"`}} that it uses a certain alias that has extra source paths? Or is it customary to just add that source path directly to deps.edn directly?

Mikko Harju10:10:28

I'd like to have the possibility to omit one source directory, that needs to be specified by the dependency user to include/not include it

Mikko Harju10:10:33

The reason is that if you choose to have that directory, you must have add additional dependencies that not every project using the dependency needs at all

Alex Miller (Clojure team)12:10:07

I think you are outside the bounds of what deps.edn supports

Mikko Harju13:10:04

Yeah, I thought so too – and it was trivial to just add the source path to :paths declaration in the project using the dependency (it's included as a submodule in checkouts)

Mikko Harju13:10:30

I'm not sure if this is idiomatic, but works for our use case just fine!

Day Bobby13:10:16

isn't it http://clojure.org, or does it have another domain i dont know

jjttjj13:10:58

ohhh you're right. I think the dot com used to redirect somewhere at least? I clicked a dead link somewhere

👍 3
Alex Miller (Clojure team)13:10:08

.com has not existed for a long time

abdullahibra16:10:41

is there a way to parse timestamp with whatever format ?

andy.fingerhut16:10:34

Clojure folks tend to rely on existing Java libraries for this, I believe.

abdullahibra16:10:24

what java libs you may suggest that helps here?

dharrigan16:10:58

Java, since version 8, has very good build-in time support, under the java.time package

andy.fingerhut16:10:38

Several different classes for different purposes, many with Java methods whose name contains "parse"

abdullahibra16:10:11

i think the most worth here is java.text.SimpleDateFormat

abdullahibra16:10:18

but that takes format

abdullahibra16:10:37

maybe i need to write another function to determine the date format at first

abdullahibra16:10:06

anyway thanks guys

andy.fingerhut16:10:29

There are so many date/time formats in text, that saying "whatever" format is unlikely to produce a list that ends if you start writing it this year.

andy.fingerhut16:10:53

Any given application you have hopefully you can limit them to a small set of acceptable formats.

andy.fingerhut16:10:11

If your goal is "recognize dates/times in any way a human might recognize", then you are in AI/machine-learning territory.

abdullahibra16:10:52

yeah i got that, maybe you can use CRF model to do that, stanford NLP has that feature, but i'm not seeking dates extraction from text

abdullahibra16:10:49

i think i'll define some regexp for specific number of timestamp format, then search which regexp is right for it

abdullahibra16:10:01

after determine the format i'll parse it

Daniel Stephens16:10:47

Is the aim to parse any individual timestamp or to recognise a format given many date strings? Plenty of dates are ambiguous if you don't know the format, 01-01-2020T... could be day first or month first so very few programs would do anything beyond telling you which format to provide timestamps in

abdullahibra16:10:20

the ultimate goal is parsing timestamps, so the problem now as you addressed "the format", so i'll limit that to a set of formats then i'll need method to determine the format before the parse step

p-himik19:10:57

That's exactly what clj-time does - it tries to guess the format based on its own list of formats: https://github.com/clj-time/clj-time/blob/master/src/clj_time/format.clj#L156-L165

abdullahibra06:10:17

but you still need the format as input, i have wrote another function which check the predicated format.

p-himik06:10:55

No you don't - there are two arities, the second one accepts only a single string.

dharrigan16:10:25

Sure, what do you have in mind?

abdullahibra16:10:31

what do you mean?

Ray Grant16:10:16

I'm wondering if there is a commonly adopted clojure framework used for building backend routes and services for a web app. Or is there a list that could help me know what one to use?

Ray Grant17:10:18

Thanks!

👍 3
Kevin19:10:56

My lack of Java knowledge is really testing me right now, hopefully someone can point out the obvious for me. I instantiated a new com.googlecode.lanterna.gui2.MultiWindowTextGUI Object (https://github.com/mabe02/lanterna/blob/lanterna-3.0.3/src/main/java/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java) using (new MultiWindowTextGUI screen wm x). I then want to tall the getFocusedInteractable method. When I check the source file https://github.com/mabe02/lanterna/blob/lanterna-3.0.3/src/main/java/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java#L364 and also the API documentation https://mabe02.github.io/lanterna/apidocs/3.0/com/googlecode/lanterna/gui2/MultiWindowTextGUI.html#getFocusedInteractable-- then it looks like there should be a getFocusedInteractable method. However when I try to call it with (.getFocusedInteractable gui) I get the following error

Exception in thread "async-dispatch-1" java.lang.IllegalArgumentException: No matching field found: getFocusedInteractable​ for class com.googlecode.lanterna.gui2.MultiWindowTextGUI
        at clojure.lang.Reflector.getInstanceField(Reflector.java:397)
        at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:440)
        at trader.core$_main$fn__10988$state_machine__8040__auto____11009$fn__11011$fn__11013.invoke(core.clj:158)
        at trader.core$_main$fn__10988$state_machine__8040__auto____11009$fn__11011.invoke(core.clj:155)
        at trader.core$_main$fn__10988$state_machine__8040__auto____11009.invoke(core.clj:155)
        at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:978)
        at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:977)
        at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:982)
        at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:980)
        at trader.core$_main$fn__10988.invoke(core.clj:155)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at clojure.core.async.impl.concurrent$counted_thread_factory$reify__1811$fn__1812.invoke(concurrent.clj:29)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.lang.Thread.run(Thread.java:748)
I'm using the latest version, so I assume this method should be avaiable [com.googlecode.lanterna/lanterna "3.0.3"] If someone could point out what I'm doing wrong I'd appreciate it

phronmophobic20:10:01

the only things I can think to try are: 1. trying the call in repl on a non async thread. 2. making the reflection call yourself to see what methods exist. maybe that can point to false assumption

phronmophobic20:10:41

based on your description, it seems like it should work

p-himik20:10:57

Indeed, it worked for me in REPL just fine:

(import com.googlecode.lanterna.terminal.DefaultTerminalFactory)
=> com.googlecode.lanterna.terminal.DefaultTerminalFactory
(def tf (DefaultTerminalFactory.))
=> #'user/tf
(def term (.createTerminal tf))
=> #'user/term
(import com.googlecode.lanterna.gui2.MultiWindowTextGUI)
=> com.googlecode.lanterna.gui2.MultiWindowTextGUI
(import com.googlecode.lanterna.screen.TerminalScreen)
=> com.googlecode.lanterna.screen.TerminalScreen
(def screen (TerminalScreen. term))
=> #'user/screen
(def gui (MultiWindowTextGUI. screen))
=> #'user/gui
(.startScreen screen)
=> nil
(.getFocusedInteractable gui)
=> nil

Kevin20:10:46

What does it mean to "make the reflection call yourself" ?

p-himik20:10:40

Something like this, only for MultiWindowTextGUI.

phronmophobic20:10:32

make the reflection call yourself

(require 'clojure.reflect)
(clojure.reflect/reflect com.googlecode.lanterna.gui2.MultiWindowTextGUI)

👍 3
phronmophobic20:10:03

just to list what methods come up. it probably won't say anything too surprising, but it will at least let you know that the method does or doesn't exist

p-himik20:10:12

I would also check the class path to make sure that 3.0.3 is indeed the version that gets loaded.

phronmophobic20:10:42

one other thing that can happen if you're calling from weird threads is that thread's class loader isn't the right one. not sure if that applies here, but in your top level, you can do :

(def main-class-loader @clojure.lang.Compiler/LOADER)
then right before you make the getFocusedInteractable call, do
(.setContextClassLoader (Thread/currentThread) main-class-loader)

phronmophobic20:10:48

I think clojure.core.aync handles a lot of those weird issues for you, but if nothing else is working, it's worth a shot

Kevin20:10:12

Interesting, I was also calling this within a go-loop, maybe that's the issue

Kevin20:10:59

Ok, that seems to be the issue. So I can't call this method within a different thread?

phronmophobic20:10:22

you just need to set the thread's context class loader to match the clojure compiler's class loader

Kevin20:10:59

So within the go-loop call (.setContextClassLoader (Thread/currentThread) main-class-loader) ?

phronmophobic20:10:28

although, I thought clojure.core.async did that for you

phronmophobic20:10:40

which thread are you starting the go-loop from?

Kevin20:10:48

The main thread

Kevin20:10:08

But this doesn't seem to resolve it. I'll try creating a new thread normally

Kevin20:10:32

I am so lost, I had it working in the main thread, now this doesn't work anymore

(defn -main [& _args]
  (let [terminal (.createTerminal (DefaultTerminalFactory.))
        screen (TerminalScreen. terminal)
        gui (MultiWindowTextGUI. screen)]
    (.startScreen screen)
    (.getFocusedInteractable​ gui)))

phronmophobic20:10:00

how are you running it?

phronmophobic20:10:04

can you add:

(prn "thread: " (Thread/currentThread) )

Kevin20:10:19

well... I found the issue

Kevin20:10:14

So I think there's some kind of special character in 1 of my example codes

Kevin20:10:30

I have 2, one works, the other doesn't, and they are literally equal

Kevin20:10:29

This is so stupid 😕

Kevin20:10:56

Thanks for helping out though. Can't believe I spent so much time with this

p-himik20:10:58

Yeah, a common case of "those two bytes just cost me 8 hours", quite frustrating.

Kevin20:10:15

I think I copied @U2FRKM4TW code, which was pretty much the same as what I did, but his actually worked. Then later I must've copied back the bad text and it broke again

Kevin20:10:27

I can't believe this 😂

😡 3
Kevin20:10:55

Hidden space, great stuff. I guess copied from API docs or something. I have no idea

Kevin20:10:11

Thanks again, friends!

👍 6
JAtkins20:10:58

random shooting the breeze - I think as a community we under-utilize the fact that clojure code is data. Why spend so much time organizing code if code is data? Currently we view our (code/data) from only one perspective - file based. Maybe open multiple files. Jump around with stuff like `go-to-definition`.  But why do we constrain ourselves like that? Data science people have workflows designed around producing alternate views of the data. Maybe a tool that we are missing as programmers is a tool that looks at our code as data and re-formats it for our use based on the problem at hand? Does this even make sense? 😜

phronmophobic20:10:01

it makes sense, but there's a lot of inertia regarding text based source formats (editors, IDEs, version control, etc)

Lone Ranger20:10:43

Totally. Check out the end of @U5K8NTHEZ’s talk on Meander for a really inspired vision on this topic: https://www.youtube.com/watch?v=9fhnJpCgtUw&amp;m=7

JAtkins20:10:58

ive not thought it through fully, but I don't think those are by necessity deal breakers. Storing code in the files is sensible (though unison may be an interesting alternative look - http://unisonweb.org). Perhaps it would be more clear if I put out an example... e.g.

(defattr :a {:t1 value
             :t2 value
             ...}

(defattr :b {:t1 value
             :t2 value
             ...}

JAtkins20:10:45

maybe you want to see only :t1 for each attr. could be done by creating a view of the code

JAtkins20:10:07

@U3BALC2HH oo, I've seen that before. Forgot that he talked about this though 🙂

p-himik20:10:41

There have been many attempts to create something along those words. I believe some ideas originated from Engelbart and some things were even implemented in Xerox Alto. But it never had any serious traction. There are still undergoing attempts though, I know of http://www.andrewbragdon.com/codebubbles_site.asp and https://github.com/JJ-Atkinson/Fisher

JAtkins20:10:24

oh, lol, that's my repo

JAtkins20:10:43

I'm actually thinking about this as a feature for Fisher

JAtkins20:10:06

not quite the same as code bubbles

p-himik20:10:37

Oh, oops. :D

p-himik20:10:15

Yeah, I get that. I just mentioned that because the overall concept is the same - being able to focus on something in particular, no matter what the "lens" looks like.

JAtkins20:10:28

true. I guess I've been thinking along these lines for a while 🙂

p-himik20:10:46

IntelliJ IDEA has some interesting features as well that are somewhat relevant. Namely, analyzing data flow: https://www.jetbrains.com/help/idea/analyzing-data-flow.html But all such focusing/lensing/analysis goes out of the window as soon as there's anything dynamic going on. Even a simple (keyword n) would mess things up.

JAtkins20:10:26

that's really cool

zilti20:10:14

The problem is also that not everything in a Clojure sourcecode file is data. ;; comments are not. Empty lines for separation are not. Neither is formatting.

p-himik20:10:17

@U5P29DSUS I guess. And you can go all the way to the pure lambda calculus. :) The issue is that any useful program written using lambda calculus would almost certainly be incomprehensible. So far it seems that practicality demands sacrifices that, in turn, beget other, indirect, sacrifices.

JAtkins20:10:44

@U2APCNHCN 3 possibilities. make comments data (metadata even?), enforce a standard formatting rule, and re-implement the original use of custom formatting by creating custom views of the code ... though if you are breaking a formatting rule it's typically a boutique case and maybe not possible to create general rules for

zilti20:10:31

@U5P29DSUS What would you do when you want to, e.g. have a long map where the entries are aligned such that the values all start in the same column? Do you add metadata to the map?

phronmophobic20:10:20

I don't think formatting is that big a deal. gofmt let's go users not have to worry about formatting which seems like a good thing

JAtkins20:10:22

I dunno. I kind of think formatting is a moot point most of the time. I'd like to see the editor try to maintain formatting rules to show to the programmer, and maybe when saving the file to git put the file back in the default formatting. Would allow each programmer to see code how they want, and not have tons of formatting clashes on the way out

phronmophobic21:10:31

I think the tougher challenges are around all the other tooling that expects files: packaging, making jars, version control, code editors, grep, etc.

JAtkins21:10:57

right. I'm just wondering if it's possible (or, more accurately if it's useful), to use transformations to create views of our code for debugging or project exploration.

zilti21:10:51

These challenges have been solved basically. There have been languages in the past that didn't use files, but instead an "image". The one language today doing that I am aware of is Pharo. The code you see there is merely a serialization of the image / VM state.

seancorfield21:10:35

The original proof of concept for LightTable was focused on functions and call trees but when they tried it with focus groups, folks complained it was too hard/unfamiliar and wanted something more file-based... so really only the auto-eval/inline-results survived from that early concept.

seancorfield21:10:50

Well, I guess some of the ideas of visualizing data in the editor did too (something that ProtoREPL offered for Atom -- but that's no longer maintained). Now folks are using REBL and Reveal alongside "regular editors" as a way to do that sort of visualization and data navigation.

isak22:10:16

I like the idea. I think all of the problems people have brought up so far (except for the text editor) could be solved by just saving all the code into 1 file. I think having multiple views is useful. These days even the worst editors, like one one in visual studio supports more than one "vertical view" (like emacs), and this sounds like it would be even better. Having project scaffolding with default view definitions that people can commit to the codebase would help with the on-boarding. One challenge is what properties should you automatically assign to a function/class/etc based on the view it is typed into? Could probably think of something reasonable, though.

zilti22:10:36

I think what Pharo does is that you actively have to add a property/method/whatever to a class

isak22:10:38

Another challenge would be how to deal with imports/requires. You would need something way better than the stuff in Clojure, for example. I guess imports/requires would need to be global, and the way "`rf/dispatch`" expands to re-frame.core/dispatch being controlled by another view-like definition.

isak22:10:08

@U2APCNHCN Hmm, wouldn't that mean your functions could disappear on you from your view if you forgot something? Seems like an easy mistake

seancorfield22:10:50

I was very excited about the early LT concepts -- I would have loved to try it out. It would have been interesting to see how it would scale to a really large code base. I think Clojure definitely could be a good target for an editor that treated every top-level form as a "thing" to be edited but there would need to be a huge amount of semantic support (ordering of definitions for the purpose of feeding them to the compiler/REPL for starters).

zilti22:10:51

Well, there are just two ways to write code in Pharo, you either write and evaluate something on the "scratch pad" which just alters the image you are running; or if you want permanent code, you choose a class, then write the code inside it

3
JAtkins22:10:29

@U04V70XH6 That's the goal of Fisher. I've run out of time to work on it short term (startup is starting to get into sell mode :P). I plan to possibly monetize it and get a team together. Dunno, would need a proof of concept though before I do all that.

seancorfield22:10:16

just looking over the readme sounds very cool (and a lot of work 🙂 ).

Jose Varela23:10:30

Someone mentioned Pharo in the thread, thought you’d like this: https://gtoolkit.com/ I think this app may give you some ides @U5P29DSUS

JAtkins23:10:28

yup, thanks

JAtkins23:10:46

@U016Y9K11H9 It's actually really really cool. I'm gonna have to dig into this a bit 😉

didibus02:10:42

I'll argue something here, the issue is 2D visualization are too limited, so text can convey more complicated graphs

didibus02:10:05

Something like: `(let [a (foo) b (bar a) c (baz a :with-option) d (biz b c)] (buz d))`

didibus02:10:19

What visualization here would make this clearer?

JAtkins03:10:11

It’s just a different angle. Also, I’m thinking here of code->alt code visualizations.

JAtkins03:10:45

Reorganizing events, hiding ui stuff, joining attributes by a key, etc

JAtkins03:10:17

If specs are widespread, maybe using that info about the code in interesting g ways

phronmophobic03:10:20

not the best sketch, but I think this type of graphic could emphasize the dependencies

didibus03:10:39

Maybe, but I don't know, personally I'd rather look at the let then such a graph, but I can't tell for sure. I used to program a bit in Max/MSP, which was just everything as nodes connected by lines visually, and I wouldn't say it was any easier to read and follow. I think its because most real life use case, there will be too many dependencies and then you just have to many lines going to too many places

phronmophobic03:10:56

you don't have to pick just one

phronmophobic03:10:40

you can multiple representations and work with the ones that are most convenient for the purpose you're trying to accomplish

didibus03:10:08

Ya true, but a part of the question is if it is worth the effort to build such alternate visualizations to begin with. And so the question would be, how often would I switch away from the text representation? 50% of the time? 10%? 0.5%

didibus03:10:59

And I feel for me, its say... ok when do I struggle to read code in a way that an alternate representation would make it obvious, and what would that even be?

phronmophobic03:10:54

It's very difficult to tell how good a tool, method, or workflow is until you try it which means that's it's very difficult to predict ahead of time how effective it would be

phronmophobic03:10:39

I think software development still has a long way to go before we start running out of improvements.

seancorfield04:10:55

Anyone remember Together/J? It was a Java IDE that was also a UML drawing system and it could round-trip between code and UML diagrams for certain diagrams. You could modify the code and the diagrams would update or modify the diagrams and the code would update. I loved it, but there was definitely a limit to how far you could go in each direction.

didibus04:10:31

Was it good because the UML view allows you to avoid typing all the Java boilerplate?

seancorfield04:10:51

It was good because it allowed for multiple "views" of the code at different levels of abstraction. I hadn't thought about it for a while but this thread triggered by memory...

seancorfield04:10:34

But they weren't really just "views" -- it wasn't just visualization of code -- it was different levels of abstraction that you could "edit" the program at.

didibus04:10:45

Ya, that seems neat, especially in Java, like if I could just move class arounds, nest them, unnest them, etc. All through some visual view.

didibus04:10:38

I guess I hadn't thought what the other views could allow in terms of editing the code. I was thinking just in terms of reading it

zilti11:10:25

I think on the low level, plain-text code is the way to go. But I think it is interesting to have alternatives for the higher-level where you connect stuff. https://en.wikipedia.org/wiki/DRAKON was, at first glance, seemingly an interesting take on this

JAtkins17:10:23

That's really cool. I'll have to look into both of those.

Jose Varela17:10:30

GToolkit deals with the concept mentioned by @U04V70XH6 the idea is that as you browse your codebase you can query constructs like classes, methods, modules, etc and generate custom views of queries and individual componentes in the codebase Youn can then clickthrough these until you end up in the actual code for the class and/or method

subsaharancoder21:10:08

Does anyone have experience using Jib https://cloud.google.com/java/getting-started/jib to build Clojure containers for GCP? There's very little info online and the only example I have is for a lein project and none with CLI and deps.edn

dominicm13:10:05

Yeah, pack has a jib builder you can use!

dominicm13:10:17

JUXT/pack.alpha

zilti21:10:27

Sometimes I wonder where we'll stop. At how many levels deep. After packing a VM into a pseudo-VM into a VM using a config file that's been generated by a config file plus a tool, in turn generated from another config file plus tool...

p-himik22:10:21

As soon as we finally implement "Turtles all the way down". :)

zilti22:10:38

Meanwhile, for our company, I've just created a short Ansible script that deploys the server. And all the CI pipeline for our project does is to build the project, scp it to that server, and send an ssh command to restart the service. I hope I can stay away from Docker for as long as possible

sogaiu00:10:20

iiuc docker may go away, but you get podman and its friends instead...

xceno22:10:13

Hey guys, weird error happening here: I've got a ring based app, deployed as a datomic ion behind an AWS API Gateway that acts as lambda proxy as described here: https://docs.datomic.com/cloud/ions/ions-tutorial.html#lambda-proxy It works so far, but when i enable ring/ring-defaults with the following config {:session true} the AWS Api Gateway (not the app itself) crashes with: Execution failed due to configuration error: Malformed Lambda proxy response However, I double-checked and my ring-reponse seems still valid. Any ideas on how to tackle this problem?

xceno00:10:49

To future readers, who may find this in a slack archive or zulip mirror: I found the problem. It's the Set-Cookie header. When configuring the middleware like this:

(ring.middleware.defaults/wrap-defaults
 {:session true
  :security  {:anti-forgery   true
              :hsts           true
              :ssl-redirect   false
              :frame-options  :sameorigin
              :xss-protection {:enable? true
                               :mode    :block}}})
it will add a header like this:
"Set-Cookie" ("ring-session=17a0900a-00b0-42ea-b54d-fbeec2acb15e;Path=/;HttpOnly")
Notice that the value is a seq, and that's the issue. The value must be a string for the AWS API Gateway to pass it through correctly. Adding an ugly workaround like this additional middleware fixes the issue:
(defn fix-aws-api-gateway-cookie-header [handler]
  (fn [req]
    (let [res (handler req)
          cookieList (get-in res [:headers "Set-Cookie"] [])]
      (assoc-in res [:headers "Set-Cookie"] (or (first cookieList) "")))))

jmckitrick22:10:27

What would be the closest thing to Scala futures in Clojure? Core async? Is it as performant?

seancorfield00:10:49

They look like Clojure future and promise -- what am I missing?

vncz12:10:07

What's a feature vs a promise?

jmckitrick12:10:08

Sorry, I should have been more clear. Scala futures let you map over them, use for comprehensions to make it all readable and abstract away the future, etc.

jmckitrick12:10:53

So you never actually ‘await’ or deref the future, that’s all part of the for/map/flatMap machinery.

jmckitrick12:10:08

I thought maybe core.async would be the closest thing to that.

seancorfield16:10:09

@U061KMSM7 As I recall, they're just one-element "containers" so the flatMap stuff always felt a bit weird to me. It's been most of a decade since I last did any Scala production work tho' so I may be misrememberinng.

seancorfield16:10:33

Hmm, looking at them again, it seems they have a bit more functionality than that 🙂 I would likely still just use future in Clojure for most of what they show in the examples (deferring a single computation to a thread) but for composition it would really depend on what I was trying to achieve I guess. In complex composition of processes where I needed everything to potentially be computed concurrently with synchronization points, maybe I'd use core.async. But, overall, core.async isn't something I reach for a lot: it adds a lot of incidental complexity to code in my opinion.

jmckitrick17:10:33

I just found this article today:

jmckitrick17:10:50

Not exactly the same thing, but the same concept.

jmckitrick17:10:21

So a simple use case in scala, is fetching several items from the db, and each query is a future. The map/flatMap/for construct lets you write a simple ‘for’ comprehension that abstracts away the future but still wraps the result as a future to pass back up the stack.

jmckitrick17:10:57

I guess since Clojure doesn’t mess around with async db queries by default, it’s not really an issue, and regular futures and promises would do the trick.

jmckitrick17:10:28

This makes me wonder how the Clojure aleph server works. Isn’t that the one that handles all requests asynchronously?

seancorfield18:10:29

No idea. Never used it. I don't think it's maintained any more?

seancorfield18:10:05

That AppsFlyer article is about a monad (the Error monad?) and working with monadic constructs in Clojure is kind of hard because monads are better suited to statically typed languages. Scala leverages monadic constructs heavily -- which is why the approach doesn't translate directly (or even at all) into Clojure 😐

jmckitrick18:10:02

Makes sense. I just like finding similarly elegant constructs in Clojure to somewhat match what I’ve seen and liked in other languages.

seancorfield18:10:59

Yeah, I hear you. I'm not sure what I'd turn to in Clojure as a direct translation of a monadic Future -- I don't recall ever needing to essentially map f over something in a way that I would want it to be treated as, essentially, #(future (f (deref %))) which is what the Scala Future is doing in that situation. I suppose you could (pmap (comp f deref) collection-of-derefables) but pmap is usually a Bad Idea in the first place. Back when I did Scala for a living, I hated the implicit stuff because it always felt like it only existed to "workaround" the type system -- and it made code horrible to read/reason about because you couldn't just look at it and see what it did.

seancorfield18:10:34

I was very glad to switch from Scala to Clojure and get away from the madness that is Scala's type system 🙂

jmckitrick19:10:23

Oh, but haven’t you heard? Dotty (scala 3) is going to fix all of that….

jmckitrick19:10:26

And yes, I hate those things about scala as well….

seancorfield19:10:02

Hahaha... that Dotty type system overhaul has been in the works for years... I remember a preso about it at Strange Loop... Just had to look it up: it was seven years ago!

jmckitrick11:10:57

Well, it’s happening this time. Sometime this month?

rob16:10:22

Hey @U061KMSM7 — take a look at manifold, the async library used by aleph. It sounds like the api is a bit closer to what you are looking for

rob16:10:36

and you can do seq-like operations on “streams of deferreds” https://github.com/aleph-io/manifold/blob/master/docs/stream.md

jmckitrick16:10:52

You’re exactly right. That’s close to what I was talking about. Thanks!

👍 3
emccue02:10:07

@U061KMSM7 I always feel like I am taking crazy pills when people mention it, but scala doesn't have async db queries

emccue02:10:59

it all boils down to JDBC which is totally synchronous, there is no "explicit yield point" to take advantage of

emccue02:10:36

So the Future[T] there is often just a lie on top of a threadpool

emccue02:10:55

If you want to do the monadic stuff in clojure, here you go http://funcool.github.io/cats/latest/

emccue02:10:30

but for db calls i need to stress that there is no benefit unless I am very wrong

jmckitrick11:10:57

@U3JH98J4R I did not know that. Very interesting. Which makes all that fancy syntax of little benefit. I guess the only thing it does it let you map db results back to web server responses, and I’m pretty sure those are asynchronous.

dpsutton23:10:24

how can i import a nested enum? https://github.com/apache/mina-sshd/blob/master/sshd-common/src/main/java/org/apache/sshd/common/session/SessionHeartbeatController.java#L36 i'm trying [org.apache.sshd.common.session.SessionHeartbeatController $HeartbeatType] but its not finding a class there

dpsutton23:10:32

its an enum of an interface

dpsutton23:10:39

[org.apache.sshd.common.session SessionHeartbeatController$HeartbeatType] is apparently it. I thought we could import nested classes but i guess we can't

hiredman23:10:56

you can, that is the name of the class

dpsutton23:10:44

[org.apache.sshd.common.session.SessionHeartbeatController $HeartbeatType]?