This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-06-11
Channels
- # announcements (1)
- # architecture (23)
- # beginners (189)
- # boot (1)
- # calva (62)
- # clj-kondo (23)
- # cljs-dev (9)
- # clojure (336)
- # clojure-dev (11)
- # clojure-europe (2)
- # clojure-italy (17)
- # clojure-nl (25)
- # clojure-uk (53)
- # clojurescript (12)
- # core-async (29)
- # data-science (1)
- # emacs (6)
- # fulcro (23)
- # garden (3)
- # graphql (2)
- # jobs (1)
- # joker (7)
- # off-topic (17)
- # om (2)
- # qlkit (1)
- # reagent (15)
- # reitit (18)
- # rewrite-clj (7)
- # shadow-cljs (176)
- # sql (1)
- # test-check (4)
- # vim (32)
- # xtdb (30)
@i change your comment to "is not a clojure.lang.Number" and it should change your perspective.
@didibus still i don’t know what it does. for example, (num 333), however, 333 is already a number.
You need to use either Java interop and the Parse methods to do so, or use the reader itself.
i see. Number is the base class of Integer, Long, etc. so basically its using the base class Number as abstraction. Very java-ish, oo flavor.
It basically takes from any more concrete type, like float, int, double, long, etc. And coerce it back to the Clojure default for the number
And for the operation, maybe you had to coerce numbers, but you want to return it back to the appropriate Number type
If you don't want to specify the type to parse into, and want the same logic as Clojure litteral syntax, you can use (edn/read-string "333")
This a relevant issue: https://clojure.atlassian.net/browse/CLJ-2451 — it’s something that confuses a lot of people
@i It doesn't say "coerce to a Number", it says "coerce to Number". That's an important difference.
@seancorfield what’s the Number here? the java.lang.Number ?
But you'll almost never find a use for num
. Primitives are automatically boxed in Clojure, which means they end up as Long
or Double
most of the time already. And those are java.lang.Number
.
Yes, exactly.
num
on a float
(primitive) will produce a Float
(`Number`). num
on a double
(primitive) will produce a Double
(`Number`). That's all it does.
The entire implementation: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Numbers.java#L1479-L1489
java.lang.Float, java.lang.Integer, java.lang.Double, java.lang.Long are all children of java.lang.Number
About the only useful behavior of num
is that it throws an exception when called on something that isn't a Number
🙂
So primitive type long (no uppercase), will coerce to java.lang.Long, which is a child of java.lang.Number
I suspect num
is mostly used by Clojure itelf, as the implementation for the auto-boxing Sean mentioned, but I can't confirm
Well, there are lots of calls to the static method num()
inside clojure.lang.Numbers
.
i am little bit lost in the conversation. given your code snippet, of `return (Number) x’. I wonder what happened when (type (num (int 1)) becomes Long instead of Integer.
Because (int 1)
is autoboxed to Long
, and Long
is already Number
so the cast does nothing.
Like I said, pretty much the only useful behavior of num
is that it will throw an exception if called on something that isn't a Number
.
I would imagine that it is almost never used in production code.
(and if http://crossclj.info still existed, we might be able to answer that to some degree!)
@seancorfield i mean, it is boxed to Integer not Long.
Sorry, I meant Integer
there.
user=> (type (int 1))
java.lang.Integer
(...and Integer
is already Number
so the cast does nothing)
user=> (type (num (int 2)))
java.lang.Long
user=> (type (int 2))
java.lang.Integer
user=>
And the implementation is commented out: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Numbers.java#L1579-L1581
But that wouldn't be invoked anyway: (int 2)
is already boxed to Integer
by that point.
So it would go through the Object
case and be cast to Number
.
user=> (type (cast java.lang.Number (int 1)))
java.lang.Integer
So there must be some additional boxing going on with (type (num (int 1)))
user=> (type (num (double 1.0)))
java.lang.Double
user=> (type (num (float 1.0)))
java.lang.Float
user=> (type (num (short 1)))
java.lang.Long
user=> (type (num (byte 1)))
java.lang.Long
user=>
OK, so the double
and float
overloads "preserve" the cast type and end up with Double
and Float
respectively, but everything else ends up promoted to Long
which is Clojure's default integral type?Hum.. maybe. But there is an overload for num(long) and num(float) respectively which coerces them to that.
For int, there isn't, so Clojure first auto-boxes it into something, and calls num(Object) with it,which just returns it casted to Number
Ah, I'd missed the long
overload. That explains it: in Java, byte
, short
, and int
will all coerce to long
first -- so that's the overload that processes all of them.
The five definitions of num()
are not together.
I only saw the first three... doh!
Well, four since the int
overload is commented out.
Now it makes sense.
Yeah.
Clojure will call num with primitive type int, and Java will coerce it to primitive long, and dispatch to the primitive long num overload, which will coerce it to a boxed Long.
(! 686)-> cat Promote.java
public class Promote {
public String foo(long x) { return "Long"; }
public String foo(short x) { return "Short"; }
public static void main(String[] args) {
Promote p = new Promote();
System.out.println( p.foo( (byte)1 ) );
System.out.println( p.foo( (short)1 ) );
System.out.println( p.foo( (int)1 ) );
System.out.println( p.foo( (long)1 ) );
System.out.println( p.foo( 1 ) );
}
}
Mon Jun 10 22:58:56
(sean)-(jobs:0)-(~/java)
(! 687)-> java Promote
Short
Short
Long
Long
Long
Took me so many attempts to get this to compile -- after using Clojure for nine years, I can't write Java any more! 🙂Also, haha, ya, I've been writing so much Clojure, when I need to do a Java code review or code change, I'm like.. what the hell is this mess! 😛
I've written almost zero Java in nine years at this point...
Wow, that's crazy though! I still deal with a lot of mixed Java/Clojure project, but slowly Clojure is taking over
Work was a CFML (ColdFusion) shop when I joined!
My partner was going through interviews recently though. And as I was helping her practice some interview questions, I realized... damn, you can't do an interview question in Clojure 😛 And I was trying to get back to using Java and I kept being like.. Where are the functions I need!
I tried to introduce Scala but that didn't suit the other team members. So I tried Clojure, and that did.
So we slowly switched from CFML to Clojure, trading one dynamically compiled JVM language for another 🙂
Also people are like... Given an ArrayList... can you modify it in place. And you're like... You mean HashArrayMapTrie 😉
Consequently, our CFML code contains stuff like this in a few places:
var cols = clj.clojure.string.join(
",",
core.map(
core._name(),
core.keys( core.first( items ) )
)
);
which is (clojure.string/join "," (map name (keys (first items))))
🙂(the weird _...()
syntax just gets a Var reference)
We have people using Clojure libs from Java and Scala. Clojure is really easy to use from other JVM languages, its a great strenght
Our entire process for the last eight years has been based on CFML/Clojure interop. But we've retired our biggest CFML app now.
Can't imagine a reason to try, either. Or rather, can't think of anything I'd want to use from Scala in Clojure
Yeah, we have a live Socket REPL in our last remaining CFML app 🙂
The CFML/Clojure "magic sauce" https://github.com/framework-one/cfmljure
(I just pushed the latest cfmljure.cfc
from our work codebase but the rest of the repo is about two years out of date)
@didibus Hahaha nope. I used Emacs for a few years, then Atom.
@deleted-user Look at clojure.java.shell
I think
http://clojure.github.io/clojure/clojure.java.shell-api.html#clojure.java.shell/sh
No, clojure.java.shell/sh
assumes the process ends.
So you'll probably have to use Java interop and some standard Java libraries?
java.lang.ProcessBuilder
is probably what you want.
java.lang.Process
lets you get an OutputStream
which you could read as it becomes available.
Could be you can just modify the impl of sh: https://github.com/clojure/clojure/blob/fe0cfc71e6ec7b546066188c555b01dae0e368e8/src/clj/clojure/java/shell.clj#L110-L128
Lets you get program output as a lazy sequence of lines.
Just use Conch 🙂
I wasn't sure if it had been forked into clj-commons, so I had to go check.
(and with that, my work here is done... time for bed!)
Yeah, pretty much anything in Clojure that uses concurrency will require (shutdown-agents)
or an explicit (System/exit n)
call.
If I want to read the implementation of the thread macros where would I normally go look for that? (I'm less interested in the code than I am the skills to go find those sorts of answers myself in the future) ^_^
and try expanding examples (clojure.pprint/pprint (macroexpand '(-> {} (assoc :a 1) keys first val)))
I really need to pick up the habit of using the repl analysis tools more in general I'm finding. ^_^
is it always possible to turn a recursive function into a tail recursive function?
Possibly wrong question, but I am very much out of the loop. How safe is to use the python version of the transit library, in production? It seems quite abandoned but I know that can be misleading…
it's not abandoned, Cognitect supports it
is something not working?
no, just that it didn’t looked active, but if it is supported that’s a different question
it works, and the spec isn't changing, so... no active work happening. But if there's an issue, we have people that will look at it.
I am pretty sure the answer is no, although there might be some pretty wild contortions or modifications to a program that theoretically make it possible. The kind of example function that I do not see a clean way to turn into a tail recursive function is one like Clojure's tree-walk, or in general anything where the return value is the result of two or more different recursive calls.
> return value is the result of two or more different recursive calls. Yep that's exactly what i have.
If a recursive function calls itself only one time in its body, then I think it might be possible in general to transform it into a tail recursive version.
bummer!
time to switch to haskell! 🙃
Are you trying to avoid stack depth explosion? i.e. is that the reason you are looking into writing a tail recursive version?
Yeah, what @U0C7D2H1U said could be a way to help avoid stack depth increase, even if you do not write a tail recursive function.
You can in general I think create your own stack of values (or sets of values) that represent what the recursive function would put on the stack for you, and write a non-recursive version of the function that behaves identically.
i'm working through a discrete optimization class and the first lesson is doing the knapsack problem using dynamic programming. I put together a recursive solution but it needs to be memoized and additionally i assume it would be ideal to make it tail recursive. Though the later might not matter... its unclear to me.
Clojure's core.memoize library makes it pretty trivial to memoize a function, if it is a pure function.
@U0C7D2H1U i made a github repo, needed to anyway. Here is the link and thanks! https://github.com/drewverlee/knapsack/blob/4c4b4cd7053a97716e3e131e13f7647afa538727/src/knapsack/core.clj#L261
I memoized it, im not sure I can make it tail recursive, how would haskell do this? https://gist.github.com/Tavistock/a1c3adf631dbf07de36765beda65038f
when i mentioned haskell i was mostly joking, i believe haskell has general recursion optimization, due to the order not mattering. Thanks! ill take a look. Oh yea, that makes sense. I think i have to do a bit more work to make the memoization help. specifically im calling each function with the current items that are being put in the knapsack, which would reduce the number of cached hits. possible all of them 😕 No worries, this the top down approach which is easier to reason about but, apparently, very hard to optimize.
Is it the algorithm that can't be made tail recursive? Or just struggling to have it use TCO in Clojure?
Not all algorithms can be tail recursive, sometimes you do need to keep a stack to backtrack too and pop
the entire point of csp is for all calls to be tail calls. but just because a call is a tail call that does not mean it is optimized, for example clojure doesn't have tail call optimization. you can recur from a tail position and get a constant size call stack (which is what tco does), but tail calls don't get any guarantees there
so if you want an algorithm to have a constant size call stack in clojure you need to go beyond transforming things in to tail recursive form
but if you have something that is all tail recursive (because it has been cps transformed) making it trampoline is usually trivial
consuming the call stack is kind of implicit thing and there can be restrictions and limitations to the call stack, where cps basically makes the call stack as an explicit thing, and often in the process moves data from the call stack to the heap, which is often a more free wheeling place
trampoline wise the issues are more about the mechanics of the trampoline, for example clojure's built in clojure.core/trampoline has issues if the ultimate value you return is a function
with trampoline you are still representing the program state as clojure function objects
if you move to something more like an abstract machine, you can have the entire machine operate in a loop/recur and represent the machine state as fungible data instead of relatively opaque closures
Ya, trampoline is quirkier to use, but I think the quirks can be worked around if you're willing to do it
And ya, I mean that. The first question to ask is, does this solution need a stack. If it does, what stack do you want to use? If it doesn't, and you're doing recursive function calls, then you need to figure out how you're going to optimize the call stack away
So I finally understand the difference between ->
and as->
when expanded, with ->
nesting forms and as->
setting up a let with each step.
My question is, why do they do it differently? Is there some trade off between the two approaches? Or are those transparent to the compiler?
They both have the same result.
lets are mostly immaterial in the compiled code, using lets in as-> leads to a simpler implementation
So, seeking to achieve deeper enlightenment on quoting and macros, I thought to build my own. But I can't seem to understand how a symbol is getting resolved...
1 (defn-
2 placeholder
3 "put __ in as first arg if none present"
4 [form]
5 (conj (rest form) '__ (first form))) ;;if not yet written...
6
7 (defmacro =>
8 [expr & forms]
9 (let [new-forms (map placeholder forms)]
10 `(let [__ ~expr
11 ~@(interleave (repeat '__) (butlast new-forms))]
12 ~(if (empty? new-forms)
13 name
14 (last new-forms)))))
is giving me Exception Unsupported binding form: (quote com.joe.jane.forms.macro/__) clojure.core/destructure/pb--5167 (core.clj:4315)
When I was expecting that the quote on line 10 would "force" the to be in the later namespace... What am I missing about quoting here?the ` on line 10 turns into a namespaced form, but the code on line 11 should be OK
Is there a way to avoid it namespacing it?
the usual idiom is
~'__
So really what I was missing there was the differences between backtick and quote
Quote disables symbol substitution for a form. Backtick is similar, but also replaces plain symbols with fully namespaced symbols (e.g. "filter" => "clojure.core/filter")
(as well as allowing unquoting / splicing)
For my favorite version of the threading macros, see https://github.com/cloojure/tupelo#literate-threading-macro
And the source code: https://github.com/cloojure/tupelo/blob/master/src/cljc/tupelo/core.cljc#L1322
it->
is just as->
with the symbol name fixed to it
(as-> 1 it
(inc it)
(+ it 3)
(/ 10 it))
but I hate the "backwards" nature of as->
. 😞
It's mostly designed to be used in ->
pipeline
yeah, all the arrow macros are designed so ->
can be their parent, and you can mix them
(-> 1
(inc)
(+ 3)
(as-> it (/ 10 it)))
I mean, I made a version that's a knock off of ramda's, not sure if that's good but I'm all kindsa tickled to have made it work.
1 (ns whatever-you-want)
2
3 (defn- in?
4 "true if coll contains elm"
5 [coll elm]
6 (some #(= elm %) coll))
7
8 (defn-
9 placeholder
10 "put __ in as first arg if none present"
11 [form]
12 (if (in? form '__)
13 form
14 (conj (rest form) '__ (first form))))
15
16 (defmacro =>
17 [expr & forms]
18 (let [new-forms (map placeholder forms)]
19 `(let [~'__ ~expr
20 ~@(interleave (repeat '__) new-forms)]
21 ~'__)))
small suggestion - if you are relying on the prefix behavior on lists, it's often more readable to use cons
instead of conj
that way we get the same ordering of elements in the form as the output list
or perhaps here concat
(concat [(first form) '__] (rest form))
or (cons (first form) (cons '__ (rest form)))
I think concat wins the beauty contest there, but I'm not 100% sure. ^_^
I found myself wanting to write a "plug in" helper there
any idea why (list (first form) '__ (rest form))
is bad?
cause rest puts it in a list... dang
and now I miss my ...
from JS
ahh, I forgot list*
and that does precisely what we want
user=> (list* 'a 'b '(c d e))
(a b c d e)
so (list* (first form) '__ (rest form))
❤️ ❤️ ❤️ ❤️
what are people's thoughts on using datafy to parse java object models into data representations for returning back via an api
for example i'm playing around with something like that for the google maps java lib:
(extend-type DirectionsLeg
p/Datafiable
(datafy [this]
{:arrival-time (.arrivalTime this)
:departure-time (.departureTime this)
:distance (.inMeters (.distance this))
:duration (.inSeconds (.duration this))
:duration-in-traffic (.durationInTraffic this)
:end-address (.endAddress this)
:end-location (LatLng->vec (.endLocation this))
:start-address (.startAddress this)
:start-location (LatLng->vec (.startLocation this))}))
(extend-type DirectionsRoute
p/Datafiable
(datafy [this]
{; ignoring until we need to draw things
;:bounds (.bounds route)
:copyrights (.copyrights this)
;:fare (process-fare (.fare route))
:fare (.fare this)
:legs (map datafy (.legs this))
; ignoring until we need this to draw things
;:polyline (.overviewPolyline route)
:summary (.summary this)
:warnings (.warnings this)
:waypoint-order (.waypointOrder this)}))
(extend-type GeocodedWaypoint
p/Datafiable
(datafy [this]
{:partial-match (.partialMatch this)
:place-id (.placeId this)
:address-types (map str (.types this))
:status (str (.geocoderStatus this))}))
(extend-type DirectionsResult
p/Datafiable
(datafy [this]
{:waypoints (map datafy (.geocodedWaypoints this))
:routes (map datafy (.routes this))}))
previously i just had processing functions that did the same thing. i like this better because its immediately clear what java object something is operating on where as before that would only be clear if you added type hints
but i suppose there's the chance for causing some confusion by making third party objects datafiable
but this is just internal application code not a library so seems lowish risk
seems fine. you probably want to type hint this
or you're using reflection for all of that
seems fine as in its not totally bonkers or seems fine as in that could be a reasonably common pattern 🙂
seems like a common thing already being done in many places to translate from Java objects to Clojure data. might as well do it under the datafy protocol
extending to com.foo.geo.GeocodedWaypoint is fine if your library pulls in and owns all interaction with com.foo.geo
you can always duplicate the protocol under a different name if you need to extend it to things you don't own
yeah doing it in a library sounds like a recipe for confusion
I've written Datafiable a bunch of times under the name IShredJava with a single method shred
@alexmiller just as an fyi, the docs say that extend-type automatically adds the type hints to 'this' for me
oh someone already said that in a thread, whoops
well then nvm! :) I forgot that
Hello guys, I don’t know if this is the right place to ask for an opinion on my case here, but anyway: Me and 2 friends started on the beginning of this year to study together, Design, Front-End and Back. I’m on the back with clojure... And we have finished a small web app that downloads musics and playlists from YouTube. Now, we are going to start a second project, but here’s the thing, I need to build an app which will be scalable, fully tested and ready for production, including DevOps tools and best practices. But this app needs to serve two purposes: first it needs to be something that we can use as an example of an app built by us, to show to possible clients in the future (so they won’t think we are starting out of nowhere) and this needs also to be something I can use myself to show if I need in the future a regular job with clojure. (Btw I’m going to document every bit of this project on a personal blog with daily posts, with videos too, to show my Learning path along the way.) So, we don’t know what kind of clients we can come across on the future (likely that will be small systems using web clients, small because it’s only me at the back end for now) but we don’t know what kind of system we would need to build, so the web app we are going to create now, should be something that suffices as a real world example and that also gives us more knowledge for the upcoming future. What you would suggest for us to build? What kind of app? Would any kind be enough for this? I have some ideas but I’m not sure if will be enough to show off...
start with the industry you are trying to work in, and find something that incorporates the standard tech and practices you'd see in that field
That’s a nice way to see this, we don’t really know what industry we are going to get in, but we have to chose something that’s suitable for a super small team, at least for now
I'd be more impressed by something that uses the tech stack and practices of my field, I think you'll make better progress if you specialize
(if your definition of success is impressing someone and getting a contract)
It’s not but for now it has to be because of money issues haha I’ll definitely use clojure, we are trying to find what we can explore that will be suitable for our small team. We only have 1 guy in front and me at back, and with no technical real world knowledge, we have a vague sense of what is too big for us
can someone here help illuminate me as to why emitUnboxed
might get called instead of emit
on a StaticMethodExpr
? I’m assuming it has something to do with the method signature?
In Compiler.java
if the method is called in a position that allows for primitive return, then you'll get emitUnboxed
It seems that both emit
& emitUnboxed
get called during compilation for the method in question
When you say “in a position”, you mean e.g. (if (MyClass/myMethod ...) ...)
vs. (fn [& args] (MyClass/myMethod ...))
Thanks, that’s helpful!
if you are chasing down some problem and haven't turned on reflection warnings I would suggest starting there instead of digging through the compiler
We fail compilation on any reflection warnings 🙂
You should see the gratuitous type hints in our code
It’s the life of Java -> Clojure -> Java unfortunately….
you can look for canEmitPrimitive
impls in Compiler.java for all the paths where emitUnboxed
can be used
I’m mucking around in the compiler because I’m getting IncompatibleClassChangeError
s saying Method {myMethod} must be InterfaceMethodref constant
Calling this method in my REPL works just fine… but calling the function in our code with that method in my REPL on JDK 11 throws that error
It looks to me like this test should trigged the emitUnboxed
code path? - must be InterfaceMethodref constant
Whoops
Haha oh man. I fixed the error. Hallelujah
Anyone that’s a contributor want to submit a patch for me? Lol
not sure what you mean, in that tast the result of the method calls are then passed to a function =
, so not emitUnboxed
yeah that makes sense
There’s a bug in emitUnboxed
for StaticMethodExpr
s
For some reason I thought =
was a built-in form like if
…
it kind of is, sometimes -- if it's in the appropriate position and over the appropriate types it can get inlined and intrinsified as a direct *CMP bytecode
I’m not sure why
if
doesn't cause emitUnboxed either, because it has to handle anything (Object), true, false, and nil
if
will sometimes result in emitUnboxed being called if the test can emit a primitive boolean
Well, I can reproduce by putting this method as a condition to if
. It will spit out this error at runtime
I changed the code in emitUnboxed
and now if
works properly
my guess is you are running with slightly different versions of some class at runtime and at compile time
Compiler.java line 1802
gen.invokeStatic(type, m); -> gen.visitMethodInsn(INVOKESTATIC, type.getInternalName(), methodName, m.getDescriptor(), c.isInterface());
It’s the same fix that was applied to emit
for this class
let me see if I can break Clojure’s unit tests
I can repro on the unit test too
oof, this took me longer to figure out than I’d like to admit
I thought it was an issue in clojure-maven-plugin
for so long
I can make a ticket + patch for you if you want, but registering for a CA should be easy nowadays if you want to do it yourself
Honestly not sure if my company would let me contribute even if I asked nicely
I can get a diff together though with a unit test
For the unit test, I just added -
That last case breaks w/out the patch to Compiler.java
I think this line needs to be staticMethod2
? -
+ (is (= 1 (if (compilation.JDK8InterfaceMethods/staticMethod0 true) 1 2)))))
Thanks for doing that 🙂 much appreciated!
no problem!
LGTM, thanks @bronsa 🙂