This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-28
Channels
- # aws (1)
- # beginners (30)
- # boot (7)
- # cider (52)
- # clara (91)
- # cljs-dev (33)
- # cljsjs (1)
- # clojure (447)
- # clojure-brasil (3)
- # clojure-dev (16)
- # clojure-dusseldorf (5)
- # clojure-filipino (1)
- # clojure-italy (29)
- # clojure-sanfrancisco (5)
- # clojure-spec (62)
- # clojure-uk (37)
- # clojurescript (145)
- # clojurewerkz (1)
- # code-reviews (12)
- # community-development (157)
- # cursive (5)
- # datascript (1)
- # datomic (27)
- # editors (42)
- # emacs (5)
- # fulcro (31)
- # hoplon (2)
- # jobs (2)
- # keechma (1)
- # lumo (31)
- # off-topic (2)
- # om (1)
- # onyx (13)
- # parinfer (8)
- # re-frame (13)
- # reagent (32)
- # remote-jobs (4)
- # shadow-cljs (103)
- # spacemacs (15)
- # specter (10)
- # sql (1)
- # tools-deps (35)
- # unrepl (13)
how to use clj command to launch a repl and specify repl’s port?
when man clj
I found clj has a parameter: --repl , but where to specify port?
clojure has a built in socket repl that you can cause to be launched by passing the right -D arguements to the jvm
@foxlog Here's my ~/.clojure/deps.edn
file that provides aliases to start a socket REPL, a Rebel-Readline REPL, or an nREPL -- the first and last on port 5555 since I choose to hardcode that.
I guess it would be nice to have some sort of environment variable substitution available in deps.edn
but maybe that's moving too far out of scope of the intention of the tool... 🙂
@camdez I am using using your sendgrid library to send email. Great lib by the way 🙂 But i'm having trouble sending emails to multiple recipients. Could you please help me with that? I don't really understand how to send it this way to[][email protected]&to[][email protected]
@vellalpavani Happy to help. Let’s continue via DM. At a jazz bar right now but I’ll do what I can. :rolling_on_the_floor_laughing:
I'm comparing the developer experience of PaaS offering of AWS, Google, Azure and Heroku with a Clojure & PostgreSQL example app. My plan is to create a blog post and a talk on the topic. Currently it feels like Heroku is winning this one: https://twitter.com/ykarikos/status/977995307370909696
@yka do you know of a faas that supports clojure ?
@fahd.elmazouni well, if there’s a JVM you can run Clojure. Personally I’ve tried both Clojure (JVM) and ClojureScript (Node) on AWS Lambda. Some tooling exists also: https://github.com/uswitch/lambada https://github.com/mhjort/clj-lambda-utils https://github.com/portkey-cloud/portkey (aims to provide REPL-like development experience for writing AWS Lambda functions)
cool ! thanks ! do you think there might be a loss in performance ? if I run clojurescript on Node 6 ?
(sorry if I'm asking outside of the proper channel)
No problem. 🙂 I don’t know about the performance impacts but at least I haven’t experienced anything noticeable. My stuff hasn’t really been that perf-critical though.
okey thanks ! I'm trying to learn javascript the functional way ( for backend ) and I'm always under the impression I'm doing it wrong
If your going CLJS and Lambda, I’ve had good experience with this https://github.com/nervous-systems/serverless-cljs-plugin
Thanks ! I'll look into it
@fahd.elmazouni if you want the deep dive on the subject, check out https://www.youtube.com/watch?v=GINI0T8FPD4
thank you !
Regarding https://danielcompton.net/2018/03/28/clojure-survey-2018 . We probably shouldn't be overly navel-gazing as a community. However, couple of themes seem recurrent in consecutive surveys: (1) Error messages should be better (2) pace of language development should be better. I'm curious about the core-team's thoughts on these.
As a "community member" I disagree with (2) and think that may be more of a condition that is pathological to all language communities. Plus 1 for error messages.
1) agree 2) we work at the pace we work
@mailgrease that's a really interesting article though and there's a lot of takeaways
One thing I wonder: what if you plotted the number of messages in #jobs #remote-jobs etc? I could be wrong but it seems like the number of jobs is increasing rapidly.
could you point me to your info channels? i'm actively looking for a clojure job. thanks 😃
Well, I use feedly. There's a convenient search feature in there that let's you automatically pull in RSS feeds from related sites.
And then there's all the jobs channels in here. And of course the "functional jobs" website and the clojure jobs on clojure brave and true site.
you can also add your name here: http://www.clojureconsultants.org/
For 2. it does feel like some tasks could be directed at the community with a little direction and decent feedback loop.
I am sure there are some moderately low hanging fruits at least that could be solved that way
I think 'core' team hasn't wanted to play favoritism towards tools and methods for a long time. Which is why they let lein and boot have free reign. But I think some more control would help too
Definitely feel like error handling ought to bubble up to the top, and I feel like spec has the potential to make some really useful error messages possible. I don’t feel like there’s any problem with the pace of development.
I personally do not believe in the idea of “one way to do it”. I think we as a community should consider everything, try new things, and always be searching for a better solution.
It is imo not the core team’s job to choose and promote a single stack for web development for example
The pace of core language development is slow, or said another way “Clojure is a very stable language and my code works the same over many releases”.
As Rich has said “Clojure is a small language, and intends to remain so”
I agree with what tim baldridge said in the reddit thread: > Personally I would love it if new development on Clojure almost completely stopped, and instead development focused on fixing the lacking features in spec, the weirdness transducers (when is (fn []) of a transducer called?), all the problems with core.async's semantics, and in general just polished the coded added in the past 4 years.
personally, I would like to add "bring the compiler up to speed with new JVM improvements" to that list 😉
well, sorry
we’re not going to stop trying to solve important problems
I think it is exactly what you’re saying “I would love it if new development on Clojure almost completely stopped”
I would like to have a more even budget of time on maintenance level work
and that’s something we have been trying to figure out for a long while
if I would be equally uncharitable in my interpretation, I could say that you just said "fixing bugs and maintenance is not an important problem that we want to solve"
but let's not argue semantics. allow me the rephrase the statement as "on the scale of new features and maintenance, let's take a slight step towards maintenance" 🙂
then, agreed
take a look at http://jafingerhut.github.io/clj-ticket-status/CLJ-top-tickets-by-weighted-vote.html though - we look at votes as one signal for which bugs people care about (and fix many of the highest ones in each release). There are only 3 defects with 10+ votes. There are certainly bugs to fix in Clojure but I think it is actually pretty rare that you encounter bugs in Clojure that prevent you from getting your work done. spec is definitely an area where we have some known issues right now and I very much hope to get back to it soon.
Tim had the opportunity to spend any Friday he wanted at Cognitect working on Clojure or core.async maintenance
I think he still has commit rights on core.async and I’d welcome his help on the backlog
Eh, I have commit rights, but not rights to actually do development 😄 Any questions of semantics and bugs in core.async have to go through the long drawn-out process of any other patch to Clojure libs.
that’s not entirely true in core.async
I have asked him repeatedly to help on specific areas where he is the expert and he has chosen not to
Yes, I got tired of the process and the lack of direction in the library. I even asked for permission to have more control over the library and was told "we got it from here".
I loved working on the library when we had rapid iterations, feedback between team members, and clear direction as to where the library needed to head.
But today it's a toolbox of features that each differ a bit in semantics. Things like close!
semantics are still open-ended. Some are propagated down, some aren't. Some primitives allow for upward propagation, others don't.
I got tired of asking for input on these things. So when I was told it was moving into core for better management I said "Great! I wish you luck" and walked away.
if everybody that's ever contributed to clojure has burned out from it, there must be a reason
repeating that there's no problem when clearly an increasingly number of people (most of whom are past contributors) think there is, is not going to make it go away
what do you think would make the biggest difference?
@alexmiller not having a bus factor of 1
that’s not an action
when I do ask for help, people rarely do
"help gets turned down"?
@alexmiller that's because people are not willing to help when somebody else's asks for it, they're willing to help when they have time and will for it
if I keep offering my help and it gets turned down, and then you go "hey, please help now", I don't have time or will to invest more time now, I had it for the past 6 years
I just made a few contributions to cljs. It was pretty easy. I can understand if I made a big change and it didn't get accepted, how that could be frustrating. But look at the constant contention with linus torvalds and the linux community. Does anyone thing that this developer contention will ever go away? Or that it's necessarily a bad thing?
you run multiple contrib projects autonomously and have 38 commits in Clojure
how are we not accepting your help?
everyone wants to bikeshed how the code is formatted but very few want to go fix that gnarly compiler bug that takes a week (you excluded Bronsa :)
well I think this is healthy contention that should exist in a language community. People passionate about what should or shouldn't be in there
really, I'm not trying to attack anybody here but I'm baffled at seeing how this issue that every serious contributor notices, is not being taken seriously even after all those years
@alexmiller and can't that be because they know that it will take them 4 more years until it gets merged, and they'll have to rebase it 15 times, and fix all the merge commits that happen meanwhile etc
I don’t ask people to merge and rebase patches - I usually do that for people. I realize that Clojure’s development rate requires a long view and there is not the satisfaction of immediate gratification you get from a project that merges PRs every 5 minutes. I’d like to make changes that find a middle ground but Clojure is always likely to favor proactive “important” work over reactive “urgent” work.
I update patches for tickets all the time - I only ask for help with that if it’s drifted so far I can longer update.
I guess the type of patches I work on cause me to have a different perspective than most contributors then
that is probably true :)
I don't know, it seems like one day a "Clojure Foundation" sort of thing will be inevitable, when Rich one day wants to retire or whatever. But as a community member, for my vote, I'd prefer our BDFL carry the ball down the field as far as humanly possible before that inevitable bureaucracy sets in.
or it's at least confusing, I'm not sure how you can call something urgent and also deprioritize it
modern OSS development is imo incredibly destructive (to people’s lives) in creating expectations for rapid turn around on every problem
and the result of this is that oss devs often spend 99% of their time merely reacting to things rather than actually doing good software development
by “urgent” I mean “I want this now” not “something is on fire”
even Java, the eternal bastion of stability, has moved to a 6-month release cycle with extended support for every third(?) release
and the result of this is that oss devs often spend 99% of their time merely reacting to things rather than actually doing good software development
@alexmiller I understand that Clojure itself wants Jira + Patches (which is already a hurdle for some) since RH has stated it clearly: https://groups.google.com/forum/#!msg/clojure/jWMaop_eVaQ/3M4gddaXDZoJ Though, what I don't quite understand: Why are all sub-projects also on the Jira+Patches track. E.g. I'd imagine you get much more contribution and help if TDEPS (and many other projects) was just 100% github. (Like the CLJ/CLJS websites). I'd imagine this would allow you (and others) to spend more time on CLJ itself. Just a thought...
^ I was also just going to suggest splitting more stuff out and experimenting with process there.
Point being: I guess RH doesn't vet tickets on TDEPS, so why the extra hurdle of Jira+Patches?
jira+patches is imo a completely orthogonal and unimportant issue
if making a patch is a barrier to contribution, then you’re not very serious about contributing
@alexmiller have you tested that theory out?
I have used both jira/patch and github/pr approaches heavily
I spend 75% of the time understanding a problem, 24% of the time making a solution, and 1% giving it to someone
@bronsa for someone who's done it before not difficult at all. But I know I've worked with people who don't know much about Git but could still contribute some Clojure code.
https://dev.clojure.org/display/community/Contributing https://dev.clojure.org/display/community/Creating+Tickets https://dev.clojure.org/display/community/Developing+Patches
Certainly true for Clojure project. But --sticking with TDEPS--, I'd imagine you'd just get much more help. Fixing a simple docstring e.g. I'm not going to spend 5min on Jira. But might do a quick PR entirely on github.
or you can just make an issue
the aversion to jira and patches is irrational
especially since gh provides direct urls to patch files: https://github.com/clojure/tools.deps.alpha/commit/dbc867ac8a2bfb415f7b73bac00ab61391a4c892.patch
it's not an issue at all and it's just distracting from the real issues when people keep talking about it
moving clojure contrib to github PR is not going to solve any of the issues people have with the contrib process
My argument was: It'd free up time for work on Clojure itself for Alex. Since the smaller projects would see more community contributions.
I spend 0% of my time on this stuff
if you think the problem is that alex is spending all his time making docstring patches, you're entirely missing the point
I'm sure this is well meant and all, but this jira/PR thing is just useless bikeshedding
https://www.reddit.com/r/Clojure/comments/87b9a1/state_of_clojure_survey_critiques_selected_from/
@bronsa I may have missed some of your points, but a quick skim showed mislabelled issues (enhancements that you consider to be bugs) and not enough people working on Clojure. You said people are driven away when they try to contribute somewhere as well I think?
I disagree, when I look at tdeps commits: Then 99% of the 422 commits are done by Alex. That was code he had to write. My hypothesis is: If this was on Github entirely then that number would look different. Less work for Alex => good thing.
please, I've written quite exhaustively about what the issues I think are in that thread, I'm exhausted from weeks of acute insomnia and don't have the strength to repeat myself here
@rauh no that's nonsense, that's alex working on new tdeps features, not alex fixing bugs in tdeps that some community member could do
Why shouldnt the community be able to implement new features? The core team can also create issues and let the community come up with PRs for them.
they can and have. this discussion makes no sense in the context of tdeps.
the issue is that because alex is just one person, he can only work on one project at a time -- what we'd need is a way to scale contributions/bugfixing horizontally rather than having a bus factor of 1 for clojure and of 3 for most core projects
I agree with you. But I'm realistic enough that I know the bus factor of clojure wont change anytime soon. Hence my idea trying to at least get other projects more into community hands. It'd be a start
because features are not developed openly, and the cost of getting the community up to speed with the design process would outweight the benefit of having more people working on it
If the process has too many tickets, why not just close all the tickets? I bet many potential contributors visit some, maybe upvote or something (you have to create an account first), but I think years old tickets are less honest wontfixes.
we regularly get patches in clojure for tickets that have been in jira for over 5 years
that's just because there hasn't been time/interest in looking at them earlier, not because they're not important
I think reducing latency per ticket would create a lot of transparency and reduce some community frustration.
Core could resurrect a few per release cycle that are actually being worked on, without making any promises. It seems like there might be easy wins there without really adding to the mental load.
Late to the discussion (because I'm on the West Coast 🙂 ) but my position is that the slow development of Clojure is a feature, not a bug: it provides amazing stability for serious production use. The number of things we've had to change in our code base over seven years of production use, due to breakage caused by new features and/or other changes in core, is very small... maybe as many as one thing a year. That's incredible and radically different to most other languages/tech stacks.
The number of blocking bugs over those seven years has also been vanishingly small.
And on community contribution, as someone who has been doing OSS development for about 25 years (I know, "Gramps!"), with a variety of processes, I'll say that when the barrier to entry is very low, you do indeed get more contribution but that also takes up a lot more of the project maintainers' time because the quality of some of that contribution is lower. You get into long back-and-forth discussions about PRs for all sorts of reasons. The GitHub/PR process can cause a lot of friction because the burden is switched from contributor to maintainer -- you get PRs for a lot of stuff you don't want to change (whitespace/formatting) along with things that should have been discussed as issues first so the contributor is on the right page. Reviewing, discussing, and rejecting PRs all takes time that a higher barrier tends to protect the maintainer from.
For prototyping, I'd like to run multiple Clojure services in the same JVM. Maybe one is a simulator, another is an API/query service, a third serves up a clojurescrapt app, etc, etc.
Is there an obvious approach to that, say, with a library, as opposed to me mastering ClassLoaders and so on?
A separate service called "System" that just launches the others, present on the class path.
I need a Java GUI that can render a 120 rows * 100 cols of text on every keystroke within 30 ms. Should I go with Graphics2D, JFrame, some Terminalr Emulator, or something else
hired man: I like integrant, but it seems like a good idea. Maybe even with deps.edn and the relative local/root thing, I could get it working more simply than I expect.
@seancorfield I think there ought to be other ways to make noise easier to ignore instead of increasing the barrier for everybody. That seems like a blanket justification for any process, intentional or unintentional.
@zentrope if the purpose of running multiple services on the same jvm is to avoid boot time latency, there's things like drip: https://github.com/josteink/lein-drip
@john Well, this is just for allowing folks to check out a repo with several services (that I like to keep separate) and start them all at once. Could also just use fancy shell scripts. Not so worried about start-up.
e.g. if I have a service that operates as a cluster and I went to test that they reliably do stuff even when the network is flakely, I can create two systems in a single jvm (because component packages all the state locally instead of having global state), swap out the network communication for a core.async channel with a buffer that drops msgs 10% of the time, and run tests
@john My one curiosity is class loader isolation (like web containers have) for mix and match libraries (which is not really an issue I don't think for me specifically).
@zentrope You don't need Boot's pods for this (in general) tho' -- you can just start multiple components in a single JVM. As @hiredman says, that's what we do at work: start the component for each service and start the component for your tests (or have your tests start the appropriate components directly).
Yeah, I'm fuzzy on the class loader stuff, but I believe class loader isolation for multiple processes in the same jvm was explored and was considered hairy
cemerick went down this road with pomegranate: https://github.com/cemerick/pomegranate
I think web app containers / app servers (tomcat, jetty, etc) do that for war files. Each WAR gets its own class loader for its own dependencies, etc.
I also like the fact that Clojure is not a moving target. I can understand though that there seems to be a need for a community catalyst of sorts to help improve tooling. I hope that Clojurists Together plays that role.
Regarding the core team’s role, I was jarred at first with how easy Alex and David (the most well-known core people for me) say no. It clicked later though, and I’d rather we get a solid ground we can build on from the core team. Much better use of their time.
no is temporary, yes is forever
Here’s a nice turn of phrase I caught on Twitter just now: https://twitter.com/andy_matuschak/status/979019076038094848
I’d rather the core people have a long/medium term to advance the language/programmer experience than get caught up in the bustle.
Although it is very good to take stock of the advantages of any given approach, I think some of this is a false choice. You can have a stable language and a good developer experience at the same time if you engage with the community well. Learning to say “no” more nicely would be a good start.
The comments on elitism are ones I just can't see. From my own experience this has been the most friendly, most helpful community I've seen.
Same here. Though I believe that different venues might have different tones. Slack and Clojureverse are really kind, balanced and friendly. Reddit might be sometimes a bit rougher.
Curiously the newest members (who are also newest to Clojure from us) of my team did agree with the elitism part.
They reflected it heavily to the lack of basics teaching in form of tutorials and other similar content and a general unease of even daring to ask the simple stuff.
Also the amount of swearwords about the documentation has been like sailing with captain Haddock at times.
Yeah, the elitism thing might be a projection of one's unfamiliarity. The tower doesn't seem as ivory-ish, once you're able to start reading the actual core source code
Oh, I was thinking about how I felt around 10 years ago. I didn’t dare ask anything online lest I appear stupid. Perhaps there’s something there — no matter how friendly the community is, if people have to ask something, there will be a % that will be turned away.
Yeah, r/clojure seems pretty tame, too, but it is a little rougher at times. It has a small troll content at times, or maybe that's my bias 🙂
@suomi.esko What background do those team members have? I’ve tried writing an intro to Clojure on my blog but it’s really hard to “tune” the tone.
@orestis Varies a lot, but generally more junior - as in a few years of software engineering experience tops with related university studies/maybe a degree.
They're on the level that when I explained threading macros the first time it blew their minds 🙂
Well, the other of the two people I'm thinking here comes from JavaScript background. The other I'm not even sure, actually.
You folks sure are working really hard to say, “these problems don’t exist so we can ignore them”
That’s a bit harsh @lee.justin.m - I’ve already written half my intro to clojure blog post, starting from scratch, and I want to get an idea what makes people stumble.
@lee.justin.m which folks are you talking about?
http://cio.com just called out Clojure as one of the top alternative data science languages: https://www.cio.com/article/3263790/data-science/the-essential-skills-and-traits-of-an-expert-data-scientist.html
The very first reaction to “people on my team see it this way” is “gee they must be junior and/or just not get functional programming”. Seriously. Just think about how that reads.
My general tips would be that don't assume - formal education - understanding of category theory or set theory or any other similar high level concepts - understanding of functional programming and what it entails (I once spent an hour talking about persistent data structures to a crowd and afterwards I was thanked how amazing idea the whole "data stays the same" thing is) Also don't use fancy words. No one gives a frying duck what a monad is 🙂
"What background do those team members have?" does not sound like "gee they must be junior"
Whenever I try to talk about concepts I assume that someone's just seen a cool thingamajig, grabbed it and come to me asking "What's this? :D". That is, start low - when you get to know your audience you'll learn soon what you can assume and skip.
As long as we get to discuss, no hard feelings from me. There’s obviously some nuance here that must be nailed down.
Well, you're right though that we should be cognizant of these things. And it's often the case I don't see things as others might justifiably see them due to my own biases and perspective.
(tangentially, I wish http://clojuredocs.org would just plain simply replace the official api documentation)
Folks, this discussion has moved away from the technical -- which is what #clojure is for -- and into community, so it really should move to #community-development /admin
What I experience is many new comers sort of think they know everything and get mad when something comes along that exposes their ignorance, which is silly, no one knows everything
and as a high school drop out with no formal cs education besides a javascript class or two at the local community college, I find the notion of elitism kind of laughable
I'm going to make a clojure derivative called "leet," just to settle it once and for all 😉
i've a similar background to you hiredman, and also see no elitism. perhaps it's a case of hammer/nail?
(and, yes, I contributed to that earlier instead of pushing the conversation over to #community-development -- which is what I should have done two hours ago!)
Point taken @seancorfield - unfortunately I need to go but please continue on the other channel. It’s good to get these things out in the open.
Yes, definitely a healthy discussion to have.
regarding Error Messages: I'd like a tool that interprets stack frames -- not just an error "prettifier". We should be able to cook up something that was able to make a determination: "Something threw an exception while realizing an item in a lazy-sequence" you can glean all this info from a stacktrace -- there are well-defined signatures in the clojure runtime. (for example, since clojure 1.8 there is now an invoke and invokeStatic trace element for every core call -- just need to show one!)
+1000 @ghadi! Such a tool should be a web service, with client added at the REPL
wtf would be only for interpreting stacktraces specifically. expound is for prettifying spec's explain-data
keep it separate. Though it would be nice to have a community "distribution" of clojure that made it easy for beginners. Preconfigured expound + wtf, etc.
yeah, as long as the seem consistent with respect to each other, spec error reporting vs stacktraces. Yeah, if you've got a plan to go forward on that, I'd definitely help hack on it.
I guess you'd have to decide whether to use a db of known stack trace heuristics or to dynamically pull names out of the classes at runtime that we find from lines in the stack trace?
But if lots of people did that, yeah, we'd have some serious data to build heuristics on
should be on-demand, not automatic. Readme should make it clear that it is a potential security leakage
But you don't have to have data to start -- can do standard stuff like this and build some rules:
(doall (map #(throw (Exception. "foo")) [1 2 3]))
question about vars and metadata…
doing this works fine
user=> (-> identity var meta)
{:arglists ([x]), :doc "Returns its argument.", :added "1.0", :static true, :line 1443, :column 1, :file "clojure/core.clj", :name identity, :ns #object[clojure.lang.Namespace 0x2d1dee39 "clojure.core"]}
how would I accomplish something like this?
user=> (map (fn [f] (-> f var meta)) [identity])
CompilerException java.lang.RuntimeException: Unable to resolve var: f in this context, compiling:(NO_SOURCE_PATH:4:14)
@jaydeesimon var
is a special form; it happens at compile time. to do it at runtime you use resolve
:
=> (map (fn [sym] (-> sym resolve meta)) ['identity])
({:arglists ([x]), :doc "Returns its argument.", :added "1.0", :static true, :line 1443, :column 1, :file "clojure/core.clj", :name identity, :ns #object[clojure.lang.Namespace 0x44c43989 "clojure.core"]})
ah ok - thank you. what if I have a reference to the function and need to turn that into a symbol? (so that I can pass it to resolve)
ok cool. good to know. thank you
To get you started
user=> (clojure.main/demunge (str +))
"clojure.core/+@42bc14c1"
user=> (defn foo [] 42)
#'user/foo
user=> (clojure.main/demunge (str foo))
"user/foo@13518f37"
user=>
If you str/replace
#"@.*"
with ""
you should have something you can feed to symbol
and then resolve
I think.
(it won't handle anonymous functions tho')
Indeed! That looks a better path than (str f)
user=> (clojure.main/demunge (.getName (class +)))
"clojure.core/+"
user=> (clojure.main/demunge (.getName (class foo)))
"user/foo"
user=> (clojure.main/demunge (.getName (class (fn []))))
"user/eval162/fn--163"
this is great stuff - thanks again
thanks!
To get you started
user=> (clojure.main/demunge (str +))
"clojure.core/+@42bc14c1"
user=> (defn foo [] 42)
#'user/foo
user=> (clojure.main/demunge (str foo))
"user/foo@13518f37"
user=>
I wrote my first clojure program, i am hoping to have someone with experience tear it up with brutal honesty about what is bad, what is weird, and suggestions to do things differently. If anyone is interested in helping I can send you some LTC for the trouble. PM me if interested, i'll be back on later tonight.
@matthewdaniel Do you want to post it on #code-reviews ?
Maybe a stupid question. I'm trying to use spec/fdef
to validate the inputs to a function. I have come up with the following:
(s/def :my.ns/meow string?)
(s/def ::meow-spec (s/keys :req [:my.ns/meow]))
(s/fdef meow
:args (s/cat :some-map (s/coll-of ::meow-spec
:kind map?)))
(defn meow
[some-map]
some-map)
However. I am a little confused as to how this works.
(s/valid? ::meow-spec {:my.ns/meow "a"})
=> true
(s/valid? ::meow-spec {:my.ns/meow 1})
=> false
(clojure.spec.test.alpha/instrument)
(meow {:my.ns/meow "a"})
=>
ExceptionInfo Call to #'harmonium.edi.handler/meow did not conform to spec:
In: [0 0] val: [:my.ns/meow "a"] fails spec: :harmonium.edi.handler/meow-spec at: [:args :some-map] predicate: map?
clojure.core/ex-info (core.clj:4739)
What am I doing wrong?Generally, you won’t want to use coll-of ... :kind map?
. The only thing that’s valid there is a spec that describe key/value pairs, IIRC (I haven’t needed to use this form, although it can be useful in certain circumstances)
But the most important thing in the example above is that the spec says: “args must be a single element collection, the first element of which is a map, which contains maps”
I think you just want to say “args must be a single element collection, the first element of which is a map with key :my.ns/meow
”
Cool. In this case, I think you can just get away with s/keys
since (s/valid? ::meow-spec []) ; => false
. At least from your example function call, I think you are intended to just pass a map, not a map of maps
Sorry one more question. It's kind of frustrating to have to call (clojure.spec.test.alpha/instrument)
everytime I re-evaluate my ns. I sthere a way around this?
As far as I know, there is not a way around this. I wonder if this could be integrated into some editors
keep in mind that instrument
will only check the args, not the :fn
or :ret
spec. That’s a common misunderstanding
The good news is that orchestra is really easy to set up. Just replace [clojure.spec.test.alpha :as st]
with [orchestra.spec.test :as st]
and call st/instrument
as usual
oh, sorry, I misunderstood your response. i thought you meant the behavior of instrument was disappointing, but you meant that you had to call it repeatedly
The difference between orchestra instrumentation and default instrumentation is that orchestra will check your “return” and “function” specs
Well my understanding is either way. To have run-time validation of my args, I need to call instrument
that’s correct. the only difference is whether the fdef
specs for return value and function are checked
see here: https://clojure.org/guides/spec#_instrumentation_and_testing
>>>Note that the :ret
and :fn
specs are not checked with instrumentation as validating the implementation should occur at testing time.
Hmm. puzzling. I have someone elses macro doing stuff:
(some-other-macro vals {:some-data (my-macro some-arg)})
But when I macroexpand this what I expect to get is:
(... {:some-data (my-expanded-macro stuff)}
But what I get instead is just
{ ... {:some-data (my-macro some-arg)}}
so I would have to write a macro that invokes this macro AFTER expanding any macro forms inside the args?
An outer macro can conditionally decide whether some inner macro is left alone to be evaluated, or is discarded, or an entirely new form involving other inner macros is used
@lwhorton needing to do that is usually a sign that you're doing some quite complex macro, for instance core.async's go kinda does that
hmm .. it isn’t complex, it’s just trying to “fix” someone elses macro from a library
such that I can use a simple macro (get-var some-symbol)
which will be converted at compile time to some constant like “400px” or “blue”
(var-get (ns-resolve 'css.vars (symbol sym)))
except my get-var color
, for example, when used inside another macro, doesn’t actually expand to “blue”-- so it should be possible to just write a macro that wraps the other guy’s macro and first macroexpand-all’s on the arguments, then invokes the inner macro with the newly expanded args, right?
huzzah!
(defmacro defstyled [sym element styles]
(let [expanded# (clojure.walk/macroexpand-all styles)]
`(cr/defstyled ~sym ~element ~expanded#)))
could write it as
(defmacro defstyled [sym element styles]
(let [expanded (clojure.walk/macroexpand-all styles)]
(list 'cr/defstyled sym element expanded)))
still cant really get what I want, for some who-knows reason:
(defmacro get-var
"Mixing clj and cljs namespaces doesn't work at runtime. We have to have a compile-time
solution for referencing static variables from a cljs namespace in other clj or cljs
namespaces for styling purposes. For example, we need vars defining font sizes, break
points, etc. This macro will compile-time expand the given symbol into the requested
value (as defined inside this vars namespace)."
[sym]
(var-get (ns-resolve 'css.vars (symbol sym))))
(defmacro defstyled [sym element styles]
(let [expanded (clojure.walk/macroexpand-all styles)]
`(cr/defstyled ~sym ~element ~expanded)))
#_(macroexpand '(defstyled foo :bar {:color "pink" :nested {[[:max-width (get-var medium)]] {:color "red"}}}))
but if I’m outside of this namespace and invoke defstyled
, it still refuses to expand (get-var medium)
boot.user=> (macroexpand '(defstyled a b (when true)))
(cr/defstyled a b (if true (do)))
boot.user=> (in-ns 'foo)
#object[clojure.lang.Namespace 0x7e93e1b2 "foo"]
foo=> (clojure.core/macroexpand '(boot.user/defstyled a b (when true)))
(cr/defstyled a b (when true))
yea it doesnt seem to, though. when I look at the generated text at runtime its still “{:max-width (get-var medium)“. 😕
hard part is knowing if this is a cljs vs clj difference, an incorrect macro, a namespacing problem, or something else
well it happens in my clj repl, so it's not a clj/cljs thing (as i first incorrectly assumed). but it's still very curious
can someone comment on why changing into a namespace separate from where a macro is defined makes macroexpand’s behavior change?
foo=> (clojure.walk/macroexpand-all '(boot.user/defstyled a b (when true)))
(cr/defstyled a b (when true))
foo=> (clojure.core/use 'clojure.core)
nil
foo=> (clojure.walk/macroexpand-all '(boot.user/defstyled a b (when true)))
(cr/defstyled a b (if true (do)))
my intent is to totally avoid any of the complexities of this lib, and simply fix the problem that it doesn’t accept values with macro expansion in the styles
arg
so from a cljs namespace, :refer-macros [defstyled get-var]
still spits out (get-var medium)
(defmacro defstyled [sym element styles]
(let [expanded (clojure.walk/macroexpand-all styles)]
`(cljss.reagent/defstyled ~sym ~element ~expanded)))
and css.vars (for completeness)
(ns css.vars)
;; break points
(def medium "768px")
(a .clj file, though this shouldn’t matter I don’t think since it’s compile time)fwiw, using cr/defstyled
should be fine:
foo=> (require '[clojure.string :as str])
nil
foo=> `str/x
clojure.string/x
well, if I have my css.vars defined as a .cljs file-- expansion even in the same ns where macros are defined results in get var
so that’s … something. I guess it has to be a clj file in order for var-get
to work.
it works for me as expected: https://github.com/darwin/defstyled
this is pure clj code, the cljss.reagent/defstyled
macro emits cljs code, but that is not important
if you really want to define your constants in cljs then clojure code cannot help you, but you can have another macro which emits clj-defined constants as constants in cljs code, this way you can access them from cljs code, but that would be more tricky to setup
so there’s 3 differences here I can see. 1 is the namespace invoking the macro is clj, 2 is there’s no cljs compilation step, 3 is just using the clj cli tool instead of lein w/ figwheel
i really wish there was just a short-cut to tell the compiler at read time “go look up this symbol and inline it”
macros are clojure functions which rewrite code into another piece of code, typically they rewrite clj code into clj code, or cljs code into cljs code, but in this hybrid case, they rewrite code which has simple clj expressions (your constants) into cljs code
“the compiler” is ambiguous here, do you talk about clojure compiler or clojurescript compiler?
and that is what we are doing there, we are looking up symbols in clojure compiler state and inlining them
i mean the clojure compiler that sees a macro and rewrites the values. i just cannot seem to get clj to look at a macro used in a cljs file and swap out the values (defined in another clj file) properly
aren’t you expecting it to inline cljs values? if you wanted to look up cljs symbols, your would have to inspect clojurescript compiler state and get it from there, which is more complicated
" a macro used in a cljs file” is not special from my point of view, it just emits cljs code
but it runs in clojure environment, so it can look only at clojure state (under normal circumstances)
if the values are defined in a .clj file, though, as simple (def my-val "foo")
, wouldn’t a cljs file that invokes a macro still have access to my-val
during the clj compilation?
in this sense the macro is just emitting cljs code, and the code it emits does a var lookup from another clj file.
it makes no sense to me why the ultimate output of a macroexpand-all is still (get-var my-val)
and not "foo"
i appreciate all your help by the way, i guess at the end of the day I have a foundational misunderstanding somewhere that’s blinding me
sorry, didn’t see your replies, “emitting cljs code” and “the code it emits does a var lookup from another clj file.“, second sentence does not make sense. cljs code cannot see “clj world”. and cljs code (at runtime) cannot do something like a “var lookup” AFAIK
what you can do is to write a macro, which when expanded in cljs code emits some data from clj world, for example resolving some values and inlining them into cljs sources
that was my proposal, if you wanted to re-use those clj constants (css.vars) in cljs code, you could write macros which would emit them into cljs code
if I had a simple macro like this:
(defmacro get-var
[sym]
(var-get (ns-resolve 'css.vars (symbol sym))))
at compile-time from clj, would this not replace (get-var some-symbol)
where (def some-symbol "hello")
with (... {:some-val (get-var some-symbol)})
-> (... {:some-val "hello"})
?
or something along those lines, you could have a macro which will walk css.vars
namespace and generate cljs code which will def each var in cljs and inline corresponding clj value there, for example
i was just at the wrong call site the whole time - should be defining a symbol via the get-var, not at the cljs space
this macro stuff is really confusing if you don’t really understand how it works internally, mainly the important fact that macros are clj functions which rewrite code and see only clj state
but it gets more complicated than that 🙂 think about self-hosted cljs, in that situation macros are actually cljs functions
try to look at clj and cljs code as different languages, they happen to be very similar, but in these cases you really should understand “where you are”
yes, if the outer macro needs to work on expanded code then it needs to expand it as part its own work, e.g. to use macroexpand-all
is expand-all a “proper” way to handle this, or is it only intended for use as a debugging tool? i.e. should I be dipping into the tools.analyzer?