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" "<https://clojars.org/repo>"}))
{[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
@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?
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 😐
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)
@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 😐
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.
Signing doesn’t tell you anything about whether you trust the identity of the signer
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 <http://github.com|github.com>
(me!) or seancorfield
on some other servicer provider? (potentially not me, but mostly I'm the only seancorfield
everywhere as far as I know)
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
Someone couldn't then come and have a org.corfield/next.jdbc since seancorfield verified that it owned the domain.
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).
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.
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
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
And people who want to publish without wanting to validate can use groupId that are not of those format
Like I said, take it up in #clojars and see how receptive the maintainers are to these suggestions.
Also, there's no obvious connection between the domain I own <http://corfield.org|corfield.org>
and the username I have on almost every service seancorfield
so I'm not sure how domain verification would even work in that case?
Is it possible to add default implementation for protocol method?
I think you can by extending it for type Object
That's seems kinda nasty.
Is it possible to extend the type in record?
That would be better since I would not have to mess with Object.
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.
You want it implemented for all record types?
I'm sure there's some similar parent that all record belongs too that you could use?
Wait, could it be you just want to use the same functions as the implementation for multiple record types?
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
@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.
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
A bit like done here https://clojuredocs.org/clojure.core/extend#example-5be9f7e9e4b00ac801ed9ef3
Thank you @didibus. This is great! Do you know whether it's possible to get record function by keyword?
Not sure what you mean?
hi! any way to mix expound
's human-readable spec errors with orchestra
instrumentation?
I tried setting s/*explain-out*
to expound/printer
, but when there's a spec error I'm still getting the normal explain output
Hm, this should work. If you post your code in #expound I may be able to spot the issue
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.
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.
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?
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
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
I think you are outside the bounds of what deps.edn supports
It happens whenever code using the macro is compiled. That could be at aot compile time, or load time.
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)
I'm not sure if this is idiomatic, but works for our use case just fine!
http://clojure.com seems to be down
isn't it http://clojure.org, or does it have another domain i dont know
ohhh you're right. I think the dot com used to redirect somewhere at least? I clicked a dead link somewhere
.com has not existed for a long time
Hi everyone,
is there a way to parse timestamp with whatever format ?
but you still need the format as input, i have wrote another function which check the predicated format.
No you don't - there are two arities, the second one accepts only a single string.
Sure, what do you have in mind?
Clojure folks tend to rely on existing Java libraries for this, I believe.
what java libs you may suggest that helps here?
what do you mean?
Java, since version 8, has very good build-in time support, under the java.time
package
Several different classes for different purposes, many with Java methods whose name contains "parse"
i think the most worth here is java.text.SimpleDateFormat
but that takes format
maybe i need to write another function to determine the date format at first
then parse it
anyway thanks guys
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.
Any given application you have hopefully you can limit them to a small set of acceptable formats.
If your goal is "recognize dates/times in any way a human might recognize", then you are in AI/machine-learning territory.
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
i think i'll define some regexp for specific number of timestamp format, then search which regexp is right for it
after determine the format i'll parse it
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
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
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?
reitit
Thanks!
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
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 itthe 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
based on your description, it seems like it should work
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
What does it mean to "make the reflection call yourself" ?
Something like this, only for MultiWindowTextGUI
.
make the reflection call yourself
(require 'clojure.reflect)
(clojure.reflect/reflect com.googlecode.lanterna.gui2.MultiWindowTextGUI)
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
I would also check the class path to make sure that 3.0.3
is indeed the version that gets loaded.
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)
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
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? 😜
I'll argue something here, the issue is 2D visualization are too limited, so text can convey more complicated graphs
Something like: `(let [a (foo) b (bar a) c (baz a :with-option) d (biz b c)] (buz d))`
What visualization here would make this clearer?
It’s just a different angle. Also, I’m thinking here of code->alt code visualizations.
Reorganizing events, hiding ui stuff, joining attributes by a key, etc
If specs are widespread, maybe using that info about the code in interesting g ways
not the best sketch, but I think this type of graphic could emphasize the dependencies
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
you don't have to pick just one
you can multiple representations and work with the ones that are most convenient for the purpose you're trying to accomplish
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%
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?
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
I think software development still has a long way to go before we start running out of improvements.
Yup
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.
Was it good because the UML view allows you to avoid typing all the Java boilerplate?
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...
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.
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.
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
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
That's really cool. I'll have to look into both of those.
GToolkit deals with the concept mentioned by @seancorfield 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
it makes sense, but there's a lot of inertia regarding text based source formats (editors, IDEs, version control, etc)
Interesting, I was also calling this within a go-loop, maybe that's the issue
Totally. Check out the end of @jimmy’s talk on Meander for a really inspired vision on this topic: https://www.youtube.com/watch?v=9fhnJpCgtUw&m=7
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
...}
maybe you want to see only :t1 for each attr. could be done by creating a view of the code
@goomba oo, I've seen that before. Forgot that he talked about this though 🙂
Ok, that seems to be the issue. So I can't call this method within a different thread?
you just need to set the thread's context class loader to match the clojure compiler's class loader
So within the go-loop call (.setContextClassLoader (Thread/currentThread) main-class-loader)
?
right
although, I thought clojure.core.async did that for you
which thread are you starting the go-loop
from?
The main thread
But this doesn't seem to resolve it. I'll try creating a new thread normally
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
oh, lol, that's my repo
I'm actually thinking about this as a feature for Fisher
not quite the same as code bubbles
Oh, oops. :D
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.
true. I guess I've been thinking along these lines for a while 🙂
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.
that's really cool
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)))
Reminds me of https://futureofcoding.org/essays/dctp#d-is-for-denotative
how are you running it?
can you add:
(prn "thread: " (Thread/currentThread) )
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.
@jatkin 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.
well... I found the issue
@zilti 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
@p-himik yup
So I think there's some kind of special character in 1 of my example codes
I have 2, one works, the other doesn't, and they are literally equal
doh!
This is so stupid 😕
Thanks for helping out though. Can't believe I spent so much time with this
Yeah, a common case of "those two bytes just cost me 8 hours", quite frustrating.
I think I copied @p-himik 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
:bananadance:
I can't believe this 😂
Hidden space, great stuff. I guess copied from API docs or something. I have no idea
Thanks again, friends!
@jatkin 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?
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
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
I think the tougher challenges are around all the other tooling that expects files: packaging, making jars, version control, code editors, grep, etc.
When you require in a macro to a ns is that classified as load time?
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.
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
Yeah, pack has a jib builder you can use!
JUXT/pack.alpha
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.
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...
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.
When you load the ns that does the require, yes
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.
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.
As soon as we finally implement "Turtles all the way down". :)
I think what Pharo does is that you actively have to add a property/method/whatever to a class
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.
@zilti Hmm, wouldn't that mean your functions could disappear on you from your view if you forgot something? Seems like an easy mistake
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
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).
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
@seancorfield 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.
just looking over the readme sounds very cool (and a lot of work 🙂 ).
yes 🙂
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?
What would be the closest thing to Scala futures in Clojure? Core async? Is it as performant?
What's a feature vs a promise?
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.
So you never actually ‘await’ or deref the future, that’s all part of the for/map/flatMap machinery.
I thought maybe core.async would be the closest thing to that.
@jmckitrick 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.
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.
I just found this article today:
Not exactly the same thing, but the same concept.
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.
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.
This makes me wonder how the Clojure aleph server works. Isn’t that the one that handles all requests asynchronously?
No idea. Never used it. I don't think it's maintained any more?
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 😐
Makes sense. I just like finding similarly elegant constructs in Clojure to somewhat match what I’ve seen and liked in other languages.
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.
I was very glad to switch from Scala to Clojure and get away from the madness that is Scala's type system 🙂
Oh, but haven’t you heard? Dotty (scala 3) is going to fix all of that….
And yes, I hate those things about scala as well….
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!
Well, it’s happening this time. Sometime this month?
Hey @jmckitrick — 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
https://github.com/aleph-io/manifold/blob/master/docs/deferred.md
and you can do seq-like operations on “streams of deferreds” https://github.com/aleph-io/manifold/blob/master/docs/stream.md
You’re exactly right. That’s close to what I was talking about. Thanks!
@jmckitrick I always feel like I am taking crazy pills when people mention it, but scala doesn't have async db queries
it all boils down to JDBC which is totally synchronous, there is no "explicit yield point" to take advantage of
So the Future[T]
there is often just a lie on top of a threadpool
If you want to do the monadic stuff in clojure, here you go http://funcool.github.io/cats/latest/
but for db calls i need to stress that there is no benefit unless I am very wrong
@emccue 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.
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
its an enum of an interface
[org.apache.sshd.common.session SessionHeartbeatController$HeartbeatType]
is apparently it. I thought we could import nested classes but i guess we can't
you can, that is the name of the class
[org.apache.sshd.common.session.SessionHeartbeatController $HeartbeatType]
?
Someone mentioned Pharo in the thread, thought you’d like this: https://gtoolkit.com/ I think this app may give you some ides @jatkin
yup, thanks
@joservarelaf It's actually really really cool. I'm gonna have to dig into this a bit 😉